00001
00002
00003
00004
00005
00006
00007 #define DEFAULT_EDITOR_STR "kate %f"
00008
00009 #undef GrayScale
00010 #undef Color
00011 #include <config.h>
00012
00013 #include "kmcomposewin.h"
00014
00015 #include "globalsettings.h"
00016 #include "kmglobalns.h"
00017
00018 #include "kmmainwin.h"
00019 #include "kmreaderwin.h"
00020 #include "kmreadermainwin.h"
00021 #include "messagesender.h"
00022 #include "kmmsgpartdlg.h"
00023 #include <kpgpblock.h>
00024 #include <kaddrbook.h>
00025 #include "kmaddrbook.h"
00026 #include "kmmsgdict.h"
00027 #include "kmfolderimap.h"
00028 #include "kmfoldermaildir.h"
00029 #include "kmfoldermgr.h"
00030 #include "kmfoldercombobox.h"
00031 #include "kmtransport.h"
00032 #include "kmcommands.h"
00033 #include "kcursorsaver.h"
00034 #include "kmkernel.h"
00035 #include "partNode.h"
00036 #include "attachmentlistview.h"
00037 using KMail::AttachmentListView;
00038 #include "dictionarycombobox.h"
00039 using KMail::DictionaryComboBox;
00040 #include "addressesdialog.h"
00041 using KPIM::AddressesDialog;
00042 #include <maillistdrag.h>
00043 using KPIM::MailListDrag;
00044 #include "recentaddresses.h"
00045 #include "completionordereditor.h"
00046 #include "ldapclient.h"
00047
00048 using KRecentAddress::RecentAddresses;
00049 #include "kleo_util.h"
00050 #include "stl_util.h"
00051
00052 #include "attachmentcollector.h"
00053 #include "objecttreeparser.h"
00054
00055 #include <libkpimidentities/identitymanager.h>
00056 #include <libkpimidentities/identitycombo.h>
00057 #include <libkpimidentities/identity.h>
00058 #include <libkdepim/kfileio.h>
00059 #include <libkdepim/email.h>
00060 #include <kleo/cryptobackendfactory.h>
00061 #include <kleo/exportjob.h>
00062 #include <kleo/specialjob.h>
00063 #include <ui/progressdialog.h>
00064 #include <ui/keyselectiondialog.h>
00065
00066 #include <gpgmepp/context.h>
00067 #include <gpgmepp/key.h>
00068
00069 #include "klistboxdialog.h"
00070
00071 #include "messagecomposer.h"
00072
00073 #include <kcharsets.h>
00074 #include <kcompletionbox.h>
00075 #include <kcursor.h>
00076 #include <kcombobox.h>
00077 #include <kstdaccel.h>
00078 #include <kpopupmenu.h>
00079 #include <kedittoolbar.h>
00080 #include <kkeydialog.h>
00081 #include <kdebug.h>
00082 #include <kfiledialog.h>
00083 #include <kwin.h>
00084 #include <kinputdialog.h>
00085 #include <kmessagebox.h>
00086 #include <kurldrag.h>
00087 #include <kio/scheduler.h>
00088 #include <ktempfile.h>
00089 #include <klocale.h>
00090 #include <kapplication.h>
00091 #include <kstatusbar.h>
00092 #include <kaction.h>
00093 #include <kdirwatch.h>
00094 #include <kstdguiitem.h>
00095 #include <kiconloader.h>
00096 #include <kpushbutton.h>
00097 #include <kmenubar.h>
00098 #include <ktoolbarbutton.h>
00099 #include <kuserprofile.h>
00100 #include <krun.h>
00101
00102
00103 #include <kspell.h>
00104 #include <kspelldlg.h>
00105 #include <spellingfilter.h>
00106 #include <ksyntaxhighlighter.h>
00107 #include <kcolordialog.h>
00108 #include <ksavefile.h>
00109
00110 #include <qtabdialog.h>
00111 #include <qregexp.h>
00112 #include <qbuffer.h>
00113 #include <qtooltip.h>
00114 #include <qtextcodec.h>
00115 #include <qheader.h>
00116 #include <qwhatsthis.h>
00117 #include <qfontdatabase.h>
00118
00119 #include <mimelib/mimepp.h>
00120
00121 #include <algorithm>
00122 #include <memory>
00123
00124 #include <sys/stat.h>
00125 #include <sys/types.h>
00126 #include <stdlib.h>
00127 #include <unistd.h>
00128 #include <errno.h>
00129 #include <fcntl.h>
00130 #include <assert.h>
00131
00132 #include "kmcomposewin.moc"
00133
00134
00135 KMComposeWin::KMComposeWin( KMMessage *aMsg, uint id )
00136 : MailComposerIface(), KMail::SecondaryWindow( "kmail-composer#" ),
00137 mSpellCheckInProgress( false ),
00138 mDone( false ),
00139 mAtmModified( false ),
00140 mMsg( 0 ),
00141 mAttachMenu( 0 ),
00142 mSigningAndEncryptionExplicitlyDisabled( false ),
00143 mAutoRequestMDN( false ),
00144 mFolder( 0 ),
00145 mUseHTMLEditor( false ),
00146 mId( id ),
00147 mAttachPK( 0 ), mAttachMPK( 0 ),
00148 mAttachRemoveAction( 0 ), mAttachSaveAction( 0 ), mAttachPropertiesAction( 0 ),
00149 mAppendSignatureAction( 0 ), mPrependSignatureAction( 0 ), mInsertSignatureAction( 0 ),
00150 mSignAction( 0 ), mEncryptAction( 0 ), mRequestMDNAction( 0 ),
00151 mUrgentAction( 0 ), mAllFieldsAction( 0 ), mFromAction( 0 ),
00152 mReplyToAction( 0 ), mToAction( 0 ), mCcAction( 0 ), mBccAction( 0 ),
00153 mSubjectAction( 0 ),
00154 mIdentityAction( 0 ), mTransportAction( 0 ), mFccAction( 0 ),
00155 mWordWrapAction( 0 ), mFixedFontAction( 0 ), mAutoSpellCheckingAction( 0 ),
00156 mDictionaryAction( 0 ),
00157 mEncodingAction( 0 ),
00158 mCryptoModuleAction( 0 ),
00159 mTextCompletionAction( 0 ),
00160 #ifdef KLEO_CHIASMUS
00161 mEncryptChiasmusAction( 0 ),
00162 mEncryptBodyChiasmusAction( 0 ),
00163 mEncryptWithChiasmus( false ),
00164 mEncryptBodyWithChiasmus( false ),
00165 #endif
00166 mComposer( 0 ),
00167 mAutoSaveTimer( 0 ), mLastAutoSaveErrno( 0 )
00168 {
00169
00170
00171 setWFlags( getWFlags() | WGroupLeader );
00172
00173 mSubjectTextWasSpellChecked = false;
00174 if (kmkernel->xmlGuiInstance())
00175 setInstance( kmkernel->xmlGuiInstance() );
00176 mMainWidget = new QWidget(this);
00177 mIdentity = new KPIM::IdentityCombo(kmkernel->identityManager(), mMainWidget);
00178 mDictionaryCombo = new DictionaryComboBox( mMainWidget );
00179 mFcc = new KMFolderComboBox(mMainWidget);
00180 mFcc->showOutboxFolder( FALSE );
00181 mTransport = new QComboBox(true, mMainWidget);
00182 mEdtFrom = new KMLineEdit(this,false,mMainWidget);
00183 mEdtReplyTo = new KMLineEdit(this,false,mMainWidget);
00184 mEdtTo = new KMLineEdit(this,true,mMainWidget);
00185 mEdtCc = new KMLineEdit(this,true,mMainWidget);
00186 mEdtBcc = new KMLineEdit(this,true,mMainWidget);
00187 mEdtSubject = new KMLineEditSpell(this,false,mMainWidget, "subjectLine");
00188 mLblIdentity = new QLabel(mMainWidget);
00189 mDictionaryLabel = new QLabel( mMainWidget );
00190 mLblFcc = new QLabel(mMainWidget);
00191 mLblTransport = new QLabel(mMainWidget);
00192 mLblFrom = new QLabel(mMainWidget);
00193 mLblReplyTo = new QLabel(mMainWidget);
00194 mLblTo = new QLabel(mMainWidget);
00195 mLblCc = new QLabel(mMainWidget);
00196 mLblBcc = new QLabel(mMainWidget);
00197 mLblSubject = new QLabel(mMainWidget);
00198 QString sticky = i18n("Sticky");
00199 mBtnIdentity = new QCheckBox(sticky,mMainWidget);
00200 mBtnFcc = new QCheckBox(sticky,mMainWidget);
00201 mBtnTransport = new QCheckBox(sticky,mMainWidget);
00202 mBtnTo = new QPushButton("...",mMainWidget);
00203 mBtnCc = new QPushButton("...",mMainWidget);
00204 mBtnBcc = new QPushButton("...",mMainWidget);
00205
00206 mBtnReplyTo = new QPushButton("...",mMainWidget);
00207
00208
00209 mDone = false;
00210 mGrid = 0;
00211 mAtmListView = 0;
00212 mAtmList.setAutoDelete(TRUE);
00213 mAtmTempList.setAutoDelete(TRUE);
00214 mAtmModified = FALSE;
00215 mAutoDeleteMsg = FALSE;
00216 mFolder = 0;
00217 mAutoCharset = TRUE;
00218 mFixedFontAction = 0;
00219 mEditor = new KMEdit( mMainWidget, this, mDictionaryCombo->spellConfig() );
00220 mEditor->setTextFormat(Qt::PlainText);
00221 mEditor->setAcceptDrops( true );
00222
00223 QString tip = i18n("Select email address(es)");
00224 QToolTip::add( mBtnTo, tip );
00225 QToolTip::add( mBtnCc, tip );
00226 QToolTip::add( mBtnReplyTo, tip );
00227
00228 QWhatsThis::add( mBtnIdentity, i18n("Remember this identity, so that it "
00229 "will be used in future composer windows as well."));
00230 QWhatsThis::add( mBtnFcc, i18n("Remember this folder for sent items, so "
00231 "that it will be used in future composer windows as well."));
00232 QWhatsThis::add( mBtnTransport, i18n("Remember this mail transport, so "
00233 "that it will be used in future composer windows as well."));
00234
00235 mSpellCheckInProgress=FALSE;
00236
00237 setCaption( i18n("Composer") );
00238 setMinimumSize(200,200);
00239
00240 mBtnIdentity->setFocusPolicy(QWidget::NoFocus);
00241 mBtnFcc->setFocusPolicy(QWidget::NoFocus);
00242 mBtnTransport->setFocusPolicy(QWidget::NoFocus);
00243 mBtnTo->setFocusPolicy(QWidget::NoFocus);
00244 mBtnCc->setFocusPolicy(QWidget::NoFocus);
00245 mBtnBcc->setFocusPolicy(QWidget::NoFocus);
00246
00247 mBtnReplyTo->setFocusPolicy(QWidget::NoFocus);
00248
00249 mAtmListView = new AttachmentListView( this, mMainWidget,
00250 "attachment list view" );
00251 mAtmListView->setSelectionMode( QListView::Extended );
00252 mAtmListView->setFocusPolicy( QWidget::NoFocus );
00253 mAtmListView->addColumn( i18n("Name"), 200 );
00254 mAtmListView->addColumn( i18n("Size"), 80 );
00255 mAtmListView->addColumn( i18n("Encoding"), 120 );
00256 int atmColType = mAtmListView->addColumn( i18n("Type"), 120 );
00257
00258 mAtmListView->header()->setStretchEnabled( true, atmColType );
00259 mAtmEncryptColWidth = 80;
00260 mAtmSignColWidth = 80;
00261 mAtmColEncrypt = mAtmListView->addColumn( i18n("Encrypt"),
00262 mAtmEncryptColWidth );
00263 mAtmColSign = mAtmListView->addColumn( i18n("Sign"),
00264 mAtmSignColWidth );
00265 mAtmListView->setColumnWidth( mAtmColEncrypt, 0 );
00266 mAtmListView->setColumnWidth( mAtmColSign, 0 );
00267 mAtmListView->setAllColumnsShowFocus( true );
00268
00269 connect( mAtmListView,
00270 SIGNAL( doubleClicked( QListViewItem* ) ),
00271 SLOT( slotAttachOpen() ) );
00272 connect( mAtmListView,
00273 SIGNAL( rightButtonPressed( QListViewItem*, const QPoint&, int ) ),
00274 SLOT( slotAttachPopupMenu( QListViewItem*, const QPoint&, int ) ) );
00275 connect( mAtmListView,
00276 SIGNAL( selectionChanged() ),
00277 SLOT( slotUpdateAttachActions() ) );
00278 mAttachMenu = 0;
00279
00280 readConfig();
00281 setupStatusBar();
00282 setupEditor();
00283 if( !aMsg || aMsg->headerField("X-KMail-CryptoFormat").isEmpty() )
00284 setupActions();
00285 else
00286 setupActions( aMsg->headerField("X-KMail-CryptoFormat").stripWhiteSpace().toInt() );
00287
00288 applyMainWindowSettings(KMKernel::config(), "Composer");
00289
00290 connect( mEdtSubject, SIGNAL( subjectTextSpellChecked() ),
00291 SLOT( slotSubjectTextSpellChecked() ) );
00292 connect(mEdtSubject,SIGNAL(textChanged(const QString&)),
00293 SLOT(slotUpdWinTitle(const QString&)));
00294 connect(mBtnTo,SIGNAL(clicked()),SLOT(slotAddrBookTo()));
00295 connect(mBtnCc,SIGNAL(clicked()),SLOT(slotAddrBookTo()));
00296 connect(mBtnBcc,SIGNAL(clicked()),SLOT(slotAddrBookTo()));
00297 connect(mBtnReplyTo,SIGNAL(clicked()),SLOT(slotAddrBookReplyTo()));
00298
00299 connect(mIdentity,SIGNAL(identityChanged(uint)),
00300 SLOT(slotIdentityChanged(uint)));
00301 connect( kmkernel->identityManager(), SIGNAL(changed(uint)),
00302 SLOT(slotIdentityChanged(uint)));
00303
00304 connect(mEdtTo,SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
00305 SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)));
00306 connect(mEdtCc,SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
00307 SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)));
00308 connect(mEdtBcc,SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
00309 SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)));
00310 connect(mEdtReplyTo,SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
00311 SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)));
00312 connect(mEdtFrom,SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
00313 SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)));
00314 connect(kmkernel->folderMgr(),SIGNAL(folderRemoved(KMFolder*)),
00315 SLOT(slotFolderRemoved(KMFolder*)));
00316 connect(kmkernel->imapFolderMgr(),SIGNAL(folderRemoved(KMFolder*)),
00317 SLOT(slotFolderRemoved(KMFolder*)));
00318 connect(kmkernel->dimapFolderMgr(),SIGNAL(folderRemoved(KMFolder*)),
00319 SLOT(slotFolderRemoved(KMFolder*)));
00320 connect( kmkernel, SIGNAL( configChanged() ),
00321 this, SLOT( slotConfigChanged() ) );
00322
00323 connect (mEditor, SIGNAL (spellcheck_done(int)),
00324 this, SLOT (slotSpellcheckDone (int)));
00325
00326 mMainWidget->resize(480,510);
00327 setCentralWidget(mMainWidget);
00328 rethinkFields();
00329
00330 if (mUseExtEditor) {
00331 mEditor->setUseExternalEditor(true);
00332 mEditor->setExternalEditorPath(mExtEditor);
00333 }
00334
00335 initAutoSave();
00336
00337 slotUpdateSignatureActions();
00338
00339 mMsg = 0;
00340 if (aMsg)
00341 setMsg(aMsg);
00342
00343 mEdtTo->setFocus();
00344
00345 mDone = true;
00346 }
00347
00348
00349 KMComposeWin::~KMComposeWin()
00350 {
00351 writeConfig();
00352 if (mFolder && mMsg)
00353 {
00354 mAutoDeleteMsg = FALSE;
00355 mFolder->addMsg(mMsg);
00356
00357 mFolder->unGetMsg( mFolder->count() - 1 );
00358 }
00359 if (mAutoDeleteMsg) {
00360 delete mMsg;
00361 mMsg = 0;
00362 }
00363 QMap<KIO::Job*, atmLoadData>::Iterator it = mMapAtmLoadData.begin();
00364 while ( it != mMapAtmLoadData.end() )
00365 {
00366 KIO::Job *job = it.key();
00367 mMapAtmLoadData.remove( it );
00368 job->kill();
00369 it = mMapAtmLoadData.begin();
00370 }
00371 deleteAll( mComposedMessages );
00372 }
00373
00374 void KMComposeWin::setAutoDeleteWindow( bool f )
00375 {
00376 if ( f )
00377 setWFlags( getWFlags() | WDestructiveClose );
00378 else
00379 setWFlags( getWFlags() & ~WDestructiveClose );
00380 }
00381
00382
00383 void KMComposeWin::send(int how)
00384 {
00385 switch (how) {
00386 case 1:
00387 slotSendNow();
00388 break;
00389 default:
00390 case 0:
00391
00392 case 2:
00393 slotSendLater();
00394 break;
00395 }
00396 }
00397
00398
00399 void KMComposeWin::addAttachment(KURL url,QString )
00400 {
00401 addAttach(url);
00402 }
00403
00404
00405 void KMComposeWin::addAttachment(const QString &name,
00406 const QCString &,
00407 const QByteArray &data,
00408 const QCString &type,
00409 const QCString &subType,
00410 const QCString ¶mAttr,
00411 const QString ¶mValue,
00412 const QCString &contDisp)
00413 {
00414 if (!data.isEmpty()) {
00415 KMMessagePart *msgPart = new KMMessagePart;
00416 msgPart->setName(name);
00417 if ( type == "message" && subType == "rfc822" ) {
00418 msgPart->setMessageBody( data );
00419 } else {
00420 QValueList<int> dummy;
00421 msgPart->setBodyAndGuessCte(data, dummy,
00422 kmkernel->msgSender()->sendQuotedPrintable());
00423 }
00424 msgPart->setTypeStr(type);
00425 msgPart->setSubtypeStr(subType);
00426 msgPart->setParameter(paramAttr,paramValue);
00427 msgPart->setContentDisposition(contDisp);
00428 addAttach(msgPart);
00429 }
00430 }
00431
00432
00433 void KMComposeWin::setBody(QString body)
00434 {
00435 mEditor->setText(body);
00436 }
00437
00438
00439 bool KMComposeWin::event(QEvent *e)
00440 {
00441 if (e->type() == QEvent::ApplicationPaletteChange)
00442 {
00443 readColorConfig();
00444 }
00445 return KMail::SecondaryWindow::event(e);
00446 }
00447
00448
00449
00450 void KMComposeWin::readColorConfig(void)
00451 {
00452 KConfig *config = KMKernel::config();
00453 KConfigGroupSaver saver(config, "Reader");
00454 QColor c1=QColor(kapp->palette().active().text());
00455 QColor c4=QColor(kapp->palette().active().base());
00456
00457 if (!config->readBoolEntry("defaultColors",TRUE)) {
00458 mForeColor = config->readColorEntry("ForegroundColor",&c1);
00459 mBackColor = config->readColorEntry("BackgroundColor",&c4);
00460 }
00461 else {
00462 mForeColor = c1;
00463 mBackColor = c4;
00464 }
00465
00466
00467 mPalette = kapp->palette();
00468 QColorGroup cgrp = mPalette.active();
00469 cgrp.setColor( QColorGroup::Base, mBackColor);
00470 cgrp.setColor( QColorGroup::Text, mForeColor);
00471 mPalette.setActive(cgrp);
00472 mPalette.setInactive(cgrp);
00473
00474 mEdtTo->setPalette(mPalette);
00475 mEdtFrom->setPalette(mPalette);
00476 mEdtCc->setPalette(mPalette);
00477 mEdtSubject->setPalette(mPalette);
00478 mEdtReplyTo->setPalette(mPalette);
00479 mEdtBcc->setPalette(mPalette);
00480 mTransport->setPalette(mPalette);
00481 mEditor->setPalette(mPalette);
00482 mFcc->setPalette(mPalette);
00483 }
00484
00485
00486 void KMComposeWin::readConfig(void)
00487 {
00488 KConfig *config = KMKernel::config();
00489 QCString str;
00490
00491 int maxTransportItems;
00492
00493 KConfigGroupSaver saver(config, "Composer");
00494
00495 mDefCharset = KMMessage::defaultCharset();
00496 mForceReplyCharset = config->readBoolEntry("force-reply-charset", false );
00497 mAutoSign = config->readEntry("signature","auto") == "auto";
00498 mShowHeaders = config->readNumEntry("headers", HDR_STANDARD);
00499 mWordWrap = config->readBoolEntry("word-wrap", true);
00500 mUseFixedFont = config->readBoolEntry("use-fixed-font", false);
00501 mLineBreak = config->readNumEntry("break-at", 78);
00502 mBtnIdentity->setChecked(config->readBoolEntry("sticky-identity", false));
00503 if (mBtnIdentity->isChecked())
00504 mId = config->readUnsignedNumEntry("previous-identity", mId );
00505 mBtnFcc->setChecked(config->readBoolEntry("sticky-fcc", false));
00506 QString previousFcc = kmkernel->sentFolder()->idString();
00507 if (mBtnFcc->isChecked())
00508 previousFcc = config->readEntry("previous-fcc", previousFcc );
00509 mBtnTransport->setChecked(config->readBoolEntry("sticky-transport", false));
00510 mTransportHistory = config->readListEntry("transport-history");
00511 QString currentTransport = config->readEntry("current-transport");
00512 maxTransportItems = config->readNumEntry("max-transport-items",10);
00513
00514 if ((mLineBreak == 0) || (mLineBreak > 78))
00515 mLineBreak = 78;
00516 if (mLineBreak < 30)
00517 mLineBreak = 30;
00518 mOutlookCompatible = config->readBoolEntry( "outlook-compatible-attachments", false );
00519 mAutoPgpSign = config->readBoolEntry("pgp-auto-sign", false);
00520 mAutoPgpEncrypt = config->readBoolEntry("pgp-auto-encrypt", false);
00521 mNeverEncryptWhenSavingInDrafts = config->readBoolEntry("never-encrypt-drafts", true);
00522 mConfirmSend = config->readBoolEntry("confirm-before-send", false);
00523 mAutoRequestMDN = config->readBoolEntry("request-mdn", false);
00524 #ifdef KLEO_CHIASMUS
00525 mChiasmusKey = config->readEntry( "chiasmus-key" );
00526 mChiasmusOptions = config->readEntry( "chiasmus-options" );
00527 #endif
00528
00529 int mode = config->readNumEntry("Completion Mode",
00530 KGlobalSettings::completionMode() );
00531 mEdtFrom->setCompletionMode( (KGlobalSettings::Completion) mode );
00532 mEdtReplyTo->setCompletionMode( (KGlobalSettings::Completion) mode );
00533 mEdtTo->setCompletionMode( (KGlobalSettings::Completion) mode );
00534 mEdtCc->setCompletionMode( (KGlobalSettings::Completion) mode );
00535 mEdtBcc->setCompletionMode( (KGlobalSettings::Completion) mode );
00536
00537 readColorConfig();
00538
00539 {
00540 KConfigGroupSaver saver(config, "General");
00541 mExtEditor = config->readPathEntry("external-editor", DEFAULT_EDITOR_STR);
00542 mUseExtEditor = config->readBoolEntry("use-external-editor", FALSE);
00543
00544 int headerCount = config->readNumEntry("mime-header-count", 0);
00545 mCustHeaders.clear();
00546 mCustHeaders.setAutoDelete(true);
00547 for (int i = 0; i < headerCount; i++) {
00548 QString thisGroup;
00549 _StringPair *thisItem = new _StringPair;
00550 thisGroup.sprintf("Mime #%d", i);
00551 KConfigGroupSaver saver(config, thisGroup);
00552 thisItem->name = config->readEntry("name");
00553 if ((thisItem->name).length() > 0) {
00554 thisItem->value = config->readEntry("value");
00555 mCustHeaders.append(thisItem);
00556 } else {
00557 delete thisItem;
00558 thisItem = 0;
00559 }
00560 }
00561 }
00562
00563 {
00564 KConfigGroupSaver saver(config, "Fonts");
00565 mBodyFont = KGlobalSettings::generalFont();
00566 mFixedFont = KGlobalSettings::fixedFont();
00567 if (!config->readBoolEntry("defaultFonts",TRUE)) {
00568 mBodyFont = config->readFontEntry("composer-font", &mBodyFont);
00569 mFixedFont = config->readFontEntry("fixed-font", &mFixedFont);
00570 }
00571 slotUpdateFont();
00572 mEdtFrom->setFont(mBodyFont);
00573 mEdtReplyTo->setFont(mBodyFont);
00574 mEdtTo->setFont(mBodyFont);
00575 mEdtCc->setFont(mBodyFont);
00576 mEdtBcc->setFont(mBodyFont);
00577 mEdtSubject->setFont(mBodyFont);
00578 }
00579
00580 {
00581 KConfigGroupSaver saver(config, "Geometry");
00582 QSize defaultSize(480,510);
00583 QSize siz = config->readSizeEntry("composer", &defaultSize);
00584 if (siz.width() < 200) siz.setWidth(200);
00585 if (siz.height() < 200) siz.setHeight(200);
00586 resize(siz);
00587 }
00588
00589 mIdentity->setCurrentIdentity( mId );
00590
00591 kdDebug(5006) << "KMComposeWin::readConfig. " << mIdentity->currentIdentityName() << endl;
00592 const KPIM::Identity & ident =
00593 kmkernel->identityManager()->identityForUoid( mIdentity->currentIdentity() );
00594
00595 mDictionaryCombo->setCurrentByDictionary( ident.dictionary() );
00596
00597 mTransport->clear();
00598 mTransport->insertStringList( KMTransportInfo::availableTransports() );
00599 while (mTransportHistory.count() > (uint)maxTransportItems)
00600 mTransportHistory.remove( mTransportHistory.last() );
00601 mTransport->insertStringList( mTransportHistory );
00602 if (mBtnTransport->isChecked() && !currentTransport.isEmpty())
00603 {
00604 for (int i = 0; i < mTransport->count(); i++)
00605 if (mTransport->text(i) == currentTransport)
00606 mTransport->setCurrentItem(i);
00607 mTransport->setEditText( currentTransport );
00608 }
00609
00610 if ( !mBtnFcc->isChecked() )
00611 {
00612 kdDebug(5006) << "KMComposeWin::readConfig: identity.fcc()='"
00613 << ident.fcc() << "'" << endl;
00614 if ( ident.fcc().isEmpty() )
00615 previousFcc = kmkernel->sentFolder()->idString();
00616 else
00617 previousFcc = ident.fcc();
00618 kdDebug(5006) << "KMComposeWin::readConfig: previousFcc="
00619 << previousFcc << endl;
00620 }
00621
00622 setFcc( previousFcc );
00623 }
00624
00625
00626 void KMComposeWin::writeConfig(void)
00627 {
00628 KConfig *config = KMKernel::config();
00629 QString str;
00630
00631 {
00632 KConfigGroupSaver saver(config, "Composer");
00633 config->writeEntry("signature", mAutoSign?"auto":"manual");
00634 config->writeEntry("headers", mShowHeaders);
00635 config->writeEntry("sticky-transport", mBtnTransport->isChecked());
00636 config->writeEntry("sticky-identity", mBtnIdentity->isChecked());
00637 config->writeEntry("sticky-fcc", mBtnFcc->isChecked());
00638 config->writeEntry("previous-identity", mIdentity->currentIdentity() );
00639 config->writeEntry("current-transport", mTransport->currentText());
00640 config->writeEntry("previous-fcc", mFcc->getFolder()->idString() );
00641 config->writeEntry( "autoSpellChecking",
00642 mAutoSpellCheckingAction->isChecked() );
00643 mTransportHistory.remove(mTransport->currentText());
00644 if (KMTransportInfo::availableTransports().findIndex(mTransport
00645 ->currentText()) == -1)
00646 mTransportHistory.prepend(mTransport->currentText());
00647 config->writeEntry("transport-history", mTransportHistory );
00648 config->writeEntry("use-fixed-font", mUseFixedFont );
00649 #ifdef KLEO_CHIASMUS
00650 config->writeEntry( "chiasmus-key", mChiasmusKey );
00651 config->writeEntry( "chiasmus-options", mChiasmusOptions );
00652 #endif
00653 }
00654
00655 {
00656 KConfigGroupSaver saver(config, "Geometry");
00657 config->writeEntry("composer", size());
00658
00659 saveMainWindowSettings(config, "Composer");
00660 config->sync();
00661 }
00662 }
00663
00664
00665
00666 void KMComposeWin::autoSaveMessage()
00667 {
00668 kdDebug(5006) << k_funcinfo << endl;
00669 if ( !mMsg || mComposer || mAutoSaveFilename.isEmpty() )
00670 return;
00671 kdDebug(5006) << k_funcinfo << "autosaving message" << endl;
00672
00673 if ( mAutoSaveTimer )
00674 mAutoSaveTimer->stop();
00675 connect( this, SIGNAL( applyChangesDone( bool ) ),
00676 this, SLOT( slotContinueAutoSave( bool ) ) );
00677
00678
00679
00680 applyChanges( true, true );
00681
00682
00683 qApp->enter_loop();
00684
00685
00686 if ( mComposedMessages.isEmpty() ) {
00687 kdDebug(5006) << "Composing the message failed." << endl;
00688 return;
00689 }
00690 KMMessage *msg = mComposedMessages.first();
00691
00692 kdDebug(5006) << k_funcinfo << "opening autoSaveFile " << mAutoSaveFilename
00693 << endl;
00694 const QString filename =
00695 KMKernel::localDataPath() + "autosave/cur/" + mAutoSaveFilename;
00696 KSaveFile autoSaveFile( filename, 0600 );
00697 int status = autoSaveFile.status();
00698 kdDebug(5006) << k_funcinfo << "autoSaveFile.status() = " << status << endl;
00699 if ( status == 0 ) {
00700 kdDebug(5006) << "autosaving message in " << filename << endl;
00701 int fd = autoSaveFile.handle();
00702 QCString msgStr = msg->asString();
00703 if ( ::write( fd, msgStr, msgStr.length() ) == -1 )
00704 status = errno;
00705 }
00706 if ( status == 0 ) {
00707 kdDebug(5006) << k_funcinfo << "closing autoSaveFile" << endl;
00708 autoSaveFile.close();
00709 mLastAutoSaveErrno = 0;
00710 }
00711 else {
00712 kdDebug(5006) << k_funcinfo << "autosaving failed" << endl;
00713 autoSaveFile.abort();
00714 if ( status != mLastAutoSaveErrno ) {
00715
00716 KMessageBox::queuedMessageBox( 0, KMessageBox::Sorry,
00717 i18n("Autosaving the message as %1 "
00718 "failed.\n"
00719 "Reason: %2" )
00720 .arg( filename, strerror( status ) ),
00721 i18n("Autosaving Failed") );
00722 mLastAutoSaveErrno = status;
00723 }
00724 }
00725
00726 if ( autoSaveInterval() > 0 )
00727 mAutoSaveTimer->start( autoSaveInterval() );
00728 }
00729
00730 void KMComposeWin::slotContinueAutoSave( bool )
00731 {
00732 disconnect( this, SIGNAL( applyChangesDone( bool ) ),
00733 this, SLOT( slotContinueAutoSave( bool ) ) );
00734 qApp->exit_loop();
00735 }
00736
00737
00738
00739 void KMComposeWin::slotView(void)
00740 {
00741 if (!mDone)
00742 return;
00743
00744 int id;
00745
00746
00747
00748 if (!sender()->isA("KToggleAction"))
00749 return;
00750 KToggleAction *act = (KToggleAction *) sender();
00751
00752 if (act == mAllFieldsAction)
00753 id = 0;
00754 else if (act == mIdentityAction)
00755 id = HDR_IDENTITY;
00756 else if (act == mTransportAction)
00757 id = HDR_TRANSPORT;
00758 else if (act == mFromAction)
00759 id = HDR_FROM;
00760 else if (act == mReplyToAction)
00761 id = HDR_REPLY_TO;
00762 else if (act == mToAction)
00763 id = HDR_TO;
00764 else if (act == mCcAction)
00765 id = HDR_CC;
00766 else if (act == mBccAction)
00767 id = HDR_BCC;
00768 else if (act == mSubjectAction)
00769 id = HDR_SUBJECT;
00770 else if (act == mFccAction)
00771 id = HDR_FCC;
00772 else if ( act == mDictionaryAction )
00773 id = HDR_DICTIONARY;
00774 else
00775 {
00776 id = 0;
00777 kdDebug(5006) << "Something is wrong (Oh, yeah?)" << endl;
00778 return;
00779 }
00780
00781
00782
00783
00784 if (!act->isChecked())
00785 {
00786
00787 if (id > 0) mShowHeaders = mShowHeaders & ~id;
00788 else mShowHeaders = abs(mShowHeaders);
00789 }
00790 else
00791 {
00792
00793 if (id > 0) mShowHeaders |= id;
00794 else mShowHeaders = -abs(mShowHeaders);
00795 }
00796 rethinkFields(true);
00797
00798 }
00799
00800 void KMComposeWin::rethinkFields(bool fromSlot)
00801 {
00802
00803 int mask, row, numRows;
00804 long showHeaders;
00805
00806 if (mShowHeaders < 0)
00807 showHeaders = HDR_ALL;
00808 else
00809 showHeaders = mShowHeaders;
00810
00811 for (mask=1,mNumHeaders=0; mask<=showHeaders; mask<<=1)
00812 if ((showHeaders&mask) != 0) mNumHeaders++;
00813
00814 numRows = mNumHeaders + 2;
00815
00816 delete mGrid;
00817 mGrid = new QGridLayout(mMainWidget, numRows, 3, 4, 4);
00818 mGrid->setColStretch(0, 1);
00819 mGrid->setColStretch(1, 100);
00820 mGrid->setColStretch(2, 1);
00821 mGrid->setRowStretch(mNumHeaders, 100);
00822
00823 mEdtList.clear();
00824 row = 0;
00825 kdDebug(5006) << "KMComposeWin::rethinkFields" << endl;
00826 if (!fromSlot) mAllFieldsAction->setChecked(showHeaders==HDR_ALL);
00827
00828 if (!fromSlot) mIdentityAction->setChecked(abs(mShowHeaders)&HDR_IDENTITY);
00829 rethinkHeaderLine(showHeaders,HDR_IDENTITY, row, i18n("&Identity:"),
00830 mLblIdentity, mIdentity, mBtnIdentity);
00831 if (!fromSlot) mDictionaryAction->setChecked(abs(mShowHeaders)&HDR_DICTIONARY);
00832 rethinkHeaderLine(showHeaders,HDR_DICTIONARY, row, i18n("&Dictionary:"),
00833 mDictionaryLabel, mDictionaryCombo, 0 );
00834 if (!fromSlot) mFccAction->setChecked(abs(mShowHeaders)&HDR_FCC);
00835 rethinkHeaderLine(showHeaders,HDR_FCC, row, i18n("Se&nt-Mail folder:"),
00836 mLblFcc, mFcc, mBtnFcc);
00837 if (!fromSlot) mTransportAction->setChecked(abs(mShowHeaders)&HDR_TRANSPORT);
00838 rethinkHeaderLine(showHeaders,HDR_TRANSPORT, row, i18n("Mai&l transport:"),
00839 mLblTransport, mTransport, mBtnTransport);
00840 if (!fromSlot) mFromAction->setChecked(abs(mShowHeaders)&HDR_FROM);
00841 rethinkHeaderLine(showHeaders,HDR_FROM, row, i18n("&From:"),
00842 mLblFrom, mEdtFrom );
00843 if (!fromSlot) mReplyToAction->setChecked(abs(mShowHeaders)&HDR_REPLY_TO);
00844 rethinkHeaderLine(showHeaders,HDR_REPLY_TO,row,i18n("&Reply to:"),
00845 mLblReplyTo, mEdtReplyTo, mBtnReplyTo);
00846 if (!fromSlot) mToAction->setChecked(abs(mShowHeaders)&HDR_TO);
00847 rethinkHeaderLine(showHeaders, HDR_TO, row, i18n("To:"),
00848 mLblTo, mEdtTo, mBtnTo,
00849 i18n("Primary Recipients"),
00850 i18n("<qt>The email addresses you put "
00851 "in this field receive a copy of the email.</qt>"));
00852 if (!fromSlot) mCcAction->setChecked(abs(mShowHeaders)&HDR_CC);
00853 rethinkHeaderLine(showHeaders, HDR_CC, row, i18n("&Copy to (CC):"),
00854 mLblCc, mEdtCc, mBtnCc,
00855 i18n("Additional Recipients"),
00856 i18n("<qt>The email addresses you put "
00857 "in this field receive a copy of the email. "
00858 "Technically it is the same thing as putting all the "
00859 "addresses in the <b>To:</b> field but differs in "
00860 "that it usually symbolises the receiver of the "
00861 "Carbon Copy (CC) is a listener, not the main "
00862 "recipient.</qt>"));
00863 if (!fromSlot) mBccAction->setChecked(abs(mShowHeaders)&HDR_BCC);
00864 rethinkHeaderLine(showHeaders,HDR_BCC, row, i18n("&Blind copy to (BCC):"),
00865 mLblBcc, mEdtBcc, mBtnBcc,
00866 i18n("Hidden Recipients"),
00867 i18n("<qt>Essentially the same thing "
00868 "as the <b>Copy To:</b> field but differs in that "
00869 "all other recipients do not see who receives a "
00870 "blind copy.</qt>"));
00871 if (!fromSlot) mSubjectAction->setChecked(abs(mShowHeaders)&HDR_SUBJECT);
00872 rethinkHeaderLine(showHeaders,HDR_SUBJECT, row, i18n("S&ubject:"),
00873 mLblSubject, mEdtSubject);
00874 assert(row<=mNumHeaders);
00875
00876 mGrid->addMultiCellWidget(mEditor, row, mNumHeaders, 0, 2);
00877 mGrid->addMultiCellWidget(mAtmListView, mNumHeaders+1, mNumHeaders+1, 0, 2);
00878
00879 if( !mAtmList.isEmpty() )
00880 mAtmListView->show();
00881 else
00882 mAtmListView->hide();
00883 resize(this->size());
00884 repaint();
00885
00886 mGrid->activate();
00887
00888 slotUpdateAttachActions();
00889 mIdentityAction->setEnabled(!mAllFieldsAction->isChecked());
00890 mDictionaryAction->setEnabled( !mAllFieldsAction->isChecked() );
00891 mTransportAction->setEnabled(!mAllFieldsAction->isChecked());
00892 mFromAction->setEnabled(!mAllFieldsAction->isChecked());
00893 mReplyToAction->setEnabled(!mAllFieldsAction->isChecked());
00894 mToAction->setEnabled(!mAllFieldsAction->isChecked());
00895 mCcAction->setEnabled(!mAllFieldsAction->isChecked());
00896 mBccAction->setEnabled(!mAllFieldsAction->isChecked());
00897 mFccAction->setEnabled(!mAllFieldsAction->isChecked());
00898 mSubjectAction->setEnabled(!mAllFieldsAction->isChecked());
00899 }
00900
00901
00902
00903 void KMComposeWin::rethinkHeaderLine(int aValue, int aMask, int& aRow,
00904 const QString &aLabelStr, QLabel* aLbl,
00905 QLineEdit* aEdt, QPushButton* aBtn,
00906 const QString &toolTip, const QString &whatsThis )
00907 {
00908 if (aValue & aMask)
00909 {
00910 aLbl->setText(aLabelStr);
00911 if ( !toolTip.isEmpty() )
00912 QToolTip::add( aLbl, toolTip );
00913 if ( !whatsThis.isEmpty() )
00914 QWhatsThis::add( aLbl, whatsThis );
00915 aLbl->adjustSize();
00916 aLbl->resize((int)aLbl->sizeHint().width(),aLbl->sizeHint().height() + 6);
00917 aLbl->setMinimumSize(aLbl->size());
00918 aLbl->show();
00919 aLbl->setBuddy(aEdt);
00920 mGrid->addWidget(aLbl, aRow, 0);
00921
00922 aEdt->setBackgroundColor( mBackColor );
00923 aEdt->show();
00924 aEdt->setMinimumSize(100, aLbl->height()+2);
00925 mEdtList.append(aEdt);
00926
00927 mGrid->addWidget(aEdt, aRow, 1);
00928 if (aBtn)
00929 {
00930 mGrid->addWidget(aBtn, aRow, 2);
00931 aBtn->setFixedSize(aBtn->sizeHint().width(), aLbl->height());
00932 aBtn->show();
00933 }
00934 aRow++;
00935 }
00936 else
00937 {
00938 aLbl->hide();
00939 aEdt->hide();
00940 if (aBtn) aBtn->hide();
00941 }
00942 }
00943
00944
00945 void KMComposeWin::rethinkHeaderLine(int aValue, int aMask, int& aRow,
00946 const QString &aLabelStr, QLabel* aLbl,
00947 QComboBox* aCbx, QCheckBox* aChk)
00948 {
00949 if (aValue & aMask)
00950 {
00951 aLbl->setText(aLabelStr);
00952 aLbl->adjustSize();
00953 aLbl->resize((int)aLbl->sizeHint().width(),aLbl->sizeHint().height() + 6);
00954 aLbl->setMinimumSize(aLbl->size());
00955 aLbl->show();
00956 aLbl->setBuddy(aCbx);
00957 mGrid->addWidget(aLbl, aRow, 0);
00958
00959
00960 aCbx->show();
00961 aCbx->setMinimumSize(100, aLbl->height()+2);
00962
00963 mGrid->addWidget(aCbx, aRow, 1);
00964 if ( aChk ) {
00965 mGrid->addWidget(aChk, aRow, 2);
00966 aChk->setFixedSize(aChk->sizeHint().width(), aLbl->height());
00967 aChk->show();
00968 }
00969 aRow++;
00970 }
00971 else
00972 {
00973 aLbl->hide();
00974 aCbx->hide();
00975 if ( aChk )
00976 aChk->hide();
00977 }
00978 }
00979
00980 namespace {
00981
00982 #if KDE_IS_VERSION( 3, 3, 0 )
00983
00984 typedef KToggleAction K33ToggleAction;
00985 #else
00986 class K33ToggleAction : public KToggleAction {
00987 KGuiItem * m_checkedGuiItem;
00988 public:
00989 K33ToggleAction( const QString & text, const QString & pix, const KShortcut & cut,
00990 QObject * parent, const char * name=0 )
00991 : KToggleAction( text, pix, cut, parent, name ),
00992 m_checkedGuiItem( 0 )
00993 {
00994
00995 }
00996 ~K33ToggleAction() {
00997 delete m_checkedGuiItem; m_checkedGuiItem = 0;
00998 }
00999
01000
01001 void updateChecked( int id ) {
01002 if ( !m_checkedGuiItem ) {
01003 KToggleAction::updateChecked( id );
01004 return;
01005 }
01006
01007 QWidget *w = container( id );
01008
01009 if ( ::qt_cast<QPopupMenu *>( w ) ) {
01010 QPopupMenu* pm = static_cast<QPopupMenu*>(w);
01011 int itemId_ = itemId( id );
01012 if ( isChecked() ) {
01013 if ( m_checkedGuiItem->hasIcon() )
01014 pm->changeItem( itemId_, m_checkedGuiItem->iconSet( KIcon::Small ), m_checkedGuiItem->text() );
01015 else
01016 pm->changeItem( itemId_, m_checkedGuiItem->text() );
01017 if ( !m_checkedGuiItem->whatsThis().isEmpty() )
01018 pm->setWhatsThis( itemId_, m_checkedGuiItem->whatsThis() );
01019 } else {
01020 if ( hasIcon() )
01021 pm->changeItem( itemId_, iconSet( KIcon::Small ), text() );
01022 else
01023 pm->changeItem( itemId_, text() );
01024 pm->setWhatsThis( itemId_, whatsThis() );
01025 }
01026 pm->setItemChecked( itemId_, isChecked() );
01027 updateShortcut( pm, itemId_ );
01028 }
01029 else if ( ::qt_cast<QMenuBar *>( w ) )
01030 static_cast<QMenuBar*>(w)->setItemChecked( itemId( id ), isChecked() );
01031 else if ( ::qt_cast<KToolBar *>( w ) ) {
01032 QWidget* r = static_cast<KToolBar*>( w )->getButton( itemId( id ) );
01033 if ( r && ::qt_cast<KToolBarButton *>( r ) ) {
01034 static_cast<KToolBar*>( w )->setButton( itemId( id ), isChecked() );
01035 if ( m_checkedGuiItem->hasIcon() ) {
01036 const QIconSet iconSet = isChecked()
01037 ? m_checkedGuiItem->iconSet( KIcon::Toolbar )
01038 : this->iconSet( KIcon::Toolbar );
01039 static_cast<KToolBar*>( w )->setButtonIconSet( itemId( id ), iconSet );
01040 }
01041 }
01042 }
01043 }
01044
01045 void setCheckedState( const KGuiItem & item ) {
01046 delete m_checkedGuiItem;
01047 m_checkedGuiItem = new KGuiItem( item );
01048 }
01049
01050 QString toolTip() const {
01051 if ( m_checkedGuiItem && isChecked() )
01052 return m_checkedGuiItem->toolTip();
01053 else
01054 return KToggleAction::toolTip();
01055 }
01056 };
01057
01058 #endif
01059
01060 }
01061
01062
01063 void KMComposeWin::setupActions(int aCryptoMessageFormat)
01064 {
01065 if (kmkernel->msgSender()->sendImmediate())
01066 {
01067
01068 (void) new KAction (i18n("&Send"), "mail_send", CTRL+Key_Return,
01069 this, SLOT(slotSendNow()), actionCollection(),
01070 "send_default");
01071 (void) new KAction (i18n("&Queue"), "queue", 0,
01072 this, SLOT(slotSendLater()),
01073 actionCollection(), "send_alternative");
01074 }
01075 else
01076 {
01077
01078 (void) new KAction (i18n("&Queue"), "queue",
01079 CTRL+Key_Return,
01080 this, SLOT(slotSendLater()), actionCollection(),
01081 "send_default");
01082 (void) new KAction (i18n("&Send Now"), "mail_send", 0,
01083 this, SLOT(slotSendNow()),
01084 actionCollection(), "send_alternative");
01085 }
01086
01087 (void) new KAction (i18n("Save in &Drafts Folder"), "filesave", 0,
01088 this, SLOT(slotSaveDraft()),
01089 actionCollection(), "save_in_drafts");
01090 (void) new KAction (i18n("&Insert File..."), "fileopen", 0,
01091 this, SLOT(slotInsertFile()),
01092 actionCollection(), "insert_file");
01093 (void) new KAction (i18n("&Address Book"), "contents",0,
01094 this, SLOT(slotAddrBook()),
01095 actionCollection(), "addressbook");
01096 (void) new KAction (i18n("&New Composer"), "mail_new",
01097 KStdAccel::shortcut(KStdAccel::New),
01098 this, SLOT(slotNewComposer()),
01099 actionCollection(), "new_composer");
01100 (void) new KAction (i18n("New Main &Window"), "window_new", 0,
01101 this, SLOT(slotNewMailReader()),
01102 actionCollection(), "open_mailreader");
01103
01104
01105
01106 KStdAction::print (this, SLOT(slotPrint()), actionCollection());
01107 KStdAction::close (this, SLOT(slotClose()), actionCollection());
01108
01109 KStdAction::undo (this, SLOT(slotUndo()), actionCollection());
01110 KStdAction::redo (this, SLOT(slotRedo()), actionCollection());
01111 KStdAction::cut (this, SLOT(slotCut()), actionCollection());
01112 KStdAction::copy (this, SLOT(slotCopy()), actionCollection());
01113 KStdAction::pasteText (this, SLOT(slotPaste()), actionCollection());
01114 KStdAction::selectAll (this, SLOT(slotMarkAll()), actionCollection());
01115
01116 KStdAction::find (this, SLOT(slotFind()), actionCollection());
01117 KStdAction::findNext(this, SLOT(slotSearchAgain()), actionCollection());
01118
01119 KStdAction::replace (this, SLOT(slotReplace()), actionCollection());
01120 KStdAction::spelling (this, SLOT(slotSpellcheck()), actionCollection(), "spellcheck");
01121
01122 (void) new KAction (i18n("Pa&ste as Quotation"),0,this,SLOT( slotPasteAsQuotation()),
01123 actionCollection(), "paste_quoted");
01124
01125 (void) new KAction(i18n("Add &Quote Characters"), 0, this,
01126 SLOT(slotAddQuotes()), actionCollection(), "tools_quote");
01127
01128 (void) new KAction(i18n("Re&move Quote Characters"), 0, this,
01129 SLOT(slotRemoveQuotes()), actionCollection(), "tools_unquote");
01130
01131
01132 (void) new KAction (i18n("Cl&ean Spaces"), 0, this, SLOT(slotCleanSpace()),
01133 actionCollection(), "clean_spaces");
01134
01135 mFixedFontAction = new KToggleAction( i18n("Use Fi&xed Font"), 0, this,
01136 SLOT(slotUpdateFont()), actionCollection(), "toggle_fixedfont" );
01137 mFixedFontAction->setChecked(mUseFixedFont);
01138
01139
01140 mUrgentAction = new KToggleAction (i18n("&Urgent"), 0,
01141 actionCollection(),
01142 "urgent");
01143 mRequestMDNAction = new KToggleAction ( i18n("&Request Disposition Notification"), 0,
01144 actionCollection(),
01145 "options_request_mdn");
01146 mRequestMDNAction->setChecked(mAutoRequestMDN);
01147
01148 mEncodingAction = new KSelectAction( i18n( "Se&t Encoding" ), "charset",
01149 0, this, SLOT(slotSetCharset() ),
01150 actionCollection(), "charsets" );
01151 mWordWrapAction = new KToggleAction (i18n("&Wordwrap"), 0,
01152 actionCollection(), "wordwrap");
01153 mWordWrapAction->setChecked(mWordWrap);
01154 connect(mWordWrapAction, SIGNAL(toggled(bool)), SLOT(slotWordWrapToggled(bool)));
01155
01156 mAutoSpellCheckingAction =
01157 new KToggleAction( i18n( "&Automatic Spellchecking" ), "spellcheck", 0,
01158 actionCollection(), "options_auto_spellchecking" );
01159 KConfigGroup composerConfig( KMKernel::config(), "Composer" );
01160 const bool spellChecking =
01161 composerConfig.readBoolEntry( "autoSpellChecking", true );
01162 mAutoSpellCheckingAction->setEnabled( !mUseExtEditor );
01163 mAutoSpellCheckingAction->setChecked( !mUseExtEditor && spellChecking );
01164 slotAutoSpellCheckingToggled( !mUseExtEditor && spellChecking );
01165 connect( mAutoSpellCheckingAction, SIGNAL( toggled( bool ) ),
01166 this, SLOT( slotAutoSpellCheckingToggled( bool ) ) );
01167
01168 QStringList encodings = KMMsgBase::supportedEncodings(TRUE);
01169 encodings.prepend( i18n("Auto-Detect"));
01170 mEncodingAction->setItems( encodings );
01171 mEncodingAction->setCurrentItem( -1 );
01172
01173
01174 markupAction = new KToggleAction (i18n("Formatting (HTML)"), 0, this,
01175 SLOT(slotToggleMarkup()),
01176 actionCollection(), "html");
01177 markupAction->setChecked(mUseHTMLEditor);
01178
01179 mAllFieldsAction = new KToggleAction (i18n("&All Fields"), 0, this,
01180 SLOT(slotView()),
01181 actionCollection(), "show_all_fields");
01182 mIdentityAction = new KToggleAction (i18n("&Identity"), 0, this,
01183 SLOT(slotView()),
01184 actionCollection(), "show_identity");
01185 mDictionaryAction = new KToggleAction (i18n("&Dictionary"), 0, this,
01186 SLOT(slotView()),
01187 actionCollection(), "show_dictionary");
01188 mFccAction = new KToggleAction (i18n("Sent-Mail F&older"), 0, this,
01189 SLOT(slotView()),
01190 actionCollection(), "show_fcc");
01191 mTransportAction = new KToggleAction (i18n("&Mail Transport"), 0, this,
01192 SLOT(slotView()),
01193 actionCollection(), "show_transport");
01194 mFromAction = new KToggleAction (i18n("&From"), 0, this,
01195 SLOT(slotView()),
01196 actionCollection(), "show_from");
01197 mReplyToAction = new KToggleAction (i18n("&Reply To"), 0, this,
01198 SLOT(slotView()),
01199 actionCollection(), "show_reply_to");
01200 mToAction = new KToggleAction (i18n("&To"), 0, this,
01201 SLOT(slotView()),
01202 actionCollection(), "show_to");
01203 mCcAction = new KToggleAction (i18n("&CC"), 0, this,
01204 SLOT(slotView()),
01205 actionCollection(), "show_cc");
01206 mBccAction = new KToggleAction (i18n("&BCC"), 0, this,
01207 SLOT(slotView()),
01208 actionCollection(), "show_bcc");
01209 mSubjectAction = new KToggleAction (i18n("&Subject"), 0, this,
01210 SLOT(slotView()),
01211 actionCollection(), "show_subject");
01212
01213
01214 mAppendSignatureAction = new KAction (i18n("Append S&ignature"), 0, this,
01215 SLOT(slotAppendSignature()),
01216 actionCollection(), "append_signature");
01217
01218 mPrependSignatureAction = new KAction (i18n("Prepend S&ignature"), 0, this,
01219 SLOT(slotPrependSignature()),
01220 actionCollection(), "prepend_signature");
01221
01222 mInsertSignatureAction = new KAction (i18n("Insert Signature At C&ursor Position"), "edit", 0, this,
01223 SLOT(slotInsertSignatureAtCursor()),
01224 actionCollection(), "insert_signature_at_cursor_position");
01225
01226 mAttachPK = new KAction (i18n("Attach &Public Key..."), 0, this,
01227 SLOT(slotInsertPublicKey()),
01228 actionCollection(), "attach_public_key");
01229 mAttachMPK = new KAction (i18n("Attach &My Public Key"), 0, this,
01230 SLOT(slotInsertMyPublicKey()),
01231 actionCollection(), "attach_my_public_key");
01232 (void) new KAction (i18n("&Attach File..."), "attach",
01233 0, this, SLOT(slotAttachFile()),
01234 actionCollection(), "attach");
01235 mAttachRemoveAction = new KAction (i18n("&Remove Attachment"), 0, this,
01236 SLOT(slotAttachRemove()),
01237 actionCollection(), "remove");
01238 mAttachSaveAction = new KAction (i18n("&Save Attachment As..."), "filesave",0,
01239 this, SLOT(slotAttachSave()),
01240 actionCollection(), "attach_save");
01241 mAttachPropertiesAction = new KAction (i18n("Attachment Pr&operties"), 0, this,
01242 SLOT(slotAttachProperties()),
01243 actionCollection(), "attach_properties");
01244
01245 setStandardToolBarMenuEnabled(true);
01246
01247 KStdAction::keyBindings(this, SLOT(slotEditKeys()), actionCollection());
01248 KStdAction::configureToolbars(this, SLOT(slotEditToolbars()), actionCollection());
01249 KStdAction::preferences(kmkernel, SLOT(slotShowConfigurationDialog()), actionCollection());
01250
01251 (void) new KAction (i18n("Configure &Spellchecker..."), 0, this, SLOT(slotSpellcheckConfig()),
01252 actionCollection(), "setup_spellchecker");
01253
01254 mTextCompletionAction = new KSelectAction (i18n("&Text Completion"), 0,
01255 this, SLOT(slotMenuTextCompletion()),
01256 actionCollection(), "setup_text_completion");
01257
01258
01259
01260 QStringList menuItems;
01261 for ( int i=0; i < KMGlobalNS::numCompletionModes; ++i )
01262 menuItems << i18n( KMGlobalNS::completionModes[i].displayName );
01263
01264 mTextCompletionAction->setItems( menuItems );
01265
01266
01267 KConfigGroup composer( KMKernel::config(), "Composer" );
01268 const int mode = composer.readNumEntry("Completion Mode", KGlobalSettings::completionMode() );
01269 for ( int i=0; i < KMGlobalNS::numCompletionModes; ++i ) {
01270 if ( KMGlobalNS::completionModes[i].mode == mode )
01271 mTextCompletionAction->setCurrentItem( i );
01272 }
01273
01274 (void) new KAction (i18n("Configure Completion &Order..."), 0,
01275 this, SLOT(slotConfigureAddressCompletion()),
01276 actionCollection(), "setup_completion_order");
01277
01278 (void) new KAction ( i18n("Configure &Recent Addresses..." ), 0,
01279 mEdtTo, SLOT( editRecentAddresses() ),
01280 actionCollection(), "setup_recent_addresses" );
01281
01282 #ifdef KLEO_CHIASMUS
01283 if ( Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" ) ) {
01284 K33ToggleAction * a = new K33ToggleAction( i18n( "Encrypt Message with Chiasmus..." ),
01285 "chidecrypted", 0, actionCollection(),
01286 "encrypt_message_chiasmus" );
01287 a->setCheckedState( KGuiItem( i18n( "Encrypt Message with Chiasmus..." ), "chiencrypted" ) );
01288 mEncryptChiasmusAction = a;
01289 a = new K33ToggleAction( i18n( "Encrypt Message Body with Chiasmus..." ),
01290 "chidecrypted", 0, actionCollection(),
01291 "encrypt_message_body_chiasmus" );
01292 a->setCheckedState( KGuiItem( i18n( "Encrypt Message Body with Chiasmus..." ), "chiencrypted" ) );
01293 mEncryptBodyChiasmusAction = a;
01294 mEncryptBodyChiasmusAction->setEnabled( false );
01295
01296 connect( mEncryptChiasmusAction, SIGNAL(toggled(bool)),
01297 this, SLOT(slotEncryptChiasmusToggled(bool)) );
01298 connect( mEncryptBodyChiasmusAction, SIGNAL(toggled(bool)),
01299 this, SLOT(slotEncryptBodyChiasmusToggled(bool)) );
01300
01301 } else {
01302 mEncryptChiasmusAction = 0;
01303 mEncryptBodyChiasmusAction = 0;
01304 }
01305 #endif // KLEO_CHIASMUS
01306
01307 mEncryptAction = new KToggleAction (i18n("&Encrypt Message"),
01308 "decrypted", 0,
01309 actionCollection(), "encrypt_message");
01310 mSignAction = new KToggleAction (i18n("&Sign Message"),
01311 "signature", 0,
01312 actionCollection(), "sign_message");
01313
01314 const KPIM::Identity & ident =
01315 kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() );
01316
01317
01318 mLastIdentityHasSigningKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
01319 mLastIdentityHasEncryptionKey = !ident.pgpEncryptionKey().isEmpty() || !ident.smimeEncryptionKey().isEmpty();
01320
01321 mLastEncryptActionState = false;
01322 mLastSignActionState = mAutoPgpSign;
01323
01324
01325 mAttachPK->setEnabled( Kleo::CryptoBackendFactory::instance()->openpgp() );
01326
01327
01328
01329 mAttachMPK->setEnabled( Kleo::CryptoBackendFactory::instance()->openpgp() &&
01330 !ident.pgpEncryptionKey().isEmpty() );
01331
01332 if ( !Kleo::CryptoBackendFactory::instance()->openpgp() && !Kleo::CryptoBackendFactory::instance()->smime() ) {
01333
01334 mEncryptAction->setEnabled( false );
01335 setEncryption( false );
01336 mSignAction->setEnabled( false );
01337 setSigning( false );
01338 } else {
01339 const bool canOpenPGPSign = Kleo::CryptoBackendFactory::instance()->openpgp()
01340 && !ident.pgpSigningKey().isEmpty();
01341 const bool canSMIMESign = Kleo::CryptoBackendFactory::instance()->smime()
01342 && !ident.smimeSigningKey().isEmpty();
01343
01344 setEncryption( false );
01345 setSigning( ( canOpenPGPSign || canSMIMESign ) && mAutoPgpSign );
01346 }
01347
01348 connect(mEncryptAction, SIGNAL(toggled(bool)),
01349 SLOT(slotEncryptToggled( bool )));
01350 connect(mSignAction, SIGNAL(toggled(bool)),
01351 SLOT(slotSignToggled( bool )));
01352
01353 QStringList l;
01354 for ( int i = 0 ; i < numCryptoMessageFormats ; ++i )
01355 l.push_back( Kleo::cryptoMessageFormatToLabel( cryptoMessageFormats[i] ) );
01356
01357 mCryptoModuleAction = new KSelectAction( i18n( "&Cryptographic Message Format" ), 0,
01358 this, SLOT(slotSelectCryptoModule()),
01359 actionCollection(), "options_select_crypto" );
01360 mCryptoModuleAction->setItems( l );
01361 mCryptoModuleAction->setCurrentItem(
01362 format2cb( (0 <= aCryptoMessageFormat)
01363 ? (Kleo::CryptoMessageFormat)aCryptoMessageFormat
01364 : ident.preferredCryptoMessageFormat() ) );
01365
01366 slotSelectCryptoModule();
01367
01368 QStringList styleItems;
01369 styleItems << i18n( "Standard" );
01370 styleItems << i18n( "Bulleted List (Disc)" );
01371 styleItems << i18n( "Bulleted List (Circle)" );
01372 styleItems << i18n( "Bulleted List (Square)" );
01373 styleItems << i18n( "Ordered List (Decimal)" );
01374 styleItems << i18n( "Ordered List (Alpha lower)" );
01375 styleItems << i18n( "Ordered List (Alpha upper)" );
01376
01377 listAction = new KSelectAction( i18n( "Select Style" ), 0, actionCollection(),
01378 "text_list" );
01379 listAction->setItems( styleItems );
01380 connect( listAction, SIGNAL( activated( const QString& ) ),
01381 SLOT( slotListAction( const QString& ) ) );
01382 fontAction = new KFontAction( "Select Font", 0, actionCollection(),
01383 "text_font" );
01384 connect( fontAction, SIGNAL( activated( const QString& ) ),
01385 SLOT( slotFontAction( const QString& ) ) );
01386 fontSizeAction = new KFontSizeAction( "Select Size", 0, actionCollection(),
01387 "text_size" );
01388 connect( fontSizeAction, SIGNAL( fontSizeChanged( int ) ),
01389 SLOT( slotSizeAction( int ) ) );
01390
01391 alignLeftAction = new KToggleAction (i18n("Align Left"), "text_left", 0,
01392 this, SLOT(slotAlignLeft()), actionCollection(),
01393 "align_left");
01394 alignLeftAction->setChecked( TRUE );
01395 alignRightAction = new KToggleAction (i18n("Align Right"), "text_right", 0,
01396 this, SLOT(slotAlignRight()), actionCollection(),
01397 "align_right");
01398 alignCenterAction = new KToggleAction (i18n("Align Center"), "text_center", 0,
01399 this, SLOT(slotAlignCenter()), actionCollection(),
01400 "align_center");
01401 textBoldAction = new KToggleAction (i18n("&Bold"), "text_bold", 0,
01402 this, SLOT(slotTextBold()),
01403 actionCollection(), "text_bold");
01404 textItalicAction = new KToggleAction (i18n("&Italic"), "text_italic", 0,
01405 this, SLOT(slotTextItalic()),
01406 actionCollection(), "text_italic");
01407 textUnderAction = new KToggleAction (i18n("&Underline"), "text_under", 0,
01408 this, SLOT(slotTextUnder()),
01409 actionCollection(), "text_under");
01410 actionFormatReset = new KAction( i18n( "Reset Font Settings" ), "eraser", 0,
01411 this, SLOT( slotFormatReset() ),
01412 actionCollection(), "format_reset");
01413 actionFormatColor = new KAction( i18n( "Text Color..." ), "colorize", 0,
01414 this, SLOT( slotTextColor() ),
01415 actionCollection(), "format_color");
01416
01417
01418 createGUI("kmcomposerui.rc");
01419
01420
01421 KAction* configureAction = actionCollection()->action("options_configure" );
01422 if ( configureAction )
01423 configureAction->setText( i18n("Configure KMail" ) );
01424 }
01425
01426
01427 void KMComposeWin::setupStatusBar(void)
01428 {
01429 statusBar()->insertItem("", 0, 1);
01430 statusBar()->setItemAlignment(0, AlignLeft | AlignVCenter);
01431
01432 statusBar()->insertItem(i18n(" Column: %1 ").arg(" "),2,0,true);
01433 statusBar()->insertItem(i18n(" Line: %1 ").arg(" "),1,0,true);
01434 }
01435
01436
01437
01438 void KMComposeWin::updateCursorPosition()
01439 {
01440 int col,line;
01441 QString temp;
01442 line = mEditor->currentLine();
01443 col = mEditor->currentColumn();
01444 temp = i18n(" Line: %1 ").arg(line+1);
01445 statusBar()->changeItem(temp,1);
01446 temp = i18n(" Column: %1 ").arg(col+1);
01447 statusBar()->changeItem(temp,2);
01448 }
01449
01450
01451
01452 void KMComposeWin::setupEditor(void)
01453 {
01454
01455 mEditor->setModified(FALSE);
01456 QFontMetrics fm(mBodyFont);
01457 mEditor->setTabStopWidth(fm.width(QChar(' ')) * 8);
01458
01459
01460 if (mWordWrap)
01461 {
01462 mEditor->setWordWrap( QMultiLineEdit::FixedColumnWidth );
01463 mEditor->setWrapColumnOrWidth(mLineBreak);
01464 }
01465 else
01466 {
01467 mEditor->setWordWrap( QMultiLineEdit::NoWrap );
01468 }
01469
01470
01471 slotUpdateFont();
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494 updateCursorPosition();
01495 connect(mEditor,SIGNAL(CursorPositionChanged()),SLOT(updateCursorPosition()));
01496 connect( mEditor, SIGNAL( currentFontChanged( const QFont & ) ),
01497 this, SLOT( fontChanged( const QFont & ) ) );
01498 connect( mEditor, SIGNAL( currentAlignmentChanged( int ) ),
01499 this, SLOT( alignmentChanged( int ) ) );
01500
01501 }
01502
01503
01504
01505 static QString cleanedUpHeaderString( const QString & s )
01506 {
01507
01508 QString res( s );
01509 res.replace( '\r', "" );
01510 res.replace( '\n', " " );
01511 return res.stripWhiteSpace();
01512 }
01513
01514 static QString sanitizedSeparators( const QString& s )
01515 {
01516 const bool allowSemicolon = GlobalSettings::allowSemicolonAsAddressSeparator();
01517 return KPIM::splitEmailAddrList( s, allowSemicolon ).join( "," );
01518 }
01519
01520
01521 QString KMComposeWin::subject() const
01522 {
01523 return cleanedUpHeaderString( mEdtSubject->text() );
01524 }
01525
01526
01527 QString KMComposeWin::to() const
01528 {
01529 kdDebug() << "TO: " << kdBacktrace() << endl;
01530 return sanitizedSeparators( cleanedUpHeaderString( mEdtTo->text() ) );
01531 }
01532
01533
01534 QString KMComposeWin::cc() const
01535 {
01536 if ( mEdtCc->isHidden() )
01537 return QString::null;
01538 else
01539 return sanitizedSeparators( cleanedUpHeaderString( mEdtCc->text() ) );
01540 }
01541
01542
01543 QString KMComposeWin::bcc() const
01544 {
01545 if ( mEdtBcc->isHidden() )
01546 return QString::null;
01547 else
01548 return sanitizedSeparators( cleanedUpHeaderString( mEdtBcc->text() ) );
01549 }
01550
01551
01552 QString KMComposeWin::from() const
01553 {
01554 return cleanedUpHeaderString( mEdtFrom->text() );
01555 }
01556
01557
01558 QString KMComposeWin::replyTo() const
01559 {
01560 return cleanedUpHeaderString( mEdtReplyTo->text() );
01561 }
01562
01563
01564 void KMComposeWin::verifyWordWrapLengthIsAdequate(const QString &body)
01565 {
01566 int maxLineLength = 0;
01567 int curPos;
01568 int oldPos = 0;
01569 if (mEditor->QMultiLineEdit::wordWrap() == QMultiLineEdit::FixedColumnWidth) {
01570 for (curPos = 0; curPos < (int)body.length(); ++curPos)
01571 if (body[curPos] == '\n') {
01572 if ((curPos - oldPos) > maxLineLength)
01573 maxLineLength = curPos - oldPos;
01574 oldPos = curPos;
01575 }
01576 if ((curPos - oldPos) > maxLineLength)
01577 maxLineLength = curPos - oldPos;
01578 if (mEditor->wrapColumnOrWidth() < maxLineLength)
01579 mEditor->setWrapColumnOrWidth(maxLineLength);
01580 }
01581 }
01582
01583
01584 void KMComposeWin::decryptOrStripOffCleartextSignature( QCString& body )
01585 {
01586 QPtrList<Kpgp::Block> pgpBlocks;
01587 QStrList nonPgpBlocks;
01588 if( Kpgp::Module::prepareMessageForDecryption( body,
01589 pgpBlocks, nonPgpBlocks ) )
01590 {
01591
01592
01593 if( pgpBlocks.count() == 1 )
01594 {
01595 Kpgp::Block* block = pgpBlocks.first();
01596 if( ( block->type() == Kpgp::PgpMessageBlock ) ||
01597 ( block->type() == Kpgp::ClearsignedBlock ) )
01598 {
01599 if( block->type() == Kpgp::PgpMessageBlock )
01600
01601 block->decrypt();
01602 else
01603
01604 block->verify();
01605
01606 body = nonPgpBlocks.first()
01607 + block->text()
01608 + nonPgpBlocks.last();
01609 }
01610 }
01611 }
01612 }
01613
01614
01615 void KMComposeWin::setMsg(KMMessage* newMsg, bool mayAutoSign,
01616 bool allowDecryption, bool isModified)
01617 {
01618
01619 if(!newMsg)
01620 {
01621 kdDebug(5006) << "KMComposeWin::setMsg() : newMsg == 0!" << endl;
01622 return;
01623 }
01624 mMsg = newMsg;
01625
01626 mEdtTo->setText(mMsg->to());
01627 mEdtFrom->setText(mMsg->from());
01628 mEdtCc->setText(mMsg->cc());
01629 mEdtSubject->setText(mMsg->subject());
01630 mEdtReplyTo->setText(mMsg->replyTo());
01631 mEdtBcc->setText(mMsg->bcc());
01632
01633 if (!mBtnIdentity->isChecked() && !newMsg->headerField("X-KMail-Identity").isEmpty())
01634 mId = newMsg->headerField("X-KMail-Identity").stripWhiteSpace().toUInt();
01635
01636
01637
01638 if ( !mBtnIdentity->isChecked() ) {
01639 disconnect(mIdentity,SIGNAL(identityChanged(uint)),
01640 this, SLOT(slotIdentityChanged(uint)));
01641 }
01642 mIdentity->setCurrentIdentity( mId );
01643 if ( !mBtnIdentity->isChecked() ) {
01644 connect(mIdentity,SIGNAL(identityChanged(uint)),
01645 this, SLOT(slotIdentityChanged(uint)));
01646 }
01647 else {
01648
01649
01650
01651 slotIdentityChanged( mId );
01652 }
01653
01654 KPIM::IdentityManager * im = kmkernel->identityManager();
01655
01656 const KPIM::Identity & ident = im->identityForUoid( mIdentity->currentIdentity() );
01657
01658 mOldSigText = GlobalSettings::prependSignatures()? ident.signature().rawText() : ident.signatureText();
01659
01660
01661
01662 QString mdnAddr = newMsg->headerField("Disposition-Notification-To");
01663 mRequestMDNAction->setChecked( ( !mdnAddr.isEmpty() &&
01664 im->thatIsMe( mdnAddr ) ) || mAutoRequestMDN );
01665
01666
01667 mUrgentAction->setChecked( newMsg->isUrgent() );
01668
01669
01670 switch ( mMsg->encryptionState() ) {
01671 case KMMsgFullyEncrypted:
01672 case KMMsgPartiallyEncrypted:
01673 mLastEncryptActionState = true;
01674 break;
01675 case KMMsgNotEncrypted:
01676 mLastEncryptActionState = false;
01677 break;
01678 default:
01679 break;
01680 }
01681
01682
01683 switch ( mMsg->signatureState() ) {
01684 case KMMsgFullySigned:
01685 case KMMsgPartiallySigned:
01686 mLastSignActionState = true;
01687 break;
01688 case KMMsgNotSigned:
01689 mLastSignActionState = false;
01690 break;
01691 default:
01692 break;
01693 }
01694
01695
01696 if ( mMsg->headers().FindField( "X-KMail-SignatureActionEnabled" ) )
01697 mLastSignActionState = (mMsg->headerField( "X-KMail-SignatureActionEnabled" ) == "true");
01698 if ( mMsg->headers().FindField( "X-KMail-EncryptActionEnabled" ) )
01699 mLastEncryptActionState = (mMsg->headerField( "X-KMail-EncryptActionEnabled" ) == "true");
01700
01701 mLastIdentityHasSigningKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
01702 mLastIdentityHasEncryptionKey = !ident.pgpEncryptionKey().isEmpty() || !ident.smimeEncryptionKey().isEmpty();
01703
01704 if( !mMsg->headerField("X-KMail-CryptoFormat").isEmpty() ){
01705 const int format = mMsg->headerField("X-KMail-CryptoFormat").stripWhiteSpace().toInt();
01706 if( 0 <= format ){
01707 mCryptoModuleAction->setCurrentItem(
01708 format2cb( (Kleo::CryptoMessageFormat)format ) );
01709 slotSelectCryptoModule();
01710 }
01711 }
01712
01713 if ( Kleo::CryptoBackendFactory::instance()->openpgp() || Kleo::CryptoBackendFactory::instance()->smime() ) {
01714 const bool canOpenPGPSign = Kleo::CryptoBackendFactory::instance()->openpgp()
01715 && !ident.pgpSigningKey().isEmpty();
01716 const bool canSMIMESign = Kleo::CryptoBackendFactory::instance()->smime()
01717 && !ident.smimeSigningKey().isEmpty();
01718
01719 setEncryption( mLastEncryptActionState );
01720 setSigning( ( canOpenPGPSign || canSMIMESign ) && mLastSignActionState );
01721 }
01722
01723
01724
01725 mAttachMPK->setEnabled( Kleo::CryptoBackendFactory::instance()->openpgp() &&
01726 !ident.pgpEncryptionKey().isEmpty() );
01727
01728 QString transport = newMsg->headerField("X-KMail-Transport");
01729 if (!mBtnTransport->isChecked() && !transport.isEmpty())
01730 {
01731 for (int i = 0; i < mTransport->count(); i++)
01732 if (mTransport->text(i) == transport)
01733 mTransport->setCurrentItem(i);
01734 mTransport->setEditText( transport );
01735 }
01736
01737 if (!mBtnFcc->isChecked())
01738 {
01739 if (!mMsg->fcc().isEmpty())
01740 setFcc(mMsg->fcc());
01741 else
01742 setFcc(ident.fcc());
01743 }
01744
01745 mDictionaryCombo->setCurrentByDictionary( ident.dictionary() );
01746
01747 partNode * root = partNode::fromMessage( mMsg );
01748
01749 KMail::ObjectTreeParser otp;
01750 otp.parseObjectTree( root );
01751
01752 KMail::AttachmentCollector ac;
01753 ac.setDiveIntoEncryptions( true );
01754 ac.setDiveIntoSignatures( true );
01755 ac.setDiveIntoMessages( false );
01756
01757 ac.collectAttachmentsFrom( root );
01758
01759 for ( std::vector<partNode*>::const_iterator it = ac.attachments().begin() ; it != ac.attachments().end() ; ++it )
01760 addAttach( new KMMessagePart( (*it)->msgPart() ) );
01761
01762 mEditor->setText( otp.textualContent() );
01763 mCharset = otp.textualContentCharset();
01764 if ( mCharset.isEmpty() )
01765 mCharset = mMsg->charset();
01766 if ( mCharset.isEmpty() )
01767 mCharset = mDefCharset;
01768 setCharset( mCharset );
01769
01770 if ( partNode * n = root->findType( DwMime::kTypeText, DwMime::kSubtypeHtml ) )
01771 if ( partNode * p = n->parentNode() )
01772 if ( p->hasType( DwMime::kTypeMultipart ) &&
01773 p->hasSubType( DwMime::kSubtypeAlternative ) )
01774 if ( mMsg->headerField( "X-KMail-Markup" ) == "true" )
01775 toggleMarkup( true );
01776
01777
01778 if ( mMsg->numBodyParts() == 0 && otp.textualContent().isEmpty() ) {
01779 mCharset=mMsg->charset();
01780 if ( mCharset.isEmpty() || mCharset == "default" )
01781 mCharset = mDefCharset;
01782
01783 QCString bodyDecoded = mMsg->bodyDecoded();
01784
01785 if( allowDecryption )
01786 decryptOrStripOffCleartextSignature( bodyDecoded );
01787
01788 const QTextCodec *codec = KMMsgBase::codecForName(mCharset);
01789 if (codec) {
01790 mEditor->setText(codec->toUnicode(bodyDecoded));
01791 } else
01792 mEditor->setText(QString::fromLocal8Bit(bodyDecoded));
01793 }
01794
01795
01796 #ifdef BROKEN_FOR_OPAQUE_SIGNED_OR_ENCRYPTED_MAILS
01797 const int num = mMsg->numBodyParts();
01798 kdDebug(5006) << "KMComposeWin::setMsg() mMsg->numBodyParts="
01799 << mMsg->numBodyParts() << endl;
01800
01801 if ( num > 0 ) {
01802 KMMessagePart bodyPart;
01803 int firstAttachment = 0;
01804
01805 mMsg->bodyPart(1, &bodyPart);
01806 if ( bodyPart.typeStr().lower() == "text" &&
01807 bodyPart.subtypeStr().lower() == "html" ) {
01808
01809 partNode *root = partNode::fromMessage( mMsg );
01810 partNode *node = root->findType( DwMime::kTypeText,
01811 DwMime::kSubtypeHtml );
01812 if ( node && node->parentNode() &&
01813 node->parentNode()->hasType( DwMime::kTypeMultipart ) &&
01814 node->parentNode()->hasSubType( DwMime::kSubtypeAlternative ) ) {
01815
01816 kdDebug(5006) << "KMComposeWin::setMsg() : text/html found" << endl;
01817 firstAttachment = 2;
01818 if ( mMsg->headerField( "X-KMail-Markup" ) == "true" )
01819 toggleMarkup( true );
01820 }
01821 delete root; root = 0;
01822 }
01823 if ( firstAttachment == 0 ) {
01824 mMsg->bodyPart(0, &bodyPart);
01825 if ( bodyPart.typeStr().lower() == "text" ) {
01826
01827 kdDebug(5006) << "KMComposeWin::setMsg() : text/* found" << endl;
01828 firstAttachment = 1;
01829 }
01830 }
01831
01832 if ( firstAttachment != 0 )
01833 {
01834 mCharset = bodyPart.charset();
01835 if ( mCharset.isEmpty() || mCharset == "default" )
01836 mCharset = mDefCharset;
01837
01838 QCString bodyDecoded = bodyPart.bodyDecoded();
01839
01840 if( allowDecryption )
01841 decryptOrStripOffCleartextSignature( bodyDecoded );
01842
01843
01844
01845
01846
01847
01848
01849 const QTextCodec *codec = KMMsgBase::codecForName(mCharset);
01850 if (codec)
01851 mEditor->setText(codec->toUnicode(bodyDecoded));
01852 else
01853 mEditor->setText(QString::fromLocal8Bit(bodyDecoded));
01854
01855 } else mEditor->setText("");
01856 for( int i = firstAttachment; i < num; ++i )
01857 {
01858 KMMessagePart *msgPart = new KMMessagePart;
01859 mMsg->bodyPart(i, msgPart);
01860 QCString mimeType = msgPart->typeStr().lower() + '/'
01861 + msgPart->subtypeStr().lower();
01862
01863
01864 if( mimeType != "application/pgp-signature" ) {
01865 addAttach(msgPart);
01866 }
01867 }
01868 } else{
01869 mCharset=mMsg->charset();
01870 if ( mCharset.isEmpty() || mCharset == "default" )
01871 mCharset = mDefCharset;
01872
01873 QCString bodyDecoded = mMsg->bodyDecoded();
01874
01875 if( allowDecryption )
01876 decryptOrStripOffCleartextSignature( bodyDecoded );
01877
01878 const QTextCodec *codec = KMMsgBase::codecForName(mCharset);
01879 if (codec) {
01880 mEditor->setText(codec->toUnicode(bodyDecoded));
01881 } else
01882 mEditor->setText(QString::fromLocal8Bit(bodyDecoded));
01883 }
01884
01885 setCharset(mCharset);
01886 #endif // BROKEN_FOR_OPAQUE_SIGNED_OR_ENCRYPTED_MAILS
01887
01888 if( mAutoSign && mayAutoSign ) {
01889
01890
01891
01892
01893
01894
01895 if ( GlobalSettings::prependSignatures() ) {
01896 QTimer::singleShot( 0, this, SLOT(slotPrependSignature()) );
01897 } else {
01898 QTimer::singleShot( 0, this, SLOT(slotAppendSignature()) );
01899 }
01900
01901 }
01902 mEditor->setModified(isModified);
01903 }
01904
01905
01906
01907 void KMComposeWin::setFcc( const QString &idString )
01908 {
01909
01910 KMFolder *folder = kmkernel->findFolderById( idString );
01911 if ( folder )
01912 mFcc->setFolder( idString );
01913 else
01914 mFcc->setFolder( kmkernel->sentFolder() );
01915 }
01916
01917
01918
01919 bool KMComposeWin::queryClose ()
01920 {
01921 if ( !mEditor->checkExternalEditorFinished() )
01922 return false;
01923 if (kmkernel->shuttingDown() || kapp->sessionSaving())
01924 return true;
01925
01926 if(mEditor->isModified() || mEdtFrom->edited() || mEdtReplyTo->edited() ||
01927 mEdtTo->edited() || mEdtCc->edited() || mEdtBcc->edited() ||
01928 mEdtSubject->edited() || mAtmModified ||
01929 (mTransport->lineEdit() && mTransport->lineEdit()->edited()))
01930 {
01931 const int rc = KMessageBox::warningYesNoCancel(this,
01932 i18n("Do you want to save the message for later or discard it?"),
01933 i18n("Close Composer"),
01934 i18n("&Save as Draft"),
01935 KStdGuiItem::discard() );
01936 if (rc == KMessageBox::Cancel)
01937 return false;
01938 else if (rc == KMessageBox::Yes) {
01939
01940 slotSaveDraft();
01941 return false;
01942 }
01943 }
01944 cleanupAutoSave();
01945 return true;
01946 }
01947
01948
01949 bool KMComposeWin::userForgotAttachment()
01950 {
01951 KConfigGroup composer( KMKernel::config(), "Composer" );
01952 bool checkForForgottenAttachments =
01953 composer.readBoolEntry( "showForgottenAttachmentWarning", true );
01954
01955 if ( !checkForForgottenAttachments || ( mAtmList.count() > 0 ) )
01956 return false;
01957
01958
01959 QStringList attachWordsList =
01960 composer.readListEntry( "attachment-keywords" );
01961
01962 if ( attachWordsList.isEmpty() ) {
01963
01964 attachWordsList << QString::fromLatin1("attachment")
01965 << QString::fromLatin1("attached");
01966 if ( QString::fromLatin1("attachment") != i18n("attachment") )
01967 attachWordsList << i18n("attachment");
01968 if ( QString::fromLatin1("attached") != i18n("attached") )
01969 attachWordsList << i18n("attached");
01970 }
01971
01972 QRegExp rx ( QString::fromLatin1("\\b") +
01973 attachWordsList.join("\\b|\\b") +
01974 QString::fromLatin1("\\b") );
01975 rx.setCaseSensitive( false );
01976
01977 bool gotMatch = false;
01978
01979
01980
01981 QString subj = subject();
01982 gotMatch = ( KMMessage::stripOffPrefixes( subj ) == subj )
01983 && ( rx.search( subj ) >= 0 );
01984
01985 if ( !gotMatch ) {
01986
01987
01988 QRegExp quotationRx ("^([ \\t]*([|>:}#]|[A-Za-z]+>))+");
01989 for ( int i = 0; i < mEditor->numLines(); ++i ) {
01990 QString line = mEditor->textLine( i );
01991 gotMatch = ( quotationRx.search( line ) < 0 )
01992 && ( rx.search( line ) >= 0 );
01993 if ( gotMatch )
01994 break;
01995 }
01996 }
01997
01998 if ( !gotMatch )
01999 return false;
02000
02001 int rc = KMessageBox::warningYesNoCancel( this,
02002 i18n("The message you have composed seems to refer to an "
02003 "attached file but you have not attached anything.\n"
02004 "Do you want to attach a file to your message?"),
02005 i18n("File Attachment Reminder"),
02006 i18n("&Attach File..."),
02007 i18n("&Send as Is") );
02008 if ( rc == KMessageBox::Cancel )
02009 return true;
02010 if ( rc == KMessageBox::Yes ) {
02011 slotAttachFile();
02012
02013 return true;
02014 }
02015 return false;
02016 }
02017
02018
02019 void KMComposeWin::applyChanges( bool dontSignNorEncrypt, bool dontDisable )
02020 {
02021 #ifdef DEBUG
02022 kdDebug(5006) << "entering KMComposeWin::applyChanges" << endl;
02023 #endif
02024
02025 if(!mMsg) {
02026 kdDebug(5006) << "KMComposeWin::applyChanges() : mMsg == 0!\n" << endl;
02027 emit applyChangesDone( false );
02028 return;
02029 }
02030
02031 if( mComposer ) {
02032 kdDebug(5006) << "KMComposeWin::applyChanges() : applyChanges called twice"
02033 << endl;
02034 return;
02035 }
02036
02037
02038 mComposer = new MessageComposer( this );
02039 connect( mComposer, SIGNAL( done( bool ) ),
02040 this, SLOT( slotComposerDone( bool ) ) );
02041
02042
02043 if ( !dontDisable )
02044 setEnabled( false );
02045
02046 mComposer->setDisableBreaking( mDisableBreaking );
02047 mComposer->applyChanges( dontSignNorEncrypt );
02048 }
02049
02050 void KMComposeWin::slotComposerDone( bool rc )
02051 {
02052 deleteAll( mComposedMessages );
02053 mComposedMessages = mComposer->composedMessageList();
02054 emit applyChangesDone( rc );
02055 delete mComposer;
02056 mComposer = 0;
02057 }
02058
02059 const KPIM::Identity & KMComposeWin::identity() const {
02060 return kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() );
02061 }
02062
02063 Kleo::CryptoMessageFormat KMComposeWin::cryptoMessageFormat() const {
02064 if ( !mCryptoModuleAction )
02065 return Kleo::AutoFormat;
02066 return cb2format( mCryptoModuleAction->currentItem() );
02067 }
02068
02069 bool KMComposeWin::encryptToSelf() const {
02070 return !Kpgp::Module::getKpgp() || Kpgp::Module::getKpgp()->encryptToSelf();
02071 }
02072
02073 bool KMComposeWin::queryExit ()
02074 {
02075 return true;
02076 }
02077
02078
02079 void KMComposeWin::addAttach(const KURL aUrl)
02080 {
02081 if ( !aUrl.isValid() ) {
02082 KMessageBox::sorry( this, i18n( "<qt><p>KMail could not recognize the location of the attachment (%1);</p>"
02083 "<p>you have to specify the full path if you wish to attach a file.</p></qt>" )
02084 .arg( aUrl.prettyURL() ) );
02085 return;
02086 }
02087 KIO::TransferJob *job = KIO::get(aUrl);
02088 KIO::Scheduler::scheduleJob( job );
02089 atmLoadData ld;
02090 ld.url = aUrl;
02091 ld.data = QByteArray();
02092 ld.insert = false;
02093 if( !aUrl.fileEncoding().isEmpty() )
02094 ld.encoding = aUrl.fileEncoding().latin1();
02095
02096 mMapAtmLoadData.insert(job, ld);
02097 connect(job, SIGNAL(result(KIO::Job *)),
02098 this, SLOT(slotAttachFileResult(KIO::Job *)));
02099 connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)),
02100 this, SLOT(slotAttachFileData(KIO::Job *, const QByteArray &)));
02101 }
02102
02103
02104
02105 void KMComposeWin::addAttach(const KMMessagePart* msgPart)
02106 {
02107 mAtmList.append(msgPart);
02108
02109
02110 if (mAtmList.count()==1)
02111 {
02112 mGrid->setRowStretch(mNumHeaders+1, 50);
02113 mAtmListView->setMinimumSize(100, 80);
02114 mAtmListView->setMaximumHeight( 100 );
02115 mAtmListView->show();
02116 resize(size());
02117 }
02118
02119
02120 KMAtmListViewItem *lvi = new KMAtmListViewItem( mAtmListView );
02121 msgPartToItem(msgPart, lvi);
02122 mAtmItemList.append(lvi);
02123
02124 slotUpdateAttachActions();
02125 }
02126
02127
02128
02129 void KMComposeWin::slotUpdateAttachActions()
02130 {
02131 int selectedCount = 0;
02132 for ( QPtrListIterator<QListViewItem> it(mAtmItemList); *it; ++it ) {
02133 if ( (*it)->isSelected() ) {
02134 ++selectedCount;
02135 }
02136 }
02137
02138 mAttachRemoveAction->setEnabled( selectedCount >= 1 );
02139 mAttachSaveAction->setEnabled( selectedCount == 1 );
02140 mAttachPropertiesAction->setEnabled( selectedCount == 1 );
02141 }
02142
02143
02144
02145
02146 QString KMComposeWin::prettyMimeType( const QString& type )
02147 {
02148 QString t = type.lower();
02149 KServiceType::Ptr st = KServiceType::serviceType( t );
02150 return st ? st->comment() : t;
02151 }
02152
02153 void KMComposeWin::msgPartToItem(const KMMessagePart* msgPart,
02154 KMAtmListViewItem *lvi)
02155 {
02156 assert(msgPart != 0);
02157
02158 if (!msgPart->fileName().isEmpty())
02159 lvi->setText(0, msgPart->fileName());
02160 else
02161 lvi->setText(0, msgPart->name());
02162 lvi->setText(1, KIO::convertSize( msgPart->decodedSize()));
02163 lvi->setText(2, msgPart->contentTransferEncodingStr());
02164 lvi->setText(3, prettyMimeType(msgPart->typeStr() + "/" + msgPart->subtypeStr()));
02165 if( canSignEncryptAttachments() ) {
02166 lvi->enableCryptoCBs( true );
02167 lvi->setEncrypt( mEncryptAction->isChecked() );
02168 lvi->setSign( mSignAction->isChecked() );
02169 } else {
02170 lvi->enableCryptoCBs( false );
02171 }
02172 }
02173
02174
02175
02176 void KMComposeWin::removeAttach(const QString &aUrl)
02177 {
02178 int idx;
02179 KMMessagePart* msgPart;
02180 for(idx=0,msgPart=mAtmList.first(); msgPart;
02181 msgPart=mAtmList.next(),idx++) {
02182 if (msgPart->name() == aUrl) {
02183 removeAttach(idx);
02184 return;
02185 }
02186 }
02187 }
02188
02189
02190
02191 void KMComposeWin::removeAttach(int idx)
02192 {
02193 mAtmModified = TRUE;
02194 mAtmList.remove(idx);
02195 delete mAtmItemList.take(idx);
02196
02197 if( mAtmList.isEmpty() )
02198 {
02199 mAtmListView->hide();
02200 mGrid->setRowStretch(mNumHeaders+1, 0);
02201 mAtmListView->setMinimumSize(0, 0);
02202 resize(size());
02203 }
02204 }
02205
02206
02207
02208 bool KMComposeWin::encryptFlagOfAttachment(int idx)
02209 {
02210 return (int)(mAtmItemList.count()) > idx
02211 ? ((KMAtmListViewItem*)(mAtmItemList.at( idx )))->isEncrypt()
02212 : false;
02213 }
02214
02215
02216
02217 bool KMComposeWin::signFlagOfAttachment(int idx)
02218 {
02219 return (int)(mAtmItemList.count()) > idx
02220 ? ((KMAtmListViewItem*)(mAtmItemList.at( idx )))->isSign()
02221 : false;
02222 }
02223
02224
02225
02226 void KMComposeWin::addrBookSelInto()
02227 {
02228 AddressesDialog dlg( this );
02229 QString txt;
02230 QStringList lst;
02231
02232 txt = to();
02233 if ( !txt.isEmpty() ) {
02234 lst = KPIM::splitEmailAddrList( txt );
02235 dlg.setSelectedTo( lst );
02236 }
02237
02238 txt = cc();
02239 if ( !txt.isEmpty() ) {
02240 lst = KPIM::splitEmailAddrList( txt );
02241 dlg.setSelectedCC( lst );
02242 }
02243
02244 txt = bcc();
02245 if ( !txt.isEmpty() ) {
02246 lst = KPIM::splitEmailAddrList( txt );
02247 dlg.setSelectedBCC( lst );
02248 }
02249
02250 dlg.setRecentAddresses( RecentAddresses::self( KMKernel::config() )->kabcAddresses() );
02251
02252 if (dlg.exec()==QDialog::Rejected) return;
02253
02254 mEdtTo->setText( dlg.to().join(", ") );
02255 mEdtTo->setEdited( true );
02256
02257 mEdtCc->setText( dlg.cc().join(", ") );
02258 mEdtCc->setEdited( true );
02259
02260 mEdtBcc->setText( dlg.bcc().join(", ") );
02261 mEdtBcc->setEdited( true );
02262 }
02263
02264
02265
02266 void KMComposeWin::setCharset(const QCString& aCharset, bool forceDefault)
02267 {
02268 if ((forceDefault && mForceReplyCharset) || aCharset.isEmpty())
02269 mCharset = mDefCharset;
02270 else
02271 mCharset = aCharset.lower();
02272
02273 if ( mCharset.isEmpty() || mCharset == "default" )
02274 mCharset = mDefCharset;
02275
02276 if (mAutoCharset)
02277 {
02278 mEncodingAction->setCurrentItem( 0 );
02279 return;
02280 }
02281
02282 QStringList encodings = mEncodingAction->items();
02283 int i = 0;
02284 bool charsetFound = FALSE;
02285 for ( QStringList::Iterator it = encodings.begin(); it != encodings.end();
02286 ++it, i++ )
02287 {
02288 if (i > 0 && ((mCharset == "us-ascii" && i == 1) ||
02289 (i != 1 && KGlobal::charsets()->codecForName(
02290 KGlobal::charsets()->encodingForName(*it))
02291 == KGlobal::charsets()->codecForName(mCharset))))
02292 {
02293 mEncodingAction->setCurrentItem( i );
02294 slotSetCharset();
02295 charsetFound = TRUE;
02296 break;
02297 }
02298 }
02299 if (!aCharset.isEmpty() && !charsetFound) setCharset("", TRUE);
02300 }
02301
02302
02303
02304 void KMComposeWin::slotAddrBook()
02305 {
02306 KAddrBookExternal::openAddressBook(this);
02307 }
02308
02309
02310
02311 void KMComposeWin::slotAddrBookFrom()
02312 {
02313 addrBookSelInto();
02314 }
02315
02316
02317
02318 void KMComposeWin::slotAddrBookReplyTo()
02319 {
02320 addrBookSelInto();
02321 }
02322
02323
02324
02325 void KMComposeWin::slotAddrBookTo()
02326 {
02327 addrBookSelInto();
02328 }
02329
02330
02331 void KMComposeWin::slotAttachFile()
02332 {
02333
02334
02335
02336
02337 KFileDialog fdlg(QString::null, QString::null, this, 0, TRUE);
02338 fdlg.setOperationMode( KFileDialog::Other );
02339 fdlg.setCaption(i18n("Attach File"));
02340 fdlg.okButton()->setGuiItem(KGuiItem(i18n("&Attach"),"fileopen"));
02341 fdlg.setMode(KFile::Files);
02342 fdlg.exec();
02343 KURL::List files = fdlg.selectedURLs();
02344
02345 for (KURL::List::Iterator it = files.begin(); it != files.end(); ++it)
02346 addAttach(*it);
02347 }
02348
02349
02350
02351 void KMComposeWin::slotAttachFileData(KIO::Job *job, const QByteArray &data)
02352 {
02353 QMap<KIO::Job*, atmLoadData>::Iterator it = mMapAtmLoadData.find(job);
02354 assert(it != mMapAtmLoadData.end());
02355 QBuffer buff((*it).data);
02356 buff.open(IO_WriteOnly | IO_Append);
02357 buff.writeBlock(data.data(), data.size());
02358 buff.close();
02359 }
02360
02361
02362
02363 void KMComposeWin::slotAttachFileResult(KIO::Job *job)
02364 {
02365 QMap<KIO::Job*, atmLoadData>::Iterator it = mMapAtmLoadData.find(job);
02366 assert(it != mMapAtmLoadData.end());
02367 if (job->error())
02368 {
02369 mMapAtmLoadData.remove(it);
02370 job->showErrorDialog();
02371 return;
02372 }
02373 if ((*it).insert)
02374 {
02375 (*it).data.resize((*it).data.size() + 1);
02376 (*it).data[(*it).data.size() - 1] = '\0';
02377 if ( const QTextCodec * codec = KGlobal::charsets()->codecForName((*it).encoding) )
02378 mEditor->insert( codec->toUnicode( (*it).data ) );
02379 else
02380 mEditor->insert( QString::fromLocal8Bit( (*it).data ) );
02381 mMapAtmLoadData.remove(it);
02382 return;
02383 }
02384 const QCString partCharset = (*it).url.fileEncoding().isEmpty()
02385 ? mCharset
02386 : QCString((*it).url.fileEncoding().latin1());
02387
02388 KMMessagePart* msgPart;
02389
02390 KCursorSaver busy(KBusyPtr::busy());
02391 QString name( (*it).url.fileName() );
02392
02393 QString mimeType = static_cast<KIO::MimetypeJob*>(job)->mimetype();
02394
02395 if ( name.isEmpty() ) {
02396
02397
02398 if( mimeType == "text/html" )
02399 name = "index.html";
02400 else {
02401
02402 QStringList patterns( KMimeType::mimeType( mimeType )->patterns() );
02403 QString ext;
02404 if( !patterns.isEmpty() ) {
02405 ext = patterns[0];
02406 int i = ext.findRev( '.' );
02407 if( i == -1 )
02408 ext.prepend( '.' );
02409 else if( i > 0 )
02410 ext = ext.mid( i );
02411 }
02412 name = QString("unknown") += ext;
02413 }
02414 }
02415
02416 name.truncate( 256 );
02417
02418 QCString encoding = KMMsgBase::autoDetectCharset(partCharset,
02419 KMMessage::preferredCharsets(), name);
02420 if (encoding.isEmpty()) encoding = "utf-8";
02421
02422 QCString encName;
02423 if ( mOutlookCompatible )
02424 encName = KMMsgBase::encodeRFC2047String( name, encoding );
02425 else
02426 encName = KMMsgBase::encodeRFC2231String( name, encoding );
02427 bool RFC2231encoded = false;
02428 if ( !mOutlookCompatible )
02429 RFC2231encoded = name != QString( encName );
02430
02431
02432 msgPart = new KMMessagePart;
02433 msgPart->setName(name);
02434 QValueList<int> allowedCTEs;
02435 if ( mimeType == "message/rfc822" ) {
02436 msgPart->setMessageBody( (*it).data );
02437 allowedCTEs << DwMime::kCte7bit;
02438 allowedCTEs << DwMime::kCte8bit;
02439 } else {
02440 msgPart->setBodyAndGuessCte((*it).data, allowedCTEs,
02441 !kmkernel->msgSender()->sendQuotedPrintable());
02442 kdDebug(5006) << "autodetected cte: " << msgPart->cteStr() << endl;
02443 }
02444 int slash = mimeType.find( '/' );
02445 if( slash == -1 )
02446 slash = mimeType.length();
02447 msgPart->setTypeStr( mimeType.left( slash ).latin1() );
02448 msgPart->setSubtypeStr( mimeType.mid( slash + 1 ).latin1() );
02449 msgPart->setContentDisposition(QCString("attachment;\n\tfilename")
02450 + ( RFC2231encoded ? "*=" + encName : "=\"" + encName + '"' ));
02451
02452 mMapAtmLoadData.remove(it);
02453
02454 msgPart->setCharset(partCharset);
02455
02456
02457 KConfigGroup composer(KMKernel::config(), "Composer");
02458 if (!composer.hasKey("showMessagePartDialogOnAttach"))
02459
02460 composer.writeEntry("showMessagePartDialogOnAttach", false);
02461 if (composer.readBoolEntry("showMessagePartDialogOnAttach", false)) {
02462 KMMsgPartDialogCompat dlg;
02463 int encodings = 0;
02464 for ( QValueListConstIterator<int> it = allowedCTEs.begin() ;
02465 it != allowedCTEs.end() ; ++it )
02466 switch ( *it ) {
02467 case DwMime::kCteBase64: encodings |= KMMsgPartDialog::Base64; break;
02468 case DwMime::kCteQp: encodings |= KMMsgPartDialog::QuotedPrintable; break;
02469 case DwMime::kCte7bit: encodings |= KMMsgPartDialog::SevenBit; break;
02470 case DwMime::kCte8bit: encodings |= KMMsgPartDialog::EightBit; break;
02471 default: ;
02472 }
02473 dlg.setShownEncodings( encodings );
02474 dlg.setMsgPart(msgPart);
02475 if (!dlg.exec()) {
02476 delete msgPart;
02477 msgPart = 0;
02478 return;
02479 }
02480 }
02481 mAtmModified = TRUE;
02482 if (msgPart->typeStr().lower() != "text") msgPart->setCharset(QCString());
02483
02484
02485 addAttach(msgPart);
02486 }
02487
02488
02489
02490 void KMComposeWin::slotInsertFile()
02491 {
02492 KFileDialog fdlg(QString::null, QString::null, this, 0, TRUE);
02493 fdlg.setOperationMode( KFileDialog::Opening );
02494 fdlg.okButton()->setText(i18n("&Insert"));
02495 fdlg.setCaption(i18n("Insert File"));
02496 fdlg.toolBar()->insertCombo(KMMsgBase::supportedEncodings(FALSE), 4711,
02497 false, 0, 0, 0);
02498 KComboBox *combo = fdlg.toolBar()->getCombo(4711);
02499 for (int i = 0; i < combo->count(); i++)
02500 if (KGlobal::charsets()->codecForName(KGlobal::charsets()->
02501 encodingForName(combo->text(i)))
02502 == QTextCodec::codecForLocale()) combo->setCurrentItem(i);
02503 if (!fdlg.exec()) return;
02504
02505 KURL u = fdlg.selectedURL();
02506
02507 if (u.fileName().isEmpty()) return;
02508
02509 KIO::Job *job = KIO::get(u);
02510 atmLoadData ld;
02511 ld.url = u;
02512 ld.data = QByteArray();
02513 ld.insert = true;
02514 ld.encoding = KGlobal::charsets()->encodingForName(
02515 combo->currentText()).latin1();
02516 mMapAtmLoadData.insert(job, ld);
02517 connect(job, SIGNAL(result(KIO::Job *)),
02518 this, SLOT(slotAttachFileResult(KIO::Job *)));
02519 connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)),
02520 this, SLOT(slotAttachFileData(KIO::Job *, const QByteArray &)));
02521 }
02522
02523
02524
02525 void KMComposeWin::slotSetCharset()
02526 {
02527 if (mEncodingAction->currentItem() == 0)
02528 {
02529 mAutoCharset = true;
02530 return;
02531 }
02532 mAutoCharset = false;
02533
02534 mCharset = KGlobal::charsets()->encodingForName( mEncodingAction->
02535 currentText() ).latin1();
02536 }
02537
02538
02539
02540 void KMComposeWin::slotSelectCryptoModule()
02541 {
02542 if( canSignEncryptAttachments() ) {
02543
02544 if( 0 == mAtmListView->columnWidth( mAtmColEncrypt ) ) {
02545
02546
02547 if( !mAtmList.isEmpty() ) {
02548 for( KMAtmListViewItem* lvi = (KMAtmListViewItem*)mAtmItemList.first();
02549 lvi;
02550 lvi = (KMAtmListViewItem*)mAtmItemList.next() ) {
02551 lvi->setSign( mSignAction->isChecked() );
02552 lvi->setEncrypt( mEncryptAction->isChecked() );
02553 }
02554 }
02555 int totalWidth = 0;
02556
02557 for( int col=0; col < mAtmColEncrypt; col++ )
02558 totalWidth += mAtmListView->columnWidth( col );
02559 int reducedTotalWidth = totalWidth - mAtmEncryptColWidth
02560 - mAtmSignColWidth;
02561
02562
02563 int usedWidth = 0;
02564 for( int col=0; col < mAtmColEncrypt-1; col++ ) {
02565 int newWidth = mAtmListView->columnWidth( col ) * reducedTotalWidth
02566 / totalWidth;
02567 mAtmListView->setColumnWidth( col, newWidth );
02568 usedWidth += newWidth;
02569 }
02570
02571
02572
02573 mAtmListView->setColumnWidth( mAtmColEncrypt-1,
02574 reducedTotalWidth - usedWidth );
02575 mAtmListView->setColumnWidth( mAtmColEncrypt, mAtmEncryptColWidth );
02576 mAtmListView->setColumnWidth( mAtmColSign, mAtmSignColWidth );
02577 for( KMAtmListViewItem* lvi = (KMAtmListViewItem*)mAtmItemList.first();
02578 lvi;
02579 lvi = (KMAtmListViewItem*)mAtmItemList.next() ) {
02580 lvi->enableCryptoCBs( true );
02581 }
02582 }
02583 } else {
02584
02585 if( 0 != mAtmListView->columnWidth( mAtmColEncrypt ) ) {
02586 mAtmEncryptColWidth = mAtmListView->columnWidth( mAtmColEncrypt );
02587 mAtmSignColWidth = mAtmListView->columnWidth( mAtmColSign );
02588 int totalWidth = 0;
02589
02590 for( int col=0; col < mAtmListView->columns(); col++ )
02591 totalWidth += mAtmListView->columnWidth( col );
02592 int reducedTotalWidth = totalWidth - mAtmEncryptColWidth
02593 - mAtmSignColWidth;
02594
02595
02596 int usedWidth = 0;
02597 for( int col=0; col < mAtmColEncrypt-1; col++ ) {
02598 int newWidth = mAtmListView->columnWidth( col ) * totalWidth
02599 / reducedTotalWidth;
02600 mAtmListView->setColumnWidth( col, newWidth );
02601 usedWidth += newWidth;
02602 }
02603
02604
02605
02606 mAtmListView->setColumnWidth( mAtmColEncrypt-1, totalWidth - usedWidth );
02607 mAtmListView->setColumnWidth( mAtmColEncrypt, 0 );
02608 mAtmListView->setColumnWidth( mAtmColSign, 0 );
02609 for( KMAtmListViewItem* lvi = (KMAtmListViewItem*)mAtmItemList.first();
02610 lvi;
02611 lvi = (KMAtmListViewItem*)mAtmItemList.next() ) {
02612 lvi->enableCryptoCBs( false );
02613 }
02614 }
02615 }
02616 }
02617
02618 static void showExportError( QWidget * w, const GpgME::Error & err ) {
02619 assert( err );
02620 const QString msg = i18n("<qt><p>An error occurred while trying to export "
02621 "the key from the backend:</p>"
02622 "<p><b>%1</b></p></qt>")
02623 .arg( QString::fromLocal8Bit( err.asString() ) );
02624 KMessageBox::error( w, msg, i18n("Key Export Failed") );
02625 }
02626
02627
02628
02629 void KMComposeWin::slotInsertMyPublicKey()
02630 {
02631
02632 mFingerprint =
02633 kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() ).pgpEncryptionKey();
02634 if ( !mFingerprint.isEmpty() )
02635 startPublicKeyExport();
02636 }
02637
02638 void KMComposeWin::startPublicKeyExport() {
02639 if ( mFingerprint.isEmpty() )
02640 return;
02641 Kleo::ExportJob * job = Kleo::CryptoBackendFactory::instance()->openpgp()->publicKeyExportJob( true );
02642 assert( job );
02643
02644 connect( job, SIGNAL(result(const GpgME::Error&,const QByteArray&)),
02645 this, SLOT(slotPublicKeyExportResult(const GpgME::Error&,const QByteArray&)) );
02646
02647 const GpgME::Error err = job->start( mFingerprint );
02648 if ( err )
02649 showExportError( this, err );
02650 else
02651 (void)new Kleo::ProgressDialog( job, i18n("Exporting key..."), this );
02652 }
02653
02654 void KMComposeWin::slotPublicKeyExportResult( const GpgME::Error & err, const QByteArray & keydata ) {
02655 if ( err ) {
02656 showExportError( this, err );
02657 return;
02658 }
02659
02660
02661 KMMessagePart * msgPart = new KMMessagePart();
02662 msgPart->setName( i18n("OpenPGP key 0x%1").arg( mFingerprint ) );
02663 msgPart->setTypeStr("application");
02664 msgPart->setSubtypeStr("pgp-keys");
02665 QValueList<int> dummy;
02666 msgPart->setBodyAndGuessCte(keydata, dummy, false);
02667 msgPart->setContentDisposition( "attachment;\n\tfilename=0x" + QCString( mFingerprint.latin1() ) + ".asc" );
02668
02669
02670 addAttach(msgPart);
02671 rethinkFields();
02672 }
02673
02674
02675 void KMComposeWin::slotInsertPublicKey()
02676 {
02677 Kleo::KeySelectionDialog dlg( i18n("Attach Public OpenPGP Key"),
02678 i18n("Select the public key which should "
02679 "be attached."),
02680 std::vector<GpgME::Key>(),
02681 Kleo::KeySelectionDialog::PublicKeys|Kleo::KeySelectionDialog::OpenPGPKeys,
02682 false ,
02683 false ,
02684 this, "attach public key selection dialog" );
02685 if ( dlg.exec() != QDialog::Accepted )
02686 return;
02687
02688 mFingerprint = dlg.fingerprint();
02689 startPublicKeyExport();
02690 }
02691
02692
02693
02694 void KMComposeWin::slotAttachPopupMenu(QListViewItem *, const QPoint &, int)
02695 {
02696 if (!mAttachMenu)
02697 {
02698 mAttachMenu = new QPopupMenu(this);
02699
02700 mOpenId = mAttachMenu->insertItem(SmallIcon("fileopen"), i18n("to open", "Open"), this,
02701 SLOT(slotAttachOpen()));
02702 mOpenWithId = mAttachMenu->insertItem(i18n("to open with", "Open with..."), this,
02703 SLOT(slotAttachOpenWith()));
02704 mViewId = mAttachMenu->insertItem(i18n("to view", "View"), this,
02705 SLOT(slotAttachView()));
02706 mRemoveId = mAttachMenu->insertItem(i18n("Remove"), this, SLOT(slotAttachRemove()));
02707 mSaveAsId = mAttachMenu->insertItem( SmallIcon("filesaveas"), i18n("Save As..."), this,
02708 SLOT( slotAttachSave() ) );
02709 mPropertiesId = mAttachMenu->insertItem( i18n("Properties"), this,
02710 SLOT( slotAttachProperties() ) );
02711 mAttachMenu->insertSeparator();
02712 mAttachMenu->insertItem(i18n("Add Attachment..."), this, SLOT(slotAttachFile()));
02713 }
02714
02715 int selectedCount = 0;
02716 for ( QPtrListIterator<QListViewItem> it(mAtmItemList); *it; ++it ) {
02717 if ( (*it)->isSelected() ) {
02718 ++selectedCount;
02719 }
02720 }
02721
02722 mAttachMenu->setItemEnabled( mOpenId, selectedCount > 0 );
02723 mAttachMenu->setItemEnabled( mOpenWithId, selectedCount > 0 );
02724 mAttachMenu->setItemEnabled( mViewId, selectedCount > 0 );
02725 mAttachMenu->setItemEnabled( mRemoveId, selectedCount > 0 );
02726 mAttachMenu->setItemEnabled( mSaveAsId, selectedCount == 1 );
02727 mAttachMenu->setItemEnabled( mPropertiesId, selectedCount == 1 );
02728
02729 mAttachMenu->popup(QCursor::pos());
02730 }
02731
02732
02733 int KMComposeWin::currentAttachmentNum()
02734 {
02735 int i = 0;
02736 for ( QPtrListIterator<QListViewItem> it(mAtmItemList); *it; ++it, ++i )
02737 if ( *it == mAtmListView->currentItem() )
02738 return i;
02739 return -1;
02740 }
02741
02742
02743 void KMComposeWin::slotAttachProperties()
02744 {
02745 int idx = currentAttachmentNum();
02746
02747 if (idx < 0) return;
02748
02749 KMMessagePart* msgPart = mAtmList.at(idx);
02750 msgPart->setCharset(mCharset);
02751
02752 KMMsgPartDialogCompat dlg;
02753 dlg.setMsgPart(msgPart);
02754 KMAtmListViewItem* listItem = (KMAtmListViewItem*)(mAtmItemList.at(idx));
02755 if( canSignEncryptAttachments() && listItem ) {
02756 dlg.setCanSign( true );
02757 dlg.setCanEncrypt( true );
02758 dlg.setSigned( listItem->isSign() );
02759 dlg.setEncrypted( listItem->isEncrypt() );
02760 } else {
02761 dlg.setCanSign( false );
02762 dlg.setCanEncrypt( false );
02763 }
02764 if (dlg.exec())
02765 {
02766 mAtmModified = TRUE;
02767
02768 if( listItem ) {
02769 msgPartToItem(msgPart, listItem);
02770 if( canSignEncryptAttachments() ) {
02771 listItem->setSign( dlg.isSigned() );
02772 listItem->setEncrypt( dlg.isEncrypted() );
02773 }
02774 }
02775 }
02776 if (msgPart->typeStr().lower() != "text") msgPart->setCharset(QCString());
02777 }
02778
02779
02780
02781 void KMComposeWin::slotAttachView()
02782 {
02783 int i = 0;
02784 for ( QPtrListIterator<QListViewItem> it(mAtmItemList); *it; ++it, ++i ) {
02785 if ( (*it)->isSelected() ) {
02786 viewAttach( i );
02787 }
02788 }
02789 }
02790
02791
02792 void KMComposeWin::slotAttachOpen()
02793 {
02794 int i = 0;
02795 for ( QPtrListIterator<QListViewItem> it(mAtmItemList); *it; ++it, ++i ) {
02796 if ( (*it)->isSelected() ) {
02797 openAttach( i, false );
02798 }
02799 }
02800 }
02801
02802
02803 void KMComposeWin::slotAttachOpenWith()
02804 {
02805 int i = 0;
02806 for ( QPtrListIterator<QListViewItem> it(mAtmItemList); *it; ++it, ++i ) {
02807 if ( (*it)->isSelected() ) {
02808 openAttach( i, true );
02809 }
02810 }
02811 }
02812
02813
02814 bool KMComposeWin::inlineSigningEncryptionSelected() {
02815 if ( !mSignAction->isChecked() && !mEncryptAction->isChecked() )
02816 return false;
02817 return cryptoMessageFormat() == Kleo::InlineOpenPGPFormat;
02818 }
02819
02820
02821 void KMComposeWin::viewAttach( int index )
02822 {
02823 QString str, pname;
02824 KMMessagePart* msgPart;
02825 msgPart = mAtmList.at(index);
02826 pname = msgPart->name().stripWhiteSpace();
02827 if (pname.isEmpty()) pname=msgPart->contentDescription();
02828 if (pname.isEmpty()) pname="unnamed";
02829
02830 KTempFile* atmTempFile = new KTempFile();
02831 mAtmTempList.append( atmTempFile );
02832 atmTempFile->setAutoDelete( true );
02833 KPIM::kByteArrayToFile(msgPart->bodyDecodedBinary(), atmTempFile->name(), false, false,
02834 false);
02835 KMReaderMainWin *win = new KMReaderMainWin(msgPart, false,
02836 atmTempFile->name(), pname, mCharset );
02837 win->show();
02838 }
02839
02840
02841 void KMComposeWin::openAttach( int index, bool with )
02842 {
02843 KMMessagePart* msgPart = mAtmList.at(index);
02844 const QString contentTypeStr =
02845 ( msgPart->typeStr() + '/' + msgPart->subtypeStr() ).lower();
02846
02847 KMimeType::Ptr mimetype;
02848 mimetype = KMimeType::mimeType( contentTypeStr );
02849
02850 KTempFile* atmTempFile = new KTempFile();
02851 mAtmTempList.append( atmTempFile );
02852 const bool autoDelete = true;
02853 atmTempFile->setAutoDelete( autoDelete );
02854
02855 KURL url;
02856 url.setPath( atmTempFile->name() );
02857
02858 KPIM::kByteArrayToFile( msgPart->bodyDecodedBinary(), atmTempFile->name(), false, false,
02859 false );
02860 if ( ::chmod( QFile::encodeName( atmTempFile->name() ), S_IRUSR ) != 0) {
02861 QFile::remove(url.path());
02862 return;
02863 }
02864
02865 KService::Ptr offer =
02866 KServiceTypeProfile::preferredService( mimetype->name(), "Application" );
02867
02868 if ( with || !offer || mimetype->name() == "application/octet-stream" ) {
02869 if ( ( !KRun::displayOpenWithDialog( url, autoDelete ) ) && autoDelete ) {
02870 QFile::remove(url.path());
02871 }
02872 }
02873 else {
02874 if ( ( !KRun::run( *offer, url, autoDelete ) ) && autoDelete ) {
02875 QFile::remove( url.path() );
02876 }
02877 }
02878
02879 }
02880
02881
02882 void KMComposeWin::slotAttachSave()
02883 {
02884 KMMessagePart* msgPart;
02885 QString fileName, pname;
02886 int idx = currentAttachmentNum();
02887
02888 if (idx < 0) return;
02889
02890 msgPart = mAtmList.at(idx);
02891 pname = msgPart->name();
02892 if (pname.isEmpty()) pname="unnamed";
02893
02894 KURL url = KFileDialog::getSaveURL(QString::null, QString::null, 0, i18n("Save Attachment As"));
02895
02896 if( url.isEmpty() )
02897 return;
02898
02899 kmkernel->byteArrayToRemoteFile(msgPart->bodyDecodedBinary(), url);
02900 }
02901
02902
02903
02904 void KMComposeWin::slotAttachRemove()
02905 {
02906 bool attachmentRemoved = false;
02907 int i = 0;
02908 for ( QPtrListIterator<QListViewItem> it(mAtmItemList); *it; ) {
02909 if ( (*it)->isSelected() ) {
02910 removeAttach( i );
02911 attachmentRemoved = true;
02912 }
02913 else {
02914 ++it;
02915 ++i;
02916 }
02917 }
02918
02919 if ( attachmentRemoved ) {
02920 mEditor->setModified( true );
02921 slotUpdateAttachActions();
02922 }
02923 }
02924
02925
02926 void KMComposeWin::slotFind()
02927 {
02928 mEditor->search();
02929 }
02930
02931 void KMComposeWin::slotSearchAgain()
02932 {
02933 mEditor->repeatSearch();
02934 }
02935
02936
02937 void KMComposeWin::slotReplace()
02938 {
02939 mEditor->replace();
02940 }
02941
02942
02943 void KMComposeWin::slotUpdateFont()
02944 {
02945 if ( mFixedFontAction ) {
02946 mUseFixedFont = mFixedFontAction->isChecked();
02947 }
02948 mEditor->setFont( mUseFixedFont ? mFixedFont : mBodyFont );
02949 }
02950
02951 QString KMComposeWin::quotePrefixName() const
02952 {
02953 if ( !msg() )
02954 return QString::null;
02955
02956 KConfig *config=KMKernel::config();
02957 KConfigGroupSaver saver(config, "General");
02958
02959 int languageNr = config->readNumEntry("reply-current-language",0);
02960 config->setGroup( QString("KMMessage #%1").arg(languageNr) );
02961
02962 QString quotePrefix = config->readEntry("indent-prefix", ">%_");
02963 quotePrefix = msg()->formatString(quotePrefix);
02964 return quotePrefix;
02965 }
02966
02967 void KMComposeWin::slotPasteAsQuotation()
02968 {
02969 if( mEditor->hasFocus() && msg() )
02970 {
02971 QString quotePrefix = quotePrefixName();
02972 QString s = QApplication::clipboard()->text();
02973 if (!s.isEmpty()) {
02974 for (int i=0; (uint)i<s.length(); i++) {
02975 if ( s[i] < ' ' && s[i] != '\n' && s[i] != '\t' )
02976 s[i] = ' ';
02977 }
02978 s.prepend(quotePrefix);
02979 s.replace("\n","\n"+quotePrefix);
02980 mEditor->insert(s);
02981 }
02982 }
02983 }
02984
02985
02986 void KMComposeWin::slotAddQuotes()
02987 {
02988 if( mEditor->hasFocus() && msg() )
02989 {
02990 if ( mEditor->hasMarkedText()) {
02991 QString s = mEditor->markedText();
02992 QString quotePrefix = quotePrefixName();
02993 s.prepend(quotePrefix);
02994 s.replace("\n", "\n"+quotePrefix);
02995 mEditor->insert(s);
02996 } else {
02997 int l = mEditor->currentLine();
02998 int c = mEditor->currentColumn();
02999 QString s = mEditor->textLine(l);
03000 s.prepend("> ");
03001 mEditor->insertLine(s,l);
03002 mEditor->removeLine(l+1);
03003 mEditor->setCursorPosition(l,c+2);
03004 }
03005 }
03006 }
03007
03008
03009 void KMComposeWin::slotRemoveQuotes()
03010 {
03011 if( mEditor->hasFocus() && msg() )
03012 {
03013 QString quotePrefix = quotePrefixName();
03014 if (mEditor->hasMarkedText()) {
03015 QString s = mEditor->markedText();
03016 QString quotePrefix = quotePrefixName();
03017 if (s.left(2) == quotePrefix )
03018 s.remove(0,2);
03019 s.replace("\n"+quotePrefix,"\n");
03020 mEditor->insert(s);
03021 } else {
03022 int l = mEditor->currentLine();
03023 int c = mEditor->currentColumn();
03024 QString s = mEditor->textLine(l);
03025 if (s.left(2) == quotePrefix) {
03026 s.remove(0,2);
03027 mEditor->insertLine(s,l);
03028 mEditor->removeLine(l+1);
03029 mEditor->setCursorPosition(l,c-2);
03030 }
03031 }
03032 }
03033 }
03034
03035
03036
03037 void KMComposeWin::slotUndo()
03038 {
03039 QWidget* fw = focusWidget();
03040 if (!fw) return;
03041
03042 if ( ::qt_cast<KEdit*>(fw) )
03043 static_cast<QMultiLineEdit*>(fw)->undo();
03044 else if (::qt_cast<QLineEdit*>(fw))
03045 static_cast<QLineEdit*>(fw)->undo();
03046 }
03047
03048 void KMComposeWin::slotRedo()
03049 {
03050 QWidget* fw = focusWidget();
03051 if (!fw) return;
03052
03053 if (::qt_cast<KEdit*>(fw))
03054 static_cast<KEdit*>(fw)->redo();
03055 else if (::qt_cast<QLineEdit*>(fw))
03056 static_cast<QLineEdit*>(fw)->redo();
03057 }
03058
03059
03060 void KMComposeWin::slotCut()
03061 {
03062 QWidget* fw = focusWidget();
03063 if (!fw) return;
03064
03065 if (::qt_cast<KEdit*>(fw))
03066 static_cast<KEdit*>(fw)->cut();
03067 else if (::qt_cast<QLineEdit*>(fw))
03068 static_cast<QLineEdit*>(fw)->cut();
03069 }
03070
03071
03072
03073 void KMComposeWin::slotCopy()
03074 {
03075 QWidget* fw = focusWidget();
03076 if (!fw) return;
03077
03078 #ifdef KeyPress
03079 #undef KeyPress
03080 #endif
03081
03082 QKeyEvent k(QEvent::KeyPress, Key_C , 0 , ControlButton);
03083 kapp->notify(fw, &k);
03084 }
03085
03086
03087
03088 void KMComposeWin::slotPaste()
03089 {
03090 QWidget* fw = focusWidget();
03091 if (!fw) return;
03092
03093 #ifdef KeyPress
03094 #undef KeyPress
03095 #endif
03096
03097 QKeyEvent k(QEvent::KeyPress, Key_V , 0 , ControlButton);
03098 kapp->notify(fw, &k);
03099 }
03100
03101
03102
03103 void KMComposeWin::slotMarkAll()
03104 {
03105 QWidget* fw = focusWidget();
03106 if (!fw) return;
03107
03108 if (::qt_cast<QLineEdit*>(fw))
03109 static_cast<QLineEdit*>(fw)->selectAll();
03110 else if (::qt_cast<KEdit*>(fw))
03111 static_cast<KEdit*>(fw)->selectAll();
03112 }
03113
03114
03115
03116 void KMComposeWin::slotClose()
03117 {
03118 close(FALSE);
03119 }
03120
03121
03122
03123 void KMComposeWin::slotNewComposer()
03124 {
03125 KMComposeWin* win;
03126 KMMessage* msg = new KMMessage;
03127
03128 msg->initHeader();
03129 win = new KMComposeWin(msg);
03130 win->show();
03131 }
03132
03133
03134
03135 void KMComposeWin::slotNewMailReader()
03136 {
03137 KMMainWin *kmmwin = new KMMainWin(0);
03138 kmmwin->show();
03139
03140 }
03141
03142
03143
03144 void KMComposeWin::slotUpdWinTitle(const QString& text)
03145 {
03146 if (text.isEmpty())
03147 setCaption("("+i18n("unnamed")+")");
03148 else setCaption(text);
03149 }
03150
03151
03152
03153 void KMComposeWin::slotEncryptToggled(bool on)
03154 {
03155 #ifdef KLEO_CHIASMUS
03156 if ( on && mEncryptBodyWithChiasmus ) {
03157 int ret = KMessageBox::warningContinueCancel( this,
03158 i18n("You have chosen to encrypt the body of your message using "
03159 "chiasmus. Additionally encrypting such messages by other means "
03160 "is currently not supported. Do you want to continue, which "
03161 "will disable encryption of the body (but not of attachments ) "
03162 "using chiasmus, or cancel, which will disable additional "
03163 "(non-chiasmus) encryption?" ),
03164 i18n("Chiasmus Body Encryption Conflict") );
03165 if ( ret == KMessageBox::Cancel ) {
03166 mEncryptAction->setChecked( false );
03167 return;
03168 }
03169 slotEncryptBodyChiasmusToggled( false );
03170 mEncryptBodyChiasmusAction->setChecked( false );
03171 }
03172 #endif
03173 setEncryption( on, true );
03174 }
03175
03176
03177
03178 void KMComposeWin::setEncryption( bool encrypt, bool setByUser )
03179 {
03180 if ( !mEncryptAction->isEnabled() )
03181 encrypt = false;
03182
03183
03184 else if ( encrypt && encryptToSelf() && !mLastIdentityHasEncryptionKey ) {
03185 if ( setByUser )
03186 KMessageBox::sorry( this,
03187 i18n("<qt><p>You have requested that messages be "
03188 "encrypted to yourself, but the currently selected "
03189 "identity does not define an (OpenPGP or S/MIME) "
03190 "encryption key to use for this.</p>"
03191 "<p>Please select the key(s) to use "
03192 "in the identity configuration.</p>"
03193 "</qt>"),
03194 i18n("Undefined Encryption Key") );
03195 encrypt = false;
03196 }
03197
03198
03199 mEncryptAction->setChecked( encrypt );
03200
03201
03202 if ( encrypt )
03203 mEncryptAction->setIcon("encrypted");
03204 else
03205 mEncryptAction->setIcon("decrypted");
03206
03207
03208 if ( canSignEncryptAttachments() ) {
03209 for ( KMAtmListViewItem* entry =
03210 static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
03211 entry;
03212 entry = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) )
03213 entry->setEncrypt( encrypt );
03214 }
03215 }
03216
03217
03218
03219 void KMComposeWin::slotSignToggled(bool on)
03220 {
03221 #ifdef KLEO_CHIASMUS
03222 if ( on && mEncryptBodyWithChiasmus ) {
03223 int ret = KMessageBox::warningContinueCancel( this,
03224 i18n("You have chosen to encrypt the body of your message using "
03225 "chiasmus. Signing such messages is currently not supported. Do you "
03226 "want to continue, which will disable encryption of the body (but not "
03227 "of attachments ) using chiasmus, or cancel, which will disable signing?"),
03228 i18n("Chiasmus Body Encryption Conflict" ) );
03229 if ( ret == KMessageBox::Cancel ) {
03230 mSignAction->setChecked( false );
03231 return;
03232 }
03233 slotEncryptBodyChiasmusToggled( false );
03234 mEncryptBodyChiasmusAction->setChecked( false );
03235 }
03236 #endif
03237 setSigning( on, true );
03238 }
03239
03240
03241
03242 void KMComposeWin::setSigning( bool sign, bool setByUser )
03243 {
03244 if ( !mSignAction->isEnabled() )
03245 sign = false;
03246
03247
03248 if ( sign && !mLastIdentityHasSigningKey ) {
03249 if ( setByUser )
03250 KMessageBox::sorry( this,
03251 i18n("<qt><p>In order to be able to sign "
03252 "this message you first have to "
03253 "define the (OpenPGP or S/MIME) signing key "
03254 "to use.</p>"
03255 "<p>Please select the key to use "
03256 "in the identity configuration.</p>"
03257 "</qt>"),
03258 i18n("Undefined Signing Key") );
03259 sign = false;
03260 }
03261
03262
03263 mSignAction->setChecked( sign );
03264
03265
03266 if ( canSignEncryptAttachments() ) {
03267 for ( KMAtmListViewItem* entry =
03268 static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
03269 entry;
03270 entry = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) )
03271 entry->setSign( sign );
03272 }
03273 }
03274
03275
03276
03277 void KMComposeWin::slotWordWrapToggled(bool on)
03278 {
03279 if (on)
03280 {
03281 mEditor->setWordWrap( QMultiLineEdit::FixedColumnWidth );
03282 mEditor->setWrapColumnOrWidth(mLineBreak);
03283 }
03284 else
03285 {
03286 mEditor->setWordWrap( QMultiLineEdit::NoWrap );
03287 }
03288 }
03289
03290
03291
03292 void KMComposeWin::slotPrint()
03293 {
03294 mMessageWasModified = ( mEditor->isModified() || mEdtFrom->edited() ||
03295 mEdtReplyTo->edited() || mEdtTo->edited() ||
03296 mEdtCc->edited() || mEdtBcc->edited() ||
03297 mEdtSubject->edited() || mAtmModified ||
03298 ( mTransport->lineEdit() &&
03299 mTransport->lineEdit()->edited() ) );
03300 connect( this, SIGNAL( applyChangesDone( bool ) ),
03301 this, SLOT( slotContinuePrint( bool ) ) );
03302 applyChanges( true );
03303 }
03304
03305 void KMComposeWin::slotContinuePrint( bool rc )
03306 {
03307 disconnect( this, SIGNAL( applyChangesDone( bool ) ),
03308 this, SLOT( slotContinuePrint( bool ) ) );
03309
03310 if( rc ) {
03311 if ( mComposedMessages.isEmpty() ) {
03312 kdDebug(5006) << "Composing the message failed." << endl;
03313 return;
03314 }
03315 KMCommand *command = new KMPrintCommand( this, mComposedMessages.first() );
03316 command->start();
03317 mEditor->setModified( mMessageWasModified );
03318 }
03319 }
03320
03321
03322
03323 void KMComposeWin::doSend(int aSendNow, bool saveInDrafts)
03324 {
03325 if ( aSendNow && kmkernel->isOffline() ) {
03326 KMessageBox::information( this,
03327 i18n("KMail is currently in offline mode,"
03328 "your messages will be kept in the outbox until you go online."),
03329 i18n("Online/Offline"), "kmailIsOffline" );
03330 mSendNow = false;
03331 } else {
03332 mSendNow = aSendNow;
03333 }
03334
03335 mSaveInDrafts = saveInDrafts;
03336
03337 if (!saveInDrafts)
03338 {
03339 if ( from().isEmpty() ) {
03340 if ( !( mShowHeaders & HDR_FROM ) ) {
03341 mShowHeaders |= HDR_FROM;
03342 rethinkFields( false );
03343 }
03344 mEdtFrom->setFocus();
03345 KMessageBox::sorry( this,
03346 i18n("You must enter your email address in the "
03347 "From: field. You should also set your email "
03348 "address for all identities, so that you do "
03349 "not have to enter it for each message.") );
03350 return;
03351 }
03352 if ( to().isEmpty() )
03353 {
03354 if ( cc().isEmpty() && bcc().isEmpty()) {
03355 if ( mEdtTo ) mEdtTo->setFocus();
03356 KMessageBox::information( this,
03357 i18n("You must specify at least one receiver,"
03358 "either in the To: field or as CC or as BCC.") );
03359 return;
03360 }
03361 else {
03362 if ( mEdtTo ) mEdtTo->setFocus();
03363 int rc =
03364 KMessageBox::questionYesNo( this,
03365 i18n("To field is missing."
03366 "Send message anyway?"),
03367 i18n("No To: specified") );
03368 if ( rc == KMessageBox::No ){
03369 return;
03370 }
03371 }
03372 }
03373
03374 if (subject().isEmpty())
03375 {
03376 mEdtSubject->setFocus();
03377 int rc =
03378 KMessageBox::questionYesNo( this,
03379 i18n("You did not specify a subject. "
03380 "Send message anyway?"),
03381 i18n("No Subject Specified"),
03382 i18n("S&end as Is"),
03383 i18n("&Specify the Subject"),
03384 "no_subject_specified" );
03385 if( rc == KMessageBox::No )
03386 {
03387 return;
03388 }
03389 }
03390
03391 if ( userForgotAttachment() )
03392 return;
03393 }
03394
03395 KCursorSaver busy(KBusyPtr::busy());
03396 mMsg->setDateToday();
03397
03398
03399
03400
03401
03402
03403 QString hf = mMsg->headerField("X-KMail-Transport");
03404 if ((mTransport->currentText() != mTransport->text(0)) ||
03405 (!hf.isEmpty() && (hf != mTransport->text(0))))
03406 mMsg->setHeaderField("X-KMail-Transport", mTransport->currentText());
03407
03408 if( saveInDrafts )
03409 mMsg->setHeaderField("X-KMail-CryptoFormat", QString::number(cryptoMessageFormat()));
03410
03411 mDisableBreaking = saveInDrafts;
03412
03413 const bool neverEncrypt = ( saveInDrafts && mNeverEncryptWhenSavingInDrafts )
03414 || mSigningAndEncryptionExplicitlyDisabled;
03415 connect( this, SIGNAL( applyChangesDone( bool ) ),
03416 SLOT( slotContinueDoSend( bool ) ) );
03417
03418 if ( mEditor->textFormat() == Qt::RichText )
03419 mMsg->setHeaderField( "X-KMail-Markup", "true" );
03420 else
03421 mMsg->removeHeaderField( "X-KMail-Markup" );
03422 if ( mEditor->textFormat() == Qt::RichText && inlineSigningEncryptionSelected() ) {
03423 QString keepBtnText = mEncryptAction->isChecked() ?
03424 mSignAction->isChecked() ? i18n( "&Keep markup, do not sign/encrypt" )
03425 : i18n( "&Keep markup, do not encrypt" )
03426 : i18n( "&Keep markup, do not sign" );
03427 QString yesBtnText = mEncryptAction->isChecked() ?
03428 mSignAction->isChecked() ? i18n("Sign/Encrypt (delete markup)")
03429 : i18n( "Encrypt (delete markup)" )
03430 : i18n( "Sign (delete markup)" );
03431 int ret = KMessageBox::warningYesNoCancel(this,
03432 i18n("<qt><p>Inline signing/encrypting of HTML messages is not possible;</p>"
03433 "<p>do you want to delete your markup?</p></qt>"),
03434 i18n("Sign/Encrypt Message?"),
03435 KGuiItem( yesBtnText ),
03436 KGuiItem( keepBtnText ) );
03437 if ( KMessageBox::Cancel == ret )
03438 return;
03439 if ( KMessageBox::No == ret ) {
03440 mEncryptAction->setChecked(false);
03441 mSignAction->setChecked(false);
03442 }
03443 else {
03444 toggleMarkup(false);
03445 }
03446 }
03447
03448 if ( neverEncrypt && saveInDrafts ) {
03449
03450
03451 mMsg->setHeaderField( "X-KMail-SignatureActionEnabled", mSignAction->isChecked()? "true":"false" );
03452 mMsg->setHeaderField( "X-KMail-EncryptActionEnabled", mEncryptAction->isChecked()? "true":"false" );
03453 } else {
03454 mMsg->removeHeaderField( "X-KMail-SignatureActionEnabled" );
03455 mMsg->removeHeaderField( "X-KMail-EncryptActionEnabled" );
03456 }
03457
03458
03459 kdDebug(5006) << "KMComposeWin::doSend() - calling applyChanges()"
03460 << endl;
03461 applyChanges( neverEncrypt );
03462 }
03463
03464 void KMComposeWin::slotContinueDoSend( bool sentOk )
03465 {
03466 kdDebug(5006) << "KMComposeWin::slotContinueDoSend( " << sentOk << " )"
03467 << endl;
03468 disconnect( this, SIGNAL( applyChangesDone( bool ) ),
03469 this, SLOT( slotContinueDoSend( bool ) ) );
03470
03471 if ( !sentOk ) {
03472 mDisableBreaking = false;
03473 return;
03474 }
03475 if (!mAutoDeleteMsg) mEditor->setModified(FALSE);
03476 mEdtFrom->setEdited(FALSE);
03477 mEdtReplyTo->setEdited(FALSE);
03478 mEdtTo->setEdited(FALSE);
03479 mEdtCc->setEdited(FALSE);
03480 mEdtBcc->setEdited(FALSE);
03481 mEdtSubject->setEdited(FALSE);
03482 if (mTransport->lineEdit())
03483 mTransport->lineEdit()->setEdited(FALSE);
03484 mAtmModified = FALSE;
03485
03486 for ( QValueVector<KMMessage*>::iterator it = mComposedMessages.begin() ; it != mComposedMessages.end() ; ++it ) {
03487
03488
03489 (*it)->cleanupHeader();
03490
03491
03492 (*it)->setComplete( true );
03493
03494 if (mSaveInDrafts) {
03495 KMFolder* draftsFolder = 0, *imapDraftsFolder = 0;
03496
03497 if ( !(*it)->drafts().isEmpty() ) {
03498 draftsFolder = kmkernel->folderMgr()->findIdString( (*it)->drafts() );
03499 if ( draftsFolder == 0 )
03500
03501
03502 draftsFolder = kmkernel->dimapFolderMgr()->findIdString( (*it)->drafts() );
03503 if ( draftsFolder == 0 )
03504 imapDraftsFolder = kmkernel->imapFolderMgr()->findIdString( (*it)->drafts() );
03505 if ( !draftsFolder && !imapDraftsFolder ) {
03506 const KPIM::Identity & id = kmkernel->identityManager()
03507 ->identityForUoidOrDefault( (*it)->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt() );
03508 KMessageBox::information(0, i18n("The custom drafts folder for identity "
03509 "\"%1\" does not exist (anymore); "
03510 "therefore, the default drafts folder "
03511 "will be used.")
03512 .arg( id.identityName() ) );
03513 }
03514 }
03515 if (imapDraftsFolder && imapDraftsFolder->noContent())
03516 imapDraftsFolder = 0;
03517
03518 if ( draftsFolder == 0 ) {
03519 draftsFolder = kmkernel->draftsFolder();
03520 } else {
03521 draftsFolder->open();
03522 }
03523 kdDebug(5006) << "saveindrafts: drafts=" << draftsFolder->name() << endl;
03524 if (imapDraftsFolder)
03525 kdDebug(5006) << "saveindrafts: imapdrafts="
03526 << imapDraftsFolder->name() << endl;
03527
03528 sentOk = !(draftsFolder->addMsg((*it)));
03529
03530
03531 draftsFolder->unGetMsg(draftsFolder->count() - 1);
03532 (*it) = draftsFolder->getMsg(draftsFolder->count() - 1);
03533
03534 if (imapDraftsFolder) {
03535
03536 imapDraftsFolder->moveMsg((*it));
03537 (static_cast<KMFolderImap*>(imapDraftsFolder->storage()))->getFolder();
03538 }
03539
03540 } else {
03541 (*it)->setTo( KMMessage::expandAliases( to() ));
03542 (*it)->setCc( KMMessage::expandAliases( cc() ));
03543 if( !mComposer->originalBCC().isEmpty() )
03544 (*it)->setBcc( KMMessage::expandAliases( mComposer->originalBCC() ));
03545 QString recips = (*it)->headerField( "X-KMail-Recipients" );
03546 if( !recips.isEmpty() ) {
03547 (*it)->setHeaderField( "X-KMail-Recipients", KMMessage::expandAliases( recips ) );
03548 }
03549 (*it)->cleanupHeader();
03550 sentOk = kmkernel->msgSender()->send((*it), mSendNow);
03551 }
03552
03553 if (!sentOk)
03554 return;
03555
03556 *it = 0;
03557 }
03558
03559 RecentAddresses::self( KMKernel::config() )->add( bcc() );
03560 RecentAddresses::self( KMKernel::config() )->add( cc() );
03561 RecentAddresses::self( KMKernel::config() )->add( to() );
03562
03563 mAutoDeleteMsg = FALSE;
03564 mFolder = 0;
03565 cleanupAutoSave();
03566 close();
03567 return;
03568 }
03569
03570
03571
03572
03573 void KMComposeWin::slotSendLater()
03574 {
03575 if ( mEditor->checkExternalEditorFinished() )
03576 doSend( false );
03577 }
03578
03579
03580
03581 void KMComposeWin::slotSaveDraft() {
03582 if ( mEditor->checkExternalEditorFinished() )
03583 doSend( false, true );
03584 }
03585
03586
03587
03588 void KMComposeWin::slotSendNow() {
03589 if ( !mEditor->checkExternalEditorFinished() )
03590 return;
03591 if (mConfirmSend) {
03592 switch(KMessageBox::warningYesNoCancel(mMainWidget,
03593 i18n("About to send email..."),
03594 i18n("Send Confirmation"),
03595 i18n("Send &Now"),
03596 i18n("Send &Later"))) {
03597 case KMessageBox::Yes:
03598 doSend(TRUE);
03599 break;
03600 case KMessageBox::No:
03601 doSend(FALSE);
03602 break;
03603 case KMessageBox::Cancel:
03604 break;
03605 default:
03606 ;
03607 }
03608 return;
03609 }
03610
03611 doSend(TRUE);
03612 }
03613
03614
03615
03616 void KMComposeWin::slotAppendSignature()
03617 {
03618 insertSignature();
03619 }
03620
03621
03622 void KMComposeWin::slotPrependSignature()
03623 {
03624 insertSignature( false );
03625 }
03626
03627
03628 void KMComposeWin::slotInsertSignatureAtCursor()
03629 {
03630 insertSignature( false, mEditor->currentLine() );
03631 }
03632
03633
03634
03635 void KMComposeWin::insertSignature( bool append, int pos )
03636 {
03637 bool mod = mEditor->isModified();
03638
03639 const KPIM::Identity & ident =
03640 kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() );
03641 mOldSigText = append? ident.signatureText() : ident.signature().rawText();
03642 if( !mOldSigText.isEmpty() )
03643 {
03644 mEditor->sync();
03645 if ( append ) {
03646 mEditor->append(mOldSigText);
03647 } else {
03648 mEditor->insertAt(mOldSigText, pos, 0);
03649 }
03650 mEditor->update();
03651 mEditor->setModified(mod);
03652
03653
03654 mEditor->setCursorPosition( pos, 0 );
03655 if ( !append && pos == 0 )
03656 mEditor->setContentsPos( 0, 0 );
03657 }
03658 }
03659
03660
03661
03662 void KMComposeWin::slotHelp()
03663 {
03664 kapp->invokeHelp();
03665 }
03666
03667
03668 void KMComposeWin::slotCleanSpace()
03669 {
03670 mEditor->cleanWhiteSpace();
03671 }
03672
03673
03674 void KMComposeWin::slotToggleMarkup()
03675 {
03676 if ( markupAction->isChecked() ) {
03677 toolBar("htmlToolBar")->show();
03678
03679 fontChanged( mEditor->currentFont().family() );
03680 fontAction->setFont( mEditor->currentFont().family() );
03681 fontSizeAction->setFontSize( mEditor->currentFont().pointSize() );
03682 mSaveFont = mEditor->currentFont();
03683 }
03684 else
03685 toggleMarkup(false);
03686
03687 }
03688
03689 void KMComposeWin::toggleMarkup(bool markup)
03690 {
03691 if ( markup ) {
03692 if ( !mUseHTMLEditor ) {
03693 kdDebug(5006) << "setting RichText editor" << endl;
03694 mUseHTMLEditor = true;
03695
03696
03697 int paraFrom, indexFrom, paraTo, indexTo;
03698 mEditor->getSelection ( ¶From, &indexFrom, ¶To, &indexTo);
03699 mEditor->selectAll();
03700
03701 bool _bold = textBoldAction->isChecked();
03702 bool _italic = textItalicAction->isChecked();
03703 mEditor->setColor(QColor(0,0,0));
03704 textBoldAction->setChecked(_bold);
03705 textItalicAction->setChecked(_italic);
03706 mEditor->setSelection ( paraFrom, indexFrom, paraTo, indexTo);
03707
03708 mEditor->setTextFormat(Qt::RichText);
03709 mEditor->setModified(true);
03710 markupAction->setChecked(true);
03711 toolBar( "htmlToolBar" )->show();
03712 mEditor->deleteAutoSpellChecking();
03713 mAutoSpellCheckingAction->setChecked(false);
03714 slotAutoSpellCheckingToggled(false);
03715 }
03716 }
03717 else if ( mUseHTMLEditor ) {
03718 kdDebug(5006) << "setting PlainText editor" << endl;
03719 mUseHTMLEditor = false;
03720 mEditor->setTextFormat(Qt::PlainText);
03721 QString text = mEditor->text();
03722 mEditor->setText(text);
03723 mEditor->setModified(true);
03724 toolBar("htmlToolBar")->hide();
03725 mEditor->initializeAutoSpellChecking( mDictionaryCombo->spellConfig());
03726 slotAutoSpellCheckingToggled(true);
03727 }
03728 else if ( !markup && !mUseHTMLEditor )
03729 {
03730 toolBar("htmlToolBar")->hide();
03731 }
03732 }
03733
03734 void KMComposeWin::slotSubjectTextSpellChecked()
03735 {
03736 mSubjectTextWasSpellChecked = true;
03737 }
03738
03739
03740 void KMComposeWin::slotAutoSpellCheckingToggled( bool on )
03741 {
03742 if ( mEditor->autoSpellChecking(on) == -1 )
03743 mAutoSpellCheckingAction->setChecked(false);
03744 }
03745
03746 void KMComposeWin::slotSpellcheck()
03747 {
03748 if (mSpellCheckInProgress) return;
03749 mSubjectTextWasSpellChecked = false;
03750 mSpellCheckInProgress=TRUE;
03751
03752
03753
03754
03755
03756 mEditor->spellcheck();
03757 }
03758
03759
03760
03761 void KMComposeWin::slotSpellcheckDone(int result)
03762 {
03763 kdDebug(5006) << "spell check complete: result = " << result << endl;
03764 mSpellCheckInProgress=FALSE;
03765
03766 switch( result )
03767 {
03768 case KS_CANCEL:
03769 statusBar()->changeItem(i18n(" Spell check canceled."),0);
03770 break;
03771 case KS_STOP:
03772 statusBar()->changeItem(i18n(" Spell check stopped."),0);
03773 break;
03774 default:
03775 statusBar()->changeItem(i18n(" Spell check complete."),0);
03776 break;
03777 }
03778 QTimer::singleShot( 2000, this, SLOT(slotSpellcheckDoneClearStatus()) );
03779 }
03780
03781 void KMComposeWin::slotSpellcheckDoneClearStatus()
03782 {
03783 statusBar()->changeItem("", 0);
03784 }
03785
03786
03787
03788 void KMComposeWin::focusNextPrevEdit(const QWidget* aCur, bool aNext)
03789 {
03790 QWidget* cur;
03791
03792 if (!aCur)
03793 {
03794 cur=mEdtList.last();
03795 }
03796 else
03797 {
03798 for (cur=mEdtList.first(); aCur!=cur && cur; cur=mEdtList.next())
03799 ;
03800 if (!cur) return;
03801 if (aNext) cur = mEdtList.next();
03802 else cur = mEdtList.prev();
03803 }
03804 if (cur) cur->setFocus();
03805 else if (aNext) mEditor->setFocus();
03806 }
03807
03808
03809 void KMComposeWin::slotIdentityChanged(uint uoid)
03810 {
03811 const KPIM::Identity & ident =
03812 kmkernel->identityManager()->identityForUoid( uoid );
03813 if ( ident.isNull() ) return;
03814
03815
03816 slotUpdateSignatureActions();
03817
03818 if(!ident.fullEmailAddr().isNull())
03819 mEdtFrom->setText(ident.fullEmailAddr());
03820
03821 if ( from().isEmpty() )
03822 mShowHeaders |= HDR_FROM;
03823 mEdtReplyTo->setText(ident.replyToAddr());
03824
03825
03826 if( !mEdtBcc->edited() || !ident.bcc().isEmpty() )
03827 mEdtBcc->setText(ident.bcc());
03828
03829 if (! ident.bcc().isEmpty()) {
03830 mShowHeaders |= HDR_BCC;
03831 }
03832 if (ident.organization().isEmpty())
03833 mMsg->removeHeaderField("Organization");
03834 else
03835 mMsg->setHeaderField("Organization", ident.organization());
03836
03837 if (!mBtnTransport->isChecked()) {
03838 QString transp = ident.transport();
03839 if (transp.isEmpty())
03840 {
03841 mMsg->removeHeaderField("X-KMail-Transport");
03842 transp = mTransport->text(0);
03843 }
03844 else
03845 mMsg->setHeaderField("X-KMail-Transport", transp);
03846 bool found = false;
03847 int i;
03848 for (i = 0; i < mTransport->count(); i++) {
03849 if (mTransport->text(i) == transp) {
03850 found = true;
03851 mTransport->setCurrentItem(i);
03852 break;
03853 }
03854 }
03855 if (found == false) {
03856 if (i == mTransport->maxCount()) mTransport->setMaxCount(i + 1);
03857 mTransport->insertItem(transp,i);
03858 mTransport->setCurrentItem(i);
03859 }
03860 }
03861
03862 mDictionaryCombo->setCurrentByDictionary( ident.dictionary() );
03863
03864 if ( !mBtnFcc->isChecked() )
03865 {
03866 if ( ident.fcc().isEmpty() )
03867 mFcc->setFolder( kmkernel->sentFolder() );
03868 else
03869 setFcc( ident.fcc() );
03870 }
03871
03872 QString edtText = mEditor->text();
03873 bool appendNewSig = true;
03874 const bool prepended = GlobalSettings::prependSignatures();
03875
03876 if( !mOldSigText.isEmpty() )
03877 {
03878 if( !prepended && edtText.endsWith( mOldSigText ) )
03879 edtText.truncate( edtText.length() - mOldSigText.length() );
03880 else if ( prepended && edtText.find( mOldSigText ) != -1 ) {
03881 edtText.remove( mOldSigText );
03882 }
03883 else
03884 appendNewSig = false;
03885 }
03886
03887 mOldSigText = prepended ? ident.signature().rawText() : ident.signatureText();
03888 if( appendNewSig )
03889 {
03890 if( !mOldSigText.isEmpty() && mAutoSign ) {
03891 if ( prepended ) {
03892 edtText.prepend( mOldSigText );
03893 } else {
03894 edtText.append( mOldSigText );
03895 }
03896 }
03897 mEditor->setText( edtText );
03898 }
03899
03900
03901
03902 bool bNewIdentityHasSigningKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
03903 bool bNewIdentityHasEncryptionKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
03904 mAttachMPK->setEnabled( Kleo::CryptoBackendFactory::instance()->openpgp() &&
03905 !ident.pgpEncryptionKey().isEmpty() );
03906
03907 if ( !bNewIdentityHasEncryptionKey && mLastIdentityHasEncryptionKey ) {
03908 mLastEncryptActionState = mEncryptAction->isChecked();
03909 setEncryption( false );
03910 }
03911 if ( !bNewIdentityHasSigningKey && mLastIdentityHasSigningKey ) {
03912 mLastSignActionState = mSignAction->isChecked();
03913 setSigning( false );
03914 }
03915
03916 if ( bNewIdentityHasEncryptionKey && !mLastIdentityHasEncryptionKey )
03917 setEncryption( mLastEncryptActionState );
03918 if ( bNewIdentityHasSigningKey && !mLastIdentityHasSigningKey )
03919 setSigning( mLastSignActionState );
03920
03921 mLastIdentityHasSigningKey = bNewIdentityHasSigningKey;
03922 mLastIdentityHasEncryptionKey = bNewIdentityHasEncryptionKey;
03923
03924 mEditor->setModified(TRUE);
03925 mId = uoid;
03926
03927
03928 rethinkFields( false );
03929 }
03930
03931
03932 void KMComposeWin::slotSpellcheckConfig()
03933 {
03934 KWin kwin;
03935 QTabDialog qtd (this, "tabdialog", true);
03936 KSpellConfig mKSpellConfig (&qtd);
03937
03938 qtd.addTab (&mKSpellConfig, i18n("Spellchecker"));
03939 qtd.setCancelButton ();
03940
03941 kwin.setIcons (qtd.winId(), kapp->icon(), kapp->miniIcon());
03942 qtd.setCancelButton(KStdGuiItem::cancel().text());
03943 qtd.setOkButton(KStdGuiItem::ok().text());
03944
03945 if (qtd.exec())
03946 mKSpellConfig.writeGlobalSettings();
03947 }
03948
03949
03950 void KMComposeWin::slotMenuTextCompletion()
03951 {
03952
03953 int nItem = mTextCompletionAction->currentItem();
03954
03955
03956 KConfig *config = KMKernel::config();
03957 KConfigGroup composer( config, "Composer" );
03958 composer.writeEntry( "Completion Mode", KMGlobalNS::completionModes[ nItem ].mode );
03959 config->sync();
03960
03961
03962 slotConfigChanged();
03963
03964 }
03965
03966
03967 void KMComposeWin::slotConfigureAddressCompletion()
03968 {
03969 kdDebug(5006) << k_funcinfo << endl;
03970 KPIM::LdapSearch ls;
03971 KPIM::CompletionOrderEditor editor( &ls, this );
03972 editor.exec();
03973 }
03974
03975
03976 void KMComposeWin::slotStatusMessage(const QString &message)
03977 {
03978 statusBar()->changeItem( message, 0 );
03979 }
03980
03981 void KMComposeWin::slotEditToolbars()
03982 {
03983 saveMainWindowSettings(KMKernel::config(), "Composer");
03984 KEditToolbar dlg(guiFactory(), this);
03985
03986 connect( &dlg, SIGNAL(newToolbarConfig()),
03987 SLOT(slotUpdateToolbars()) );
03988
03989 dlg.exec();
03990 }
03991
03992 void KMComposeWin::slotUpdateToolbars()
03993 {
03994 createGUI("kmcomposerui.rc");
03995 applyMainWindowSettings(KMKernel::config(), "Composer");
03996 }
03997
03998 void KMComposeWin::slotEditKeys()
03999 {
04000 KKeyDialog::configure( actionCollection(),
04001 false
04002 );
04003 }
04004
04005 void KMComposeWin::setReplyFocus( bool hasMessage )
04006 {
04007 mEditor->setFocus();
04008 if ( hasMessage )
04009 mEditor->setCursorPosition( 1, 0 );
04010 }
04011
04012 void KMComposeWin::setFocusToSubject()
04013 {
04014 mEdtSubject->setFocus();
04015 }
04016
04017 int KMComposeWin::autoSaveInterval() const
04018 {
04019 return GlobalSettings::self()->autosaveInterval() * 1000 * 60;
04020 }
04021
04022 void KMComposeWin::initAutoSave()
04023 {
04024 kdDebug(5006) << k_funcinfo << endl;
04025
04026 KMFolderMaildir::createMaildirFolders( KMKernel::localDataPath() + "autosave" );
04027 if ( mAutoSaveFilename.isEmpty() ) {
04028 mAutoSaveFilename = KMFolderMaildir::constructValidFileName();
04029 }
04030
04031 updateAutoSave();
04032 }
04033
04034 void KMComposeWin::updateAutoSave()
04035 {
04036 if ( autoSaveInterval() == 0 ) {
04037 delete mAutoSaveTimer; mAutoSaveTimer = 0;
04038 }
04039 else {
04040 if ( !mAutoSaveTimer ) {
04041 mAutoSaveTimer = new QTimer( this );
04042 connect( mAutoSaveTimer, SIGNAL( timeout() ),
04043 this, SLOT( autoSaveMessage() ) );
04044 }
04045 mAutoSaveTimer->start( autoSaveInterval() );
04046 }
04047 }
04048
04049 void KMComposeWin::setAutoSaveFilename( const QString & filename )
04050 {
04051 if ( !mAutoSaveFilename.isEmpty() )
04052 KMFolderMaildir::removeFile( KMKernel::localDataPath() + "autosave",
04053 mAutoSaveFilename );
04054 mAutoSaveFilename = filename;
04055 }
04056
04057 void KMComposeWin::cleanupAutoSave()
04058 {
04059 delete mAutoSaveTimer; mAutoSaveTimer = 0;
04060 if ( !mAutoSaveFilename.isEmpty() ) {
04061 kdDebug(5006) << k_funcinfo << "deleting autosave file "
04062 << mAutoSaveFilename << endl;
04063 KMFolderMaildir::removeFile( KMKernel::localDataPath() + "autosave",
04064 mAutoSaveFilename );
04065 mAutoSaveFilename = QString();
04066 }
04067 }
04068
04069
04070
04071 void KMComposeWin::slotCompletionModeChanged( KGlobalSettings::Completion mode)
04072 {
04073 KConfig *config = KMKernel::config();
04074 KConfigGroupSaver cs( config, "Composer" );
04075 config->writeEntry( "Completion Mode", (int) mode );
04076 config->sync();
04077
04078
04079 mEdtFrom->setCompletionMode( mode );
04080 mEdtReplyTo->setCompletionMode( mode );
04081 mEdtTo->setCompletionMode( mode );
04082 mEdtCc->setCompletionMode( mode );
04083 mEdtBcc->setCompletionMode( mode );
04084
04085
04086 for ( int i=0; i < KMGlobalNS::numCompletionModes; ++i ) {
04087 if ( KMGlobalNS::completionModes[i].mode == mode )
04088 mTextCompletionAction->setCurrentItem( i );
04089 }
04090
04091 }
04092
04093 void KMComposeWin::slotConfigChanged()
04094 {
04095 readConfig();
04096 updateAutoSave();
04097 }
04098
04099
04100
04101
04102
04103 void KMComposeWin::slotFolderRemoved(KMFolder* folder)
04104 {
04105 if ( (mFolder) && (folder->idString() == mFolder->idString()) )
04106 {
04107 mFolder = kmkernel->draftsFolder();
04108 kdDebug(5006) << "restoring drafts to " << mFolder->idString() << endl;
04109 }
04110 if (mMsg) mMsg->setParent(0);
04111 }
04112
04113
04114
04115 void KMComposeWin::slotSetAlwaysSend( bool bAlways )
04116 {
04117 mAlwaysSend = bAlways;
04118 }
04119
04120 void KMComposeWin::slotListAction( const QString& style )
04121 {
04122 toggleMarkup(true);
04123 if ( style == i18n( "Standard" ) )
04124 mEditor->setParagType( QStyleSheetItem::DisplayBlock, QStyleSheetItem::ListDisc );
04125 else if ( style == i18n( "Bulleted List (Disc)" ) )
04126 mEditor->setParagType( QStyleSheetItem::DisplayListItem, QStyleSheetItem::ListDisc );
04127 else if ( style == i18n( "Bulleted List (Circle)" ) )
04128 mEditor->setParagType( QStyleSheetItem::DisplayListItem, QStyleSheetItem::ListCircle );
04129 else if ( style == i18n( "Bulleted List (Square)" ) )
04130 mEditor->setParagType( QStyleSheetItem::DisplayListItem, QStyleSheetItem::ListSquare );
04131 else if ( style == i18n( "Ordered List (Decimal)" ))
04132 mEditor->setParagType( QStyleSheetItem::DisplayListItem, QStyleSheetItem::ListDecimal );
04133 else if ( style == i18n( "Ordered List (Alpha lower)" ) )
04134 mEditor->setParagType( QStyleSheetItem::DisplayListItem, QStyleSheetItem::ListLowerAlpha );
04135 else if ( style == i18n( "Ordered List (Alpha upper)" ) )
04136 mEditor->setParagType( QStyleSheetItem::DisplayListItem, QStyleSheetItem::ListUpperAlpha );
04137 mEditor->viewport()->setFocus();
04138 }
04139
04140 void KMComposeWin::slotFontAction( const QString& font)
04141 {
04142 toggleMarkup(true);
04143 mEditor->QTextEdit::setFamily( font );
04144 mEditor->viewport()->setFocus();
04145 }
04146
04147 void KMComposeWin::slotSizeAction( int size )
04148 {
04149 toggleMarkup(true);
04150 mEditor->setPointSize( size );
04151 mEditor->viewport()->setFocus();
04152 }
04153
04154 void KMComposeWin::slotAlignLeft()
04155 {
04156 toggleMarkup(true);
04157 mEditor->QTextEdit::setAlignment( AlignLeft );
04158 }
04159
04160 void KMComposeWin::slotAlignCenter()
04161 {
04162 toggleMarkup(true);
04163 mEditor->QTextEdit::setAlignment( AlignHCenter );
04164 }
04165
04166 void KMComposeWin::slotAlignRight()
04167 {
04168 toggleMarkup(true);
04169 mEditor->QTextEdit::setAlignment( AlignRight );
04170 }
04171
04172 void KMComposeWin::slotTextBold()
04173 {
04174 toggleMarkup(true);
04175 mEditor->QTextEdit::setBold( textBoldAction->isChecked() );
04176 }
04177
04178 void KMComposeWin::slotTextItalic()
04179 {
04180 toggleMarkup(true);
04181 mEditor->QTextEdit::setItalic( textItalicAction->isChecked() );
04182 }
04183
04184 void KMComposeWin::slotTextUnder()
04185 {
04186 toggleMarkup(true);
04187 mEditor->QTextEdit::setUnderline( textUnderAction->isChecked() );
04188 }
04189
04190 void KMComposeWin::slotFormatReset()
04191 {
04192 mEditor->setColor(mForeColor);
04193 mEditor->setCurrentFont( mSaveFont );
04194 }
04195 void KMComposeWin::slotTextColor()
04196 {
04197 QColor color = mEditor->color();
04198
04199 if ( KColorDialog::getColor( color, this ) ) {
04200 toggleMarkup(true);
04201 mEditor->setColor( color );
04202 }
04203 }
04204
04205 void KMComposeWin::fontChanged( const QFont &f )
04206 {
04207 QFontDatabase *fontdb = new QFontDatabase();
04208
04209 if ( fontdb->bold(f.family(), "Bold") ) {
04210 textBoldAction->setChecked( f.bold() );
04211 textBoldAction->setEnabled(true);
04212 }
04213 else
04214 textBoldAction->setEnabled(false);
04215
04216 if ( fontdb->italic(f.family(), "Italic") ) {
04217 textItalicAction->setChecked( f.italic() );
04218 textItalicAction->setEnabled(true);
04219 }
04220 else
04221 textItalicAction->setEnabled(false);
04222
04223 textUnderAction->setChecked( f.underline() );
04224
04225 fontAction->setFont( f.family() );
04226 fontSizeAction->setFontSize( f.pointSize() );
04227 delete fontdb;
04228 }
04229
04230 void KMComposeWin::alignmentChanged( int a )
04231 {
04232
04233 alignLeftAction->setChecked( ( a == AlignAuto ) || ( a & AlignLeft ) );
04234 alignCenterAction->setChecked( ( a & AlignHCenter ) );
04235 alignRightAction->setChecked( ( a & AlignRight ) );
04236 }
04237
04238 namespace {
04239 class KToggleActionResetter {
04240 KToggleAction * mAction;
04241 bool mOn;
04242 public:
04243 KToggleActionResetter( KToggleAction * action, bool on )
04244 : mAction( action ), mOn( on ) {}
04245 ~KToggleActionResetter() {
04246 if ( mAction )
04247 mAction->setChecked( mOn );
04248 }
04249 void disable() { mAction = 0; }
04250 };
04251 }
04252
04253
04254 void KMComposeWin::slotEncryptBodyChiasmusToggled( bool on ) {
04255 #ifdef KLEO_CHIASMUS
04256 Q_ASSERT( mEncryptChiasmusAction->isEnabled() );
04257 if ( on ) {
04258
04259
04260
04261
04262 if ( mEncryptAction->isChecked() || mSignAction->isChecked() ) {
04263 int ret = KMessageBox::warningContinueCancel( this,
04264 i18n("It is currently not possible to use chiasmus body encryption "
04265 "with signed or otherwise encrypted messages. Do you want to "
04266 "continue with chiasmus body encryption and disable other signature "
04267 "and encryption methods, or cancel, which will not encrypt the body "
04268 "using chiasmus?" ),
04269 i18n("Chiasmus body encryption not possible") );
04270 if ( ret == KMessageBox::Continue ) {
04271 setSigning( false, true );
04272 setEncryption( false, true );
04273 } else {
04274 mEncryptBodyChiasmusAction->setEnabled( false );
04275 return;
04276 }
04277
04278 }
04279 }
04280 mEncryptBodyWithChiasmus = on;
04281 #endif
04282 }
04283
04284 void KMComposeWin::slotEncryptChiasmusToggled( bool on ) {
04285 #ifdef KLEO_CHIASMUS
04286 mEncryptWithChiasmus = false;
04287 mEncryptBodyChiasmusAction->setEnabled( on );
04288 #endif
04289
04290 if ( !on )
04291 return;
04292
04293 #ifdef KLEO_CHIASMUS
04294 KToggleActionResetter resetter( mEncryptChiasmusAction, false );
04295 #endif
04296
04297 #ifndef KLEO_CHIASMUS
04298
04299 KMessageBox::information( this, i18n( "This version of KMail was not compiled "
04300 "with support for Chiasmus. You might want "
04301 "to recompile KMail with --enable-chiasmus." ),
04302 i18n( "Missing Chiasmus Support" ) );
04303 return;
04304
04305 #else
04306
04307 const Kleo::CryptoBackend::Protocol * chiasmus =
04308 Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" );
04309
04310 if ( !chiasmus ) {
04311 const QString msg = Kleo::CryptoBackendFactory::instance()->knowsAboutProtocol( "Chiasmus" )
04312 ? i18n( "Please configure a Crypto Backend to use for "
04313 "Chiasmus encryption first.\n"
04314 "You can do this in the Crypto Backends tab of "
04315 "the configure dialog's Security page." )
04316 : i18n( "It looks as though libkleopatra was compiled without "
04317 "Chiasmus support. You might want to recompile "
04318 "libkleopatra with --enable-chiasmus.");
04319 KMessageBox::information( this, msg, i18n("No Chiasmus Backend Configured" ) );
04320 return;
04321 }
04322
04323 std::auto_ptr<Kleo::SpecialJob> job( chiasmus->specialJob( "x-obtain-keys", QMap<QString,QVariant>() ) );
04324 if ( !job.get() ) {
04325 const QString msg = i18n( "Chiasmus backend does not offer the "
04326 "\"x-obtain-keys\" function. Please report this bug." );
04327 KMessageBox::error( this, msg, i18n( "Chiasmus Backend Error" ) );
04328 return;
04329 }
04330
04331 if ( job->exec() ) {
04332 job->showErrorDialog( this, i18n( "Chiasmus Backend Error" ) );
04333 return;
04334 }
04335
04336 const QVariant result = job->property( "result" );
04337 if ( result.type() != QVariant::StringList ) {
04338 const QString msg = i18n( "Unexpected return value from Chiasmus backend: "
04339 "The \"x-obtain-keys\" function did not return a "
04340 "string list. Please report this bug." );
04341 KMessageBox::error( this, msg, i18n( "Chiasmus Backend Error" ) );
04342 return;
04343 }
04344
04345 const QStringList keys = result.toStringList();
04346 if ( keys.empty() ) {
04347 const QString msg = i18n( "No keys have been found. Please check that a "
04348 "valid key path has been set in the Chiasmus "
04349 "configuration." );
04350 KMessageBox::information( this, msg, i18n( "No Chiasmus Keys Found" ) );
04351 return;
04352 }
04353
04354 ChiasmusKeySelector selectorDlg( this, i18n( "Chiasmus Encryption Key Selection" ),
04355 keys, mChiasmusKey, mChiasmusOptions );
04356 if ( selectorDlg.exec() != QDialog::Accepted )
04357 return;
04358
04359 mChiasmusOptions = selectorDlg.options();
04360 mChiasmusKey = selectorDlg.key();
04361 assert( !mChiasmusKey.isEmpty() );
04362 mEncryptWithChiasmus = true;
04363 resetter.disable();
04364 #endif // KLEO_CHIASMUS
04365 }
04366
04367
04368 void KMComposeWin::slotUpdateSignatureActions()
04369 {
04370
04371
04372 const KPIM::Identity & ident =
04373 kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() );
04374 QString sig = ident.signatureText();
04375
04376 if ( sig.isEmpty() ) {
04377 mAppendSignatureAction->setEnabled( false );
04378 mPrependSignatureAction->setEnabled( false );
04379 mInsertSignatureAction->setEnabled( false );
04380 }
04381 else {
04382 mAppendSignatureAction->setEnabled( true );
04383 mPrependSignatureAction->setEnabled( true );
04384 mInsertSignatureAction->setEnabled( true );
04385 }
04386 }
04387
04388 void KMEdit::contentsDragEnterEvent(QDragEnterEvent *e)
04389 {
04390 if (e->provides(MailListDrag::format()))
04391 e->accept(true);
04392 else
04393 return KEdit::contentsDragEnterEvent(e);
04394 }
04395
04396 void KMEdit::contentsDragMoveEvent(QDragMoveEvent *e)
04397 {
04398 if (e->provides(MailListDrag::format()))
04399 e->accept();
04400 else
04401 return KEdit::contentsDragMoveEvent(e);
04402 }
04403
04404 void KMEdit::keyPressEvent( QKeyEvent* e )
04405 {
04406 if( e->key() == Key_Return ) {
04407 int line, col;
04408 getCursorPosition( &line, &col );
04409 QString lineText = text( line );
04410
04411 lineText.truncate( lineText.length() - 1 );
04412
04413
04414 if( ( col > 0 ) && ( col < int( lineText.length() ) ) ) {
04415 bool isQuotedLine = false;
04416 uint bot = 0;
04417 while( bot < lineText.length() ) {
04418 if( ( lineText[bot] == '>' ) || ( lineText[bot] == '|' ) ) {
04419 isQuotedLine = true;
04420 ++bot;
04421 }
04422 else if( lineText[bot].isSpace() ) {
04423 ++bot;
04424 }
04425 else {
04426 break;
04427 }
04428 }
04429
04430 KEdit::keyPressEvent( e );
04431
04432
04433
04434
04435 if( isQuotedLine
04436 && ( bot != lineText.length() )
04437 && ( col >= int( bot ) ) ) {
04438
04439
04440
04441 getCursorPosition( &line, &col );
04442 QString newLine = text( line );
04443
04444
04445 unsigned int leadingWhiteSpaceCount = 0;
04446 while( ( leadingWhiteSpaceCount < newLine.length() )
04447 && newLine[leadingWhiteSpaceCount].isSpace() ) {
04448 ++leadingWhiteSpaceCount;
04449 }
04450 newLine = newLine.replace( 0, leadingWhiteSpaceCount,
04451 lineText.left( bot ) );
04452 removeParagraph( line );
04453 insertParagraph( newLine, line );
04454
04455
04456
04457 setCursorPosition( line, 0 );
04458 }
04459 }
04460 else
04461 KEdit::keyPressEvent( e );
04462 }
04463 else
04464 KEdit::keyPressEvent( e );
04465 }
04466
04467 void KMEdit::contentsDropEvent(QDropEvent *e)
04468 {
04469 if (e->provides(MailListDrag::format())) {
04470
04471 QByteArray serNums;
04472 MailListDrag::decode( e, serNums );
04473 QBuffer serNumBuffer(serNums);
04474 serNumBuffer.open(IO_ReadOnly);
04475 QDataStream serNumStream(&serNumBuffer);
04476 unsigned long serNum;
04477 KMFolder *folder = 0;
04478 int idx;
04479 QPtrList<KMMsgBase> messageList;
04480 while (!serNumStream.atEnd()) {
04481 KMMsgBase *msgBase = 0;
04482 serNumStream >> serNum;
04483 kmkernel->msgDict()->getLocation(serNum, &folder, &idx);
04484 if (folder)
04485 msgBase = folder->getMsgBase(idx);
04486 if (msgBase)
04487 messageList.append( msgBase );
04488 }
04489 serNumBuffer.close();
04490 uint identity = folder ? folder->identity() : 0;
04491 KMCommand *command =
04492 new KMForwardAttachedCommand(mComposer, messageList,
04493 identity, mComposer);
04494 command->start();
04495 }
04496 else if( KURLDrag::canDecode( e ) ) {
04497 KURL::List urlList;
04498 if( KURLDrag::decode( e, urlList ) ) {
04499 for( KURL::List::Iterator it = urlList.begin();
04500 it != urlList.end(); ++it ) {
04501 mComposer->addAttach( *it );
04502 }
04503 }
04504 }
04505 else {
04506 return KEdit::contentsDropEvent(e);
04507 }
04508 }
04509
04510
04511
04512
04513
04514
04515
04516 KMAtmListViewItem::KMAtmListViewItem(QListView *parent) :
04517 QObject(), QListViewItem( parent )
04518 {
04519
04520 mCBSignEnabled = false;
04521 mCBEncryptEnabled = false;
04522
04523 mListview = parent;
04524 mCBEncrypt = new QCheckBox(mListview->viewport());
04525 mCBSign = new QCheckBox(mListview->viewport());
04526
04527 mCBEncrypt->hide();
04528 mCBSign->hide();
04529 }
04530
04531 KMAtmListViewItem::~KMAtmListViewItem()
04532 {
04533 delete mCBEncrypt;
04534 mCBEncrypt = 0;
04535 delete mCBSign;
04536 mCBSign = 0;
04537 }
04538
04539 void KMAtmListViewItem::paintCell( QPainter * p, const QColorGroup & cg,
04540 int column, int width, int align )
04541 {
04542
04543
04544 QListViewItem::paintCell( p, cg, column, width, align );
04545 if( 4 == column || 5 == column ) {
04546 QRect r = mListview->itemRect( this );
04547 if ( !r.size().isValid() ) {
04548 mListview->ensureItemVisible( this );
04549 mListview->repaintContents( FALSE );
04550 r = mListview->itemRect( this );
04551 }
04552 int colWidth = mListview->header()->sectionSize( column );
04553 r.setX( mListview->header()->sectionPos( column )
04554 - mListview->header()->offset()
04555 + colWidth / 2
04556 - r.height() / 2
04557 - 1 );
04558 r.setY( r.y() + 1 );
04559 r.setWidth( r.height() - 2 );
04560 r.setHeight( r.height() - 2 );
04561 r = QRect( mListview->viewportToContents( r.topLeft() ), r.size() );
04562
04563 QCheckBox* cb = (4 == column) ? mCBEncrypt : mCBSign;
04564 cb->resize( r.size() );
04565 mListview->moveChild( cb, r.x(), r.y() );
04566
04567 QColor bg;
04568 if (isSelected())
04569 bg = cg.highlight();
04570 else
04571 bg = cg.base();
04572
04573 bool enabled = (4 == column) ? mCBEncryptEnabled : mCBSignEnabled;
04574 cb->setPaletteBackgroundColor(bg);
04575 if (enabled) cb->show();
04576 }
04577 }
04578
04579 void KMAtmListViewItem::enableCryptoCBs(bool on)
04580 {
04581 if( mCBEncrypt ) {
04582 mCBEncryptEnabled = on;
04583 mCBEncrypt->setEnabled( on );
04584 mCBEncrypt->setShown( on );
04585 }
04586 if( mCBSign ) {
04587 mCBSignEnabled = on;
04588 mCBSign->setEnabled( on );
04589 mCBSign->setShown( on );
04590 }
04591 }
04592
04593 void KMAtmListViewItem::setEncrypt(bool on)
04594 {
04595 if( mCBEncrypt )
04596 mCBEncrypt->setChecked( on );
04597 }
04598
04599 bool KMAtmListViewItem::isEncrypt()
04600 {
04601 if( mCBEncrypt )
04602 return mCBEncrypt->isChecked();
04603 else
04604 return false;
04605 }
04606
04607 void KMAtmListViewItem::setSign(bool on)
04608 {
04609 if( mCBSign )
04610 mCBSign->setChecked( on );
04611 }
04612
04613 bool KMAtmListViewItem::isSign()
04614 {
04615 if( mCBSign )
04616 return mCBSign->isChecked();
04617 else
04618 return false;
04619 }
04620
04621
04622
04623
04624
04625
04626
04627
04628
04629 KMLineEdit::KMLineEdit(KMComposeWin* composer, bool useCompletion,
04630 QWidget *parent, const char *name)
04631 : KPIM::AddresseeLineEdit(parent,useCompletion,name), mComposer(composer)
04632 {
04633 allowSemiColonAsSeparator( GlobalSettings::allowSemicolonAsAddressSeparator() );
04634 }
04635
04636
04637
04638 void KMLineEdit::keyPressEvent(QKeyEvent *e)
04639 {
04640
04641 if ((e->key() == Key_Enter || e->key() == Key_Return) &&
04642 !completionBox()->isVisible())
04643 {
04644 mComposer->focusNextPrevEdit(this,TRUE);
04645 return;
04646 }
04647 if (e->key() == Key_Up)
04648 {
04649 mComposer->focusNextPrevEdit(this,FALSE);
04650 return;
04651 }
04652 if (e->key() == Key_Down)
04653 {
04654 mComposer->focusNextPrevEdit(this,TRUE);
04655 return;
04656 }
04657
04658 AddresseeLineEdit::keyPressEvent(e);
04659 }
04660
04661 QPopupMenu *KMLineEdit::createPopupMenu()
04662 {
04663 QPopupMenu *menu = KPIM::AddresseeLineEdit::createPopupMenu();
04664 if ( !menu )
04665 return 0;
04666
04667 menu->insertSeparator();
04668 menu->insertItem( i18n( "Edit Recent Addresses..." ),
04669 this, SLOT( editRecentAddresses() ) );
04670
04671 return menu;
04672 }
04673
04674 void KMLineEdit::editRecentAddresses()
04675 {
04676 KRecentAddress::RecentAddressDialog dlg( this );
04677 dlg.setAddresses( RecentAddresses::self( KMKernel::config() )->addresses() );
04678 if ( dlg.exec() ) {
04679 RecentAddresses::self( KMKernel::config() )->clear();
04680 QStringList addrList = dlg.addresses();
04681 QStringList::Iterator it;
04682 for ( it = addrList.begin(); it != addrList.end(); ++it )
04683 RecentAddresses::self( KMKernel::config() )->add( *it );
04684
04685 loadContacts();
04686 }
04687 }
04688
04689
04690
04691 void KMLineEdit::loadContacts()
04692 {
04693
04694 AddresseeLineEdit::loadContacts();
04695
04696 QStringList recent =
04697 RecentAddresses::self( KMKernel::config() )->addresses();
04698 QStringList::Iterator it = recent.begin();
04699 QString name, email;
04700 int idx = addCompletionSource( i18n( "Recent Addresses" ) );
04701 for ( ; it != recent.end(); ++it ) {
04702
04703 KABC::Addressee addr;
04704 KPIM::getNameAndMail(*it, name, email);
04705 addr.setNameFromString( name );
04706 addr.insertEmail( email, true );
04707 addContact( addr, 120, idx );
04708 }
04709 }
04710
04711
04712 KMLineEditSpell::KMLineEditSpell(KMComposeWin* composer, bool useCompletion,
04713 QWidget *parent, const char *name)
04714 : KMLineEdit(composer,useCompletion,parent,name)
04715 {
04716 }
04717
04718
04719 void KMLineEditSpell::highLightWord( unsigned int length, unsigned int pos )
04720 {
04721 setSelection ( pos, length );
04722 }
04723
04724 void KMLineEditSpell::spellCheckDone( const QString &s )
04725 {
04726 if( s != text() )
04727 setText( s );
04728 }
04729
04730 void KMLineEditSpell::spellCheckerMisspelling( const QString &_text, const QStringList&, unsigned int pos)
04731 {
04732 highLightWord( _text.length(),pos );
04733 }
04734
04735 void KMLineEditSpell::spellCheckerCorrected( const QString &old, const QString &corr, unsigned int pos)
04736 {
04737 if( old!= corr )
04738 {
04739 setSelection ( pos, old.length() );
04740 insert( corr );
04741 setSelection ( pos, corr.length() );
04742 emit subjectTextSpellChecked();
04743 }
04744 }
04745
04746
04747
04748
04749
04750
04751
04752 KMEdit::KMEdit(QWidget *parent, KMComposeWin* composer,
04753 KSpellConfig* autoSpellConfig,
04754 const char *name)
04755 : KEdit( parent, name ),
04756 mComposer( composer ),
04757 mKSpell( 0 ),
04758 mSpellingFilter( 0 ),
04759 mExtEditorTempFile( 0 ),
04760 mExtEditorTempFileWatcher( 0 ),
04761 mExtEditorProcess( 0 ),
04762 mUseExtEditor( false ),
04763 mWasModifiedBeforeSpellCheck( false ),
04764 mSpellChecker( 0 ),
04765 mSpellLineEdit( false )
04766 {
04767 installEventFilter(this);
04768 KCursor::setAutoHideCursor( this, true, true );
04769 setOverwriteEnabled( true );
04770
04771 initializeAutoSpellChecking( autoSpellConfig );
04772 }
04773
04774
04775 void KMEdit::initializeAutoSpellChecking( KSpellConfig* autoSpellConfig )
04776 {
04777 if ( mSpellChecker )
04778 return;
04779 KConfigGroup readerConfig( KMKernel::config(), "Reader" );
04780 QColor defaultColor1( 0x00, 0x80, 0x00 );
04781 QColor defaultColor2( 0x00, 0x70, 0x00 );
04782 QColor defaultColor3( 0x00, 0x60, 0x00 );
04783 QColor defaultForeground( kapp->palette().active().text() );
04784 QColor col1;
04785 if (!readerConfig.readBoolEntry("defaultColors",TRUE))
04786 col1 = readerConfig.readColorEntry( "ForegroundColor", &defaultForeground );
04787 else
04788 col1 = defaultForeground;
04789 QColor col2 = readerConfig.readColorEntry( "QuotedText3", &defaultColor3 );
04790 QColor col3 = readerConfig.readColorEntry( "QuotedText2", &defaultColor2 );
04791 QColor col4 = readerConfig.readColorEntry( "QuotedText1", &defaultColor1 );
04792 QColor c = Qt::red;
04793 QColor misspelled = readerConfig.readColorEntry( "MisspelledColor", &c );
04794
04795 mSpellChecker = new KDictSpellingHighlighter( this, true,
04796 false,
04797 misspelled,
04798 true,
04799 col1, col2, col3, col4,
04800 autoSpellConfig );
04801 connect( mSpellChecker, SIGNAL(activeChanged(const QString &)),
04802 mComposer, SLOT(slotStatusMessage(const QString &)));
04803 connect( mSpellChecker, SIGNAL(newSuggestions(const QString&, const QStringList&, unsigned int)),
04804 this, SLOT(addSuggestion(const QString&, const QStringList&, unsigned int)) );
04805 }
04806
04807
04808 void KMEdit::deleteAutoSpellChecking()
04809 {
04810 delete mSpellChecker;
04811 mSpellChecker =0;
04812 }
04813
04814 void KMEdit::addSuggestion(const QString& text, const QStringList& lst, unsigned int )
04815 {
04816 mReplacements[text] = lst;
04817 }
04818
04819 void KMEdit::setSpellCheckingActive(bool spellCheckingActive)
04820 {
04821 if ( mSpellChecker ) {
04822 mSpellChecker->setActive(spellCheckingActive);
04823 }
04824 }
04825
04826
04827 KMEdit::~KMEdit()
04828 {
04829 removeEventFilter(this);
04830
04831 delete mKSpell;
04832 delete mSpellChecker;
04833 mSpellChecker = 0;
04834
04835 }
04836
04837
04838
04839 QString KMEdit::brokenText()
04840 {
04841 QString temp, line;
04842
04843 int num_lines = numLines();
04844 for (int i = 0; i < num_lines; ++i)
04845 {
04846 int lastLine = 0;
04847 line = textLine(i);
04848 for (int j = 0; j < (int)line.length(); ++j)
04849 {
04850 if (lineOfChar(i, j) > lastLine)
04851 {
04852 lastLine = lineOfChar(i, j);
04853 temp += '\n';
04854 }
04855 temp += line[j];
04856 }
04857 if (i + 1 < num_lines) temp += '\n';
04858 }
04859
04860 return temp;
04861 }
04862
04863
04864 bool KMEdit::eventFilter(QObject*o, QEvent* e)
04865 {
04866 if (o == this)
04867 KCursor::autoHideEventFilter(o, e);
04868
04869 if (e->type() == QEvent::KeyPress)
04870 {
04871 QKeyEvent *k = (QKeyEvent*)e;
04872
04873 if (mUseExtEditor) {
04874 if (k->key() == Key_Up)
04875 {
04876 mComposer->focusNextPrevEdit(0, false);
04877 return TRUE;
04878 }
04879
04880
04881 if ( (k->key() == Key_Shift) || (k->key() == Key_Control) ||
04882 (k->key() == Key_Meta) || (k->key() == Key_Alt) )
04883 return true;
04884 if (mExtEditorTempFile) return TRUE;
04885 QString sysLine = mExtEditor;
04886 mExtEditorTempFile = new KTempFile();
04887
04888 mExtEditorTempFile->setAutoDelete(true);
04889
04890 (*mExtEditorTempFile->textStream()) << text();
04891
04892 mExtEditorTempFile->close();
04893
04894 sysLine.replace( "%f", mExtEditorTempFile->name() );
04895 mExtEditorProcess = new KProcess();
04896 sysLine += " ";
04897 while (!sysLine.isEmpty())
04898 {
04899 *mExtEditorProcess << sysLine.left(sysLine.find(" ")).local8Bit();
04900 sysLine.remove(0, sysLine.find(" ") + 1);
04901 }
04902 connect(mExtEditorProcess, SIGNAL(processExited(KProcess*)),
04903 SLOT(slotExternalEditorDone(KProcess*)));
04904 if (!mExtEditorProcess->start())
04905 {
04906 KMessageBox::error( topLevelWidget(),
04907 i18n("Unable to start external editor.") );
04908 killExternalEditor();
04909 } else {
04910 mExtEditorTempFileWatcher = new KDirWatch( this, "mExtEditorTempFileWatcher" );
04911 connect( mExtEditorTempFileWatcher, SIGNAL(dirty(const QString&)),
04912 SLOT(slotExternalEditorTempFileChanged(const QString&)) );
04913 mExtEditorTempFileWatcher->addFile( mExtEditorTempFile->name() );
04914 }
04915 return TRUE;
04916 } else {
04917
04918
04919 if (k->key() == Key_Up && k->state() != ShiftButton && currentLine() == 0
04920 && lineOfChar(0, currentColumn()) == 0)
04921 {
04922 deselect();
04923 mComposer->focusNextPrevEdit(0, false);
04924 return TRUE;
04925 }
04926
04927
04928 if (k->key() == Key_Backtab && k->state() == ShiftButton)
04929 {
04930 deselect();
04931 mComposer->focusNextPrevEdit(0, false);
04932 return TRUE;
04933 }
04934
04935 }
04936 } else if ( e->type() == QEvent::ContextMenu ) {
04937 QContextMenuEvent *event = (QContextMenuEvent*) e;
04938
04939 int para = 1, charPos, firstSpace, lastSpace;
04940
04941
04942 charPos = charAt( viewportToContents(event->pos()), ¶ );
04943 QString paraText = text( para );
04944
04945 if( !paraText.at(charPos).isSpace() )
04946 {
04947
04948 const QRegExp wordBoundary( "[\\s\\W]" );
04949 firstSpace = paraText.findRev( wordBoundary, charPos ) + 1;
04950 lastSpace = paraText.find( wordBoundary, charPos );
04951 if( lastSpace == -1 )
04952 lastSpace = paraText.length();
04953 QString word = paraText.mid( firstSpace, lastSpace - firstSpace );
04954
04955 if( !word.isEmpty() && mReplacements.contains( word ) )
04956 {
04957 KPopupMenu p;
04958 p.insertTitle( i18n("Suggestions") );
04959
04960
04961 QStringList reps = mReplacements[word];
04962 if( reps.count() > 0 )
04963 {
04964 int listPos = 0;
04965 for ( QStringList::Iterator it = reps.begin(); it != reps.end(); ++it ) {
04966 p.insertItem( *it, listPos );
04967 listPos++;
04968 }
04969 }
04970 else
04971 {
04972 p.insertItem( QString::fromLatin1("No Suggestions"), -2 );
04973 }
04974
04975
04976 int id = p.exec( mapToGlobal( event->pos() ) );
04977
04978 if( id > -1 )
04979 {
04980
04981 int parIdx = 1, txtIdx = 1;
04982 getCursorPosition(&parIdx, &txtIdx);
04983 setSelection(para, firstSpace, para, lastSpace);
04984 insert(mReplacements[word][id]);
04985
04986
04987 if ( para == parIdx && txtIdx >= lastSpace )
04988 txtIdx += mReplacements[word][id].length() - word.length();
04989 setCursorPosition(parIdx, txtIdx);
04990 }
04991
04992 return true;
04993 }
04994 }
04995 }
04996
04997 return KEdit::eventFilter(o, e);
04998 }
04999
05000
05001
05002 int KMEdit::autoSpellChecking( bool on )
05003 {
05004 if ( textFormat() == Qt::RichText ) {
05005
05006 if ( on )
05007 KMessageBox::sorry(this, i18n("Automatic spellchecking is not possible on text with markup."));
05008 return -1;
05009 }
05010
05011
05012 mSpellChecker->setAutomatic( on );
05013 mSpellChecker->setActive( on );
05014 return 1;
05015 }
05016
05017
05018
05019 void KMEdit::slotExternalEditorTempFileChanged( const QString & fileName ) {
05020 if ( !mExtEditorTempFile )
05021 return;
05022 if ( fileName != mExtEditorTempFile->name() )
05023 return;
05024
05025 setAutoUpdate(false);
05026 clear();
05027
05028 insertLine(QString::fromLocal8Bit(KPIM::kFileToString( fileName, true, false )), -1);
05029 setAutoUpdate(true);
05030 repaint();
05031 }
05032
05033 void KMEdit::slotExternalEditorDone( KProcess * proc ) {
05034 assert(proc == mExtEditorProcess);
05035
05036 slotExternalEditorTempFileChanged( mExtEditorTempFile->name() );
05037 killExternalEditor();
05038 }
05039
05040 void KMEdit::killExternalEditor() {
05041 delete mExtEditorTempFileWatcher; mExtEditorTempFileWatcher = 0;
05042 delete mExtEditorTempFile; mExtEditorTempFile = 0;
05043 delete mExtEditorProcess; mExtEditorProcess = 0;
05044 }
05045
05046
05047 bool KMEdit::checkExternalEditorFinished() {
05048 if ( !mExtEditorProcess )
05049 return true;
05050 switch ( KMessageBox::warningYesNoCancel( topLevelWidget(),
05051 i18n("The external editor is still running.\n"
05052 "Abort the external editor or leave it open?"),
05053 i18n("External Editor"),
05054 i18n("Abort Editor"), i18n("Leave Editor Open") ) ) {
05055 case KMessageBox::Yes:
05056 killExternalEditor();
05057 return true;
05058 case KMessageBox::No:
05059 return true;
05060 default:
05061 return false;
05062 }
05063 }
05064
05065
05066 void KMEdit::spellcheck()
05067 {
05068 if ( mKSpell )
05069 return;
05070 mWasModifiedBeforeSpellCheck = isModified();
05071 mSpellLineEdit = !mSpellLineEdit;
05072
05073
05074
05075
05076
05077
05078
05079 mKSpell = new KSpell(this, i18n("Spellcheck - KMail"), this,
05080 SLOT(slotSpellcheck2(KSpell*)));
05081
05082
05083 QStringList l = KSpellingHighlighter::personalWords();
05084 for ( QStringList::Iterator it = l.begin(); it != l.end(); ++it ) {
05085 mKSpell->addPersonal( *it );
05086 }
05087 connect (mKSpell, SIGNAL( death()),
05088 this, SLOT (slotSpellDone()));
05089 connect (mKSpell, SIGNAL (misspelling (const QString &, const QStringList &, unsigned int)),
05090 this, SLOT (slotMisspelling (const QString &, const QStringList &, unsigned int)));
05091 connect (mKSpell, SIGNAL (corrected (const QString &, const QString &, unsigned int)),
05092 this, SLOT (slotCorrected (const QString &, const QString &, unsigned int)));
05093 connect (mKSpell, SIGNAL (done(const QString &)),
05094 this, SLOT (slotSpellResult (const QString&)));
05095 }
05096
05097 void KMEdit::cut()
05098 {
05099 KEdit::cut();
05100 if ( textFormat() != Qt::RichText )
05101 mSpellChecker->restartBackgroundSpellCheck();
05102 }
05103
05104 void KMEdit::clear()
05105 {
05106 KEdit::clear();
05107 if ( textFormat() != Qt::RichText )
05108 mSpellChecker->restartBackgroundSpellCheck();
05109 }
05110
05111 void KMEdit::del()
05112 {
05113 KEdit::del();
05114 if ( textFormat() != Qt::RichText )
05115 mSpellChecker->restartBackgroundSpellCheck();
05116 }
05117
05118
05119 void KMEdit::slotMisspelling(const QString &text, const QStringList &lst, unsigned int pos)
05120 {
05121 kdDebug(5006)<<"void KMEdit::slotMisspelling(const QString &text, const QStringList &lst, unsigned int pos) : "<<text <<endl;
05122 if( mSpellLineEdit )
05123 mComposer->sujectLineWidget()->spellCheckerMisspelling( text, lst, pos);
05124 else
05125 misspelling(text, lst, pos);
05126 }
05127
05128 void KMEdit::slotCorrected (const QString &oldWord, const QString &newWord, unsigned int pos)
05129 {
05130 kdDebug(5006)<<"slotCorrected (const QString &oldWord, const QString &newWord, unsigned int pos) : "<<oldWord<<endl;
05131 if( mSpellLineEdit )
05132 mComposer->sujectLineWidget()->spellCheckerCorrected( oldWord, newWord, pos);
05133 else {
05134 unsigned int l = 0;
05135 unsigned int cnt = 0;
05136 bool _bold,_underline,_italic;
05137 QColor _color;
05138 QFont _font;
05139 posToRowCol (pos, l, cnt);
05140 setCursorPosition(l, cnt+1);
05141 _bold = bold();
05142 _underline = underline();
05143 _italic = italic();
05144 _color = color();
05145 _font = currentFont();
05146 corrected(oldWord, newWord, pos);
05147 setSelection (l, cnt, l, cnt+newWord.length());
05148 setBold(_bold);
05149 setItalic(_italic);
05150 setUnderline(_underline);
05151 setColor(_color);
05152 setCurrentFont(_font);
05153 }
05154
05155 }
05156
05157
05158 void KMEdit::slotSpellcheck2(KSpell*)
05159 {
05160 if( !mSpellLineEdit)
05161 {
05162 spellcheck_start();
05163
05164 QString quotePrefix;
05165 if(mComposer && mComposer->msg())
05166 {
05167
05168 KConfig *config=KMKernel::config();
05169 KConfigGroupSaver saver(config, "General");
05170
05171 int languageNr = config->readNumEntry("reply-current-language",0);
05172 config->setGroup( QString("KMMessage #%1").arg(languageNr) );
05173
05174 quotePrefix = config->readEntry("indent-prefix", ">%_");
05175 quotePrefix = mComposer->msg()->formatString(quotePrefix);
05176 }
05177
05178 kdDebug(5006) << "spelling: new SpellingFilter with prefix=\"" << quotePrefix << "\"" << endl;
05179 QTextEdit plaintext;
05180 plaintext.setText(text());
05181 plaintext.setTextFormat(Qt::PlainText);
05182 mSpellingFilter = new SpellingFilter(plaintext.text(), quotePrefix, SpellingFilter::FilterUrls,
05183 SpellingFilter::FilterEmailAddresses);
05184
05185 mKSpell->check(mSpellingFilter->filteredText());
05186 }
05187 else if( mComposer )
05188 mKSpell->check( mComposer->sujectLineWidget()->text());
05189 }
05190
05191
05192 void KMEdit::slotSpellResult(const QString &s)
05193 {
05194 if( !mSpellLineEdit)
05195 spellcheck_stop();
05196
05197 int dlgResult = mKSpell->dlgResult();
05198 if ( dlgResult == KS_CANCEL )
05199 {
05200 if( mSpellLineEdit)
05201 {
05202
05203 mSpellLineEdit = false;
05204 QString tmpText( s );
05205 tmpText = tmpText.remove('\n');
05206
05207 if( tmpText != mComposer->sujectLineWidget()->text() )
05208 mComposer->sujectLineWidget()->setText( tmpText );
05209 }
05210 else
05211 {
05212 setModified(true);
05213 }
05214 }
05215 mKSpell->cleanUp();
05216 KDictSpellingHighlighter::dictionaryChanged();
05217
05218 emit spellcheck_done( dlgResult );
05219 }
05220
05221
05222 void KMEdit::slotSpellDone()
05223 {
05224 kdDebug(5006)<<" void KMEdit::slotSpellDone()\n";
05225 KSpell::spellStatus status = mKSpell->status();
05226 delete mKSpell;
05227 mKSpell = 0;
05228
05229 kdDebug(5006) << "spelling: delete SpellingFilter" << endl;
05230 delete mSpellingFilter;
05231 mSpellingFilter = 0;
05232 mComposer->sujectLineWidget()->deselect();
05233 if (status == KSpell::Error)
05234 {
05235 KMessageBox::sorry( topLevelWidget(),
05236 i18n("ISpell/Aspell could not be started. Please "
05237 "make sure you have ISpell or Aspell properly "
05238 "configured and in your PATH.") );
05239 emit spellcheck_done( KS_CANCEL );
05240 }
05241 else if (status == KSpell::Crashed)
05242 {
05243 spellcheck_stop();
05244 KMessageBox::sorry( topLevelWidget(),
05245 i18n("ISpell/Aspell seems to have crashed.") );
05246 emit spellcheck_done( KS_CANCEL );
05247 }
05248 else
05249 {
05250 if( mSpellLineEdit )
05251 spellcheck();
05252 else if( !mComposer->subjectTextWasSpellChecked() && status == KSpell::FinishedNoMisspellingsEncountered )
05253 KMessageBox::information( topLevelWidget(),
05254 i18n("No misspellings encountered.") );
05255 }
05256 }