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