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