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