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