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