• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepim API Reference
  • KDE Home
  • Contact Us
 

kmail

  • sources
  • kde-4.12
  • kdepim
  • kmail
  • editor
kmcomposewin.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of KMail.
3  * Copyright (c) 2011,2012 Laurent Montel <montel@kde.org>
4  *
5  * Copyright (c) 2009 Constantin Berzan <exit3219@gmail.com>
6  *
7  * Based on KMail code by:
8  * Copyright (c) 1997 Markus Wuebben <markus.wuebben@kde.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License along
21  * with this program; if not, write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  */
24 #include "kmcomposewin.h"
25 
26 // KMail includes
27 #include "job/addressvalidationjob.h"
28 #include "attachmentcontroller.h"
29 #include "messagecomposer/attachment/attachmentmodel.h"
30 #include "attachmentview.h"
31 #include "codecaction.h"
32 #include <messagecomposer/job/emailaddressresolvejob.h>
33 #include "kleo_util.h"
34 #include "kmcommands.h"
35 #include "editor/kmcomposereditor.h"
36 #include "kmkernel.h"
37 #include "settings/globalsettings.h"
38 #include "kmmainwin.h"
39 #include "kmmainwidget.h"
40 #include "mailcomposeradaptor.h" // TODO port all D-Bus stuff...
41 #include "messageviewer/viewer/stl_util.h"
42 #include "messageviewer/utils/util.h"
43 #include "messagecore/utils/stringutil.h"
44 #include "messagecore/attachment/attachmentcollector.h"
45 #include "util.h"
46 #include "editor/snippetwidget.h"
47 #include "templatesconfiguration_kfg.h"
48 #include "foldercollectionmonitor.h"
49 #include "kernel/mailkernel.h"
50 #include "custommimeheader.h"
51 #include "messagecomposer/autocorrection/subjectlineeditwithautocorrection.h"
52 #include "pimcommon/translator/translatorwidget.h"
53 #include "warningwidgets/attachmentmissingwarning.h"
54 #include "job/createnewcontactjob.h"
55 #include "warningwidgets/externaleditorwarning.h"
56 
57 #include "agents/sendlateragent/sendlaterutil.h"
58 #include "agents/sendlateragent/sendlaterdialog.h"
59 #include "agents/sendlateragent/sendlaterinfo.h"
60 
61 // KDEPIM includes
62 #include <libkpgp/kpgpblock.h>
63 #include <libkleo/ui/progressdialog.h>
64 #include <libkleo/ui/keyselectiondialog.h>
65 #include "kleo/cryptobackendfactory.h"
66 #include "kleo/exportjob.h"
67 #include "kleo/specialjob.h"
68 #include <messageviewer/viewer/objecttreeemptysource.h>
69 
70 #ifndef QT_NO_CURSOR
71 #include <messageviewer/utils/kcursorsaver.h>
72 #endif
73 
74 #include <messageviewer/viewer/objecttreeparser.h>
75 #include <messageviewer/viewer/nodehelper.h>
76 //#include "messageviewer/chiasmuskeyselector.h"
77 #include <messageviewer/settings/globalsettings.h>
78 #include <messagecomposer/composer/composer.h>
79 #include <messagecomposer/part/globalpart.h>
80 #include <messagecomposer/part/infopart.h>
81 #include <messagecomposer/part/textpart.h>
82 #include <settings/messagecomposersettings.h>
83 #include <messagecomposer/helper/messagehelper.h>
84 #include <messagecomposer/composer/signaturecontroller.h>
85 #include <messagecomposer/job/inserttextfilejob.h>
86 #include <messagecomposer/composer/composerlineedit.h>
87 #include <messagecore/attachment/attachmentpart.h>
88 #include "messagecore/settings/globalsettings.h"
89 #include <templateparser/templateparser.h>
90 #include <templatesconfiguration.h>
91 #include "messagecore/helpers/nodehelper.h"
92 #include <akonadi/kmime/messagestatus.h>
93 #include "messagecore/helpers/messagehelpers.h"
94 #include "mailcommon/folder/folderrequester.h"
95 #include "mailcommon/folder/foldercollection.h"
96 
97 // LIBKDEPIM includes
98 #include <libkdepim/widgets/nepomukwarning.h>
99 #include <libkdepim/addressline/recentaddresses.h>
100 
101 // KDEPIMLIBS includes
102 #include <akonadi/changerecorder.h>
103 #include <akonadi/itemcreatejob.h>
104 #include <akonadi/entitymimetypefiltermodel.h>
105 #include <akonadi/itemfetchjob.h>
106 #include <kpimutils/email.h>
107 #include <kpimidentities/identitymanager.h>
108 #include <kpimidentities/identitycombo.h>
109 #include <kpimidentities/identity.h>
110 #include <mailtransport/transportcombobox.h>
111 #include <mailtransport/transportmanager.h>
112 #include <mailtransport/transport.h>
113 #include <kmime/kmime_codecs.h>
114 #include <kmime/kmime_message.h>
115 #include <kpimtextedit/selectspecialchar.h>
116 
117 
118 // KDELIBS includes
119 #include <kactioncollection.h>
120 #include <kactionmenu.h>
121 #include <kapplication.h>
122 #include <kcharsets.h>
123 #include <kdebug.h>
124 #include <kdescendantsproxymodel.h>
125 #include <kedittoolbar.h>
126 #include <kinputdialog.h>
127 #include <kmenu.h>
128 #include <kmimetype.h>
129 #include <kmessagebox.h>
130 #include <krecentfilesaction.h>
131 #include <kshortcutsdialog.h>
132 #include <kstandarddirs.h>
133 #include <kstandardshortcut.h>
134 #include <kstatusbar.h>
135 #include <ktempdir.h>
136 #include <ktoggleaction.h>
137 #include <ktoolbar.h>
138 #include <ktoolinvocation.h>
139 #include <sonnet/dictionarycombobox.h>
140 #include <krun.h>
141 #include <KIO/JobUiDelegate>
142 #include <KPrintPreview>
143 #include <KFileDialog>
144 
145 // Qt includes
146 #include <QClipboard>
147 #include <QEvent>
148 #include <QSplitter>
149 #include <QUuid>
150 #include <QDir>
151 #include <QMimeData>
152 #include <QKeyEvent>
153 #include <QTextDocumentWriter>
154 
155 // System includes
156 #include <stdlib.h>
157 #include <unistd.h>
158 #include <fcntl.h>
159 #include <memory>
160 #include <boost/shared_ptr.hpp>
161 
162 // MOC
163 #include "kmcomposewin.moc"
164 
165 using Sonnet::DictionaryComboBox;
166 using MailTransport::TransportManager;
167 using MailTransport::Transport;
168 using KPIM::RecentAddresses;
169 using MessageComposer::KMeditor;
170 
171 KMail::Composer *KMail::makeComposer( const KMime::Message::Ptr &msg, bool lastSignState, bool lastEncryptState, Composer::TemplateContext context,
172  uint identity, const QString & textSelection,
173  const QString & customTemplate ) {
174  return KMComposeWin::create( msg, lastSignState, lastEncryptState, context, identity, textSelection, customTemplate );
175 }
176 
177 KMail::Composer *KMComposeWin::create( const KMime::Message::Ptr &msg, bool lastSignState, bool lastEncryptState, Composer::TemplateContext context,
178  uint identity, const QString & textSelection,
179  const QString & customTemplate ) {
180  return new KMComposeWin( msg, lastSignState, lastEncryptState, context, identity, textSelection, customTemplate );
181 }
182 
183 int KMComposeWin::s_composerNumber = 0;
184 
185 //-----------------------------------------------------------------------------
186 KMComposeWin::KMComposeWin( const KMime::Message::Ptr &aMsg, bool lastSignState, bool lastEncryptState, Composer::TemplateContext context, uint id,
187  const QString & textSelection, const QString & customTemplate )
188  : KMail::Composer( "kmail-composer#" ),
189  mDone( false ),
190  mTextSelection( textSelection ),
191  mCustomTemplate( customTemplate ),
192  mSigningAndEncryptionExplicitlyDisabled( false ),
193  mFolder( Akonadi::Collection( -1 ) ),
194  mForceDisableHtml( false ),
195  mId( id ),
196  mContext( context ),
197  mSignAction( 0 ), mEncryptAction( 0 ), mRequestMDNAction( 0 ),
198  mUrgentAction( 0 ), mAllFieldsAction( 0 ), mFromAction( 0 ),
199  mReplyToAction( 0 ), mSubjectAction( 0 ),
200  mIdentityAction( 0 ), mTransportAction( 0 ), mFccAction( 0 ),
201  mWordWrapAction( 0 ), mFixedFontAction( 0 ), mAutoSpellCheckingAction( 0 ),
202  mDictionaryAction( 0 ), mSnippetAction( 0 ), mTranslateAction(0),
203  mCodecAction( 0 ),
204  mCryptoModuleAction( 0 ),
205  mFindText( 0 ),
206  mFindNextText( 0 ),
207  mReplaceText( 0 ),
208  mSelectAll( 0 ),
209  mLowerCase( 0 ),
210  mUpperCase( 0 ),
211  //mEncryptChiasmusAction( 0 ),
212  mDummyComposer( 0 ),
213  mLabelWidth( 0 ),
214  mComposerBase( 0 ),
215  mSelectSpecialChar( 0 ),
216  mSignatureStateIndicator( 0 ), mEncryptionStateIndicator( 0 ),
217  mPreventFccOverwrite( false ),
218  mCheckForForgottenAttachments( true ),
219  mIgnoreStickyFields( false ),
220  mWasModified( false )
221 {
222 
223  mComposerBase = new MessageComposer::ComposerViewBase( this, this );
224  mComposerBase->setIdentityManager( kmkernel->identityManager() );
225 
226  connect( mComposerBase, SIGNAL(disableHtml(MessageComposer::ComposerViewBase::Confirmation)),
227  this, SLOT(disableHtml(MessageComposer::ComposerViewBase::Confirmation)) );
228 
229  connect( mComposerBase, SIGNAL(enableHtml()),
230  this, SLOT(enableHtml()) );
231  connect( mComposerBase, SIGNAL(failed(QString,MessageComposer::ComposerViewBase::FailedType)), this, SLOT(slotSendFailed(QString,MessageComposer::ComposerViewBase::FailedType)) );
232  connect( mComposerBase, SIGNAL(sentSuccessfully()), this, SLOT(slotSendSuccessful()) );
233  connect( mComposerBase, SIGNAL(modified(bool)), this, SLOT(setModified(bool)) );
234 
235  (void) new MailcomposerAdaptor( this );
236  mdbusObjectPath = QLatin1String("/Composer_") + QString::number( ++s_composerNumber );
237  QDBusConnection::sessionBus().registerObject( mdbusObjectPath, this );
238 
239  MessageComposer::SignatureController* sigController = new MessageComposer::SignatureController( this );
240  connect( sigController, SIGNAL(enableHtml()), SLOT(enableHtml()) );
241  mComposerBase->setSignatureController( sigController );
242 
243  if ( kmkernel->xmlGuiInstance().isValid() ) {
244  setComponentData( kmkernel->xmlGuiInstance() );
245  }
246  mMainWidget = new QWidget( this );
247  // splitter between the headers area and the actual editor
248  mHeadersToEditorSplitter = new QSplitter( Qt::Vertical, mMainWidget );
249  mHeadersToEditorSplitter->setObjectName( QLatin1String("mHeadersToEditorSplitter") );
250  mHeadersToEditorSplitter->setChildrenCollapsible( false );
251  mHeadersArea = new QWidget( mHeadersToEditorSplitter );
252  mHeadersArea->setSizePolicy( mHeadersToEditorSplitter->sizePolicy().horizontalPolicy(),
253  QSizePolicy::Expanding );
254  mHeadersToEditorSplitter->addWidget( mHeadersArea );
255  QList<int> defaultSizes;
256  defaultSizes << 0;
257  mHeadersToEditorSplitter->setSizes( defaultSizes );
258 
259 
260 
261  QVBoxLayout *v = new QVBoxLayout( mMainWidget );
262  if ( !KPIM::NepomukWarning::missingNepomukWarning( "kmail-composer" ) ) {
263  KPIM::NepomukWarning *nepomukWarning = new KPIM::NepomukWarning( "kmail-composer", this );
264  nepomukWarning->setMissingFeatures( QStringList() << i18n("Recipient auto-completion") << i18n("Distribution lists") << i18n("Per-contact crypto preferences") );
265  v->addWidget( nepomukWarning );
266  }
267  v->setMargin(0);
268  v->addWidget( mHeadersToEditorSplitter );
269  KPIMIdentities::IdentityCombo* identity = new KPIMIdentities::IdentityCombo( kmkernel->identityManager(),
270  mHeadersArea );
271  identity->setToolTip( i18n( "Select an identity for this message" ) );
272  mComposerBase->setIdentityCombo( identity );
273 
274  sigController->setIdentityCombo( identity );
275  sigController->suspend(); // we have to do identity change tracking ourselves due to the template code
276 
277  mDictionaryCombo = new DictionaryComboBox( mHeadersArea );
278  mDictionaryCombo->setToolTip( i18n( "Select the dictionary to use when spell-checking this message" ) );
279 
280  mFccFolder = new MailCommon::FolderRequester( mHeadersArea );
281  mFccFolder->setNotAllowToCreateNewFolder( true );
282  mFccFolder->setMustBeReadWrite( true );
283 
284 
285  mFccFolder->setToolTip( i18n( "Select the sent-mail folder where a copy of this message will be saved" ) );
286  connect( mFccFolder, SIGNAL(folderChanged(Akonadi::Collection)),
287  this, SLOT(slotFccFolderChanged(Akonadi::Collection)) );
288 
289  MailTransport::TransportComboBox* transport = new MailTransport::TransportComboBox( mHeadersArea );
290  transport->setToolTip( i18n( "Select the outgoing account to use for sending this message" ) );
291  mComposerBase->setTransportCombo( transport );
292 
293  mEdtFrom = new MessageComposer::ComposerLineEdit( false, mHeadersArea );
294  mEdtFrom->setObjectName( QLatin1String("fromLine") );
295  mEdtFrom->setRecentAddressConfig( MessageComposer::MessageComposerSettings::self()->config() );
296  mEdtFrom->setToolTip( i18n( "Set the \"From:\" email address for this message" ) );
297  mEdtReplyTo = new MessageComposer::ComposerLineEdit( true, mHeadersArea );
298  mEdtReplyTo->setObjectName( QLatin1String("replyToLine") );
299  mEdtReplyTo->setRecentAddressConfig( MessageComposer::MessageComposerSettings::self()->config() );
300  mEdtReplyTo->setToolTip( i18n( "Set the \"Reply-To:\" email address for this message" ) );
301  connect( mEdtReplyTo, SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
302  SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)) );
303 
304  MessageComposer::RecipientsEditor* recipientsEditor = new MessageComposer::RecipientsEditor( mHeadersArea );
305  recipientsEditor->setRecentAddressConfig( MessageComposer::MessageComposerSettings::self()->config() );
306  connect( recipientsEditor,
307  SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
308  SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)) );
309  connect( recipientsEditor, SIGNAL(sizeHintChanged()), SLOT(recipientEditorSizeHintChanged()) );
310  mComposerBase->setRecipientsEditor( recipientsEditor );
311 
312  mEdtSubject = new MessageComposer::SubjectLineEditWithAutoCorrection( mHeadersArea, QLatin1String( "kmail2rc" ) );
313  mEdtSubject->setActivateLanguageMenu(false);
314  mEdtSubject->setToolTip( i18n( "Set a subject for this message" ) );
315  mEdtSubject->setAutocorrection(KMKernel::self()->composerAutoCorrection());
316  mLblIdentity = new QLabel( i18n("&Identity:"), mHeadersArea );
317  mDictionaryLabel = new QLabel( i18n("&Dictionary:"), mHeadersArea );
318  mLblFcc = new QLabel( i18n("&Sent-Mail folder:"), mHeadersArea );
319  mLblTransport = new QLabel( i18n("&Mail transport:"), mHeadersArea );
320  mLblFrom = new QLabel( i18nc("sender address field", "&From:"), mHeadersArea );
321  mLblReplyTo = new QLabel( i18n("&Reply to:"), mHeadersArea );
322  mLblSubject = new QLabel( i18nc("@label:textbox Subject of email.", "S&ubject:"), mHeadersArea );
323  QString sticky = i18nc("@option:check Sticky identity.", "Sticky");
324  mBtnIdentity = new QCheckBox( sticky, mHeadersArea );
325  mBtnIdentity->setToolTip( i18n( "Use the selected value as your identity for future messages" ) );
326  mBtnFcc = new QCheckBox( sticky, mHeadersArea );
327  mBtnFcc->setToolTip( i18n( "Use the selected value as your sent-mail folder for future messages" ) );
328  mBtnTransport = new QCheckBox( sticky, mHeadersArea );
329  mBtnTransport->setToolTip( i18n( "Use the selected value as your outgoing account for future messages" ) );
330  mBtnDictionary = new QCheckBox( sticky, mHeadersArea );
331  mBtnDictionary->setToolTip( i18n( "Use the selected value as your dictionary for future messages" ) );
332 
333  mShowHeaders = GlobalSettings::self()->headers();
334  mDone = false;
335  mGrid = 0;
336  mFixedFontAction = 0;
337  // the attachment view is separated from the editor by a splitter
338  mSplitter = new QSplitter( Qt::Vertical, mMainWidget );
339  mSplitter->setObjectName( QLatin1String("mSplitter") );
340  mSplitter->setChildrenCollapsible( false );
341  mSnippetSplitter = new QSplitter( Qt::Horizontal, mSplitter );
342  mSnippetSplitter->setObjectName( QLatin1String("mSnippetSplitter") );
343  mSnippetSplitter->setChildrenCollapsible( false );
344  mSplitter->addWidget( mSnippetSplitter );
345 
346  QWidget *editorAndCryptoStateIndicators = new QWidget( mSplitter );
347  QVBoxLayout *vbox = new QVBoxLayout( editorAndCryptoStateIndicators );
348  vbox->setMargin(0);
349  QHBoxLayout *hbox = new QHBoxLayout();
350  {
351  hbox->setMargin(0);
352  mSignatureStateIndicator = new QLabel( editorAndCryptoStateIndicators );
353  mSignatureStateIndicator->setAlignment( Qt::AlignHCenter );
354  hbox->addWidget( mSignatureStateIndicator );
355  // Get the colors for the label
356  QPalette p( mSignatureStateIndicator->palette() );
357  KColorScheme scheme( QPalette::Active, KColorScheme::View );
358  QColor defaultSignedColor = // pgp signed
359  scheme.background( KColorScheme::PositiveBackground ).color();
360  QColor defaultEncryptedColor( 0x00, 0x80, 0xFF ); // light blue // pgp encrypted
361  QColor signedColor = defaultSignedColor;
362  QColor encryptedColor = defaultEncryptedColor;
363  if ( !MessageCore::GlobalSettings::self()->useDefaultColors() ) {
364  signedColor = MessageCore::GlobalSettings::self()->pgpSignedMessageColor();
365  encryptedColor = MessageCore::GlobalSettings::self()->pgpEncryptedMessageColor();
366  }
367 
368  p.setColor( QPalette::Window, signedColor );
369  mSignatureStateIndicator->setPalette( p );
370  mSignatureStateIndicator->setAutoFillBackground( true );
371 
372  mEncryptionStateIndicator = new QLabel( editorAndCryptoStateIndicators );
373  mEncryptionStateIndicator->setAlignment( Qt::AlignHCenter );
374  hbox->addWidget( mEncryptionStateIndicator );
375  p.setColor( QPalette::Window, encryptedColor);
376  mEncryptionStateIndicator->setPalette( p );
377  mEncryptionStateIndicator->setAutoFillBackground( true );
378  }
379 
380  KMComposerEditor* editor = new KMComposerEditor( this, editorAndCryptoStateIndicators );
381  connect( editor, SIGNAL(textChanged()),
382  this, SLOT(slotEditorTextChanged()) );
383  mComposerBase->setEditor( editor );
384  vbox->addLayout( hbox );
385  vbox->addWidget( editor );
386 
387  mSnippetSplitter->insertWidget( 0, editorAndCryptoStateIndicators );
388  mSnippetSplitter->setOpaqueResize( true );
389  sigController->setEditor( editor );
390 
391  mHeadersToEditorSplitter->addWidget( mSplitter );
392  editor->setAcceptDrops( true );
393  connect(sigController, SIGNAL(signatureAdded()), mComposerBase->editor(), SLOT(startExternalEditor()));
394 
395  connect( mDictionaryCombo, SIGNAL(dictionaryChanged(QString)),
396  this, SLOT(slotSpellCheckingLanguage(QString)) );
397 
398  connect( editor, SIGNAL(languageChanged(QString)),
399  this, SLOT(slotLanguageChanged(QString)) );
400  connect( editor, SIGNAL(spellCheckStatus(QString)),
401  this, SLOT(slotSpellCheckingStatus(QString)) );
402  connect( editor, SIGNAL(insertModeChanged()),
403  this, SLOT(slotOverwriteModeChanged()) );
404 #ifdef HAVE_FORCESPELLCHECKING
405  connect(editor,SIGNAL(spellCheckingFinished()),this,SLOT(slotCheckSendNow()));
406 #endif
407  mSnippetWidget = new SnippetWidget( editor, actionCollection(), mSnippetSplitter );
408  mSnippetWidget->setVisible( GlobalSettings::self()->showSnippetManager() );
409  mSnippetSplitter->addWidget( mSnippetWidget );
410  mSnippetSplitter->setCollapsible( 0, false );
411 
412  mSplitter->setOpaqueResize( true );
413 
414  mBtnIdentity->setWhatsThis( GlobalSettings::self()->stickyIdentityItem()->whatsThis() );
415  mBtnFcc->setWhatsThis( GlobalSettings::self()->stickyFccItem()->whatsThis() );
416  mBtnTransport->setWhatsThis( GlobalSettings::self()->stickyTransportItem()->whatsThis() );
417  mBtnDictionary->setWhatsThis( GlobalSettings::self()->stickyDictionaryItem()->whatsThis() );
418 
419  setCaption( i18n("Composer") );
420  setMinimumSize( 200, 200 );
421 
422  mBtnIdentity->setFocusPolicy( Qt::NoFocus );
423  mBtnFcc->setFocusPolicy( Qt::NoFocus );
424  mBtnTransport->setFocusPolicy( Qt::NoFocus );
425  mBtnDictionary->setFocusPolicy( Qt::NoFocus );
426 
427  mTranslatorWidget = new PimCommon::TranslatorWidget(this);
428  connect(mTranslatorWidget,SIGNAL(translatorWasClosed()),this,SLOT(slotTranslatorWasClosed()));
429  mSplitter->addWidget(mTranslatorWidget);
430 
431  MessageComposer::AttachmentModel* attachmentModel = new MessageComposer::AttachmentModel( this );
432  KMail::AttachmentView *attachmentView = new KMail::AttachmentView( attachmentModel, mSplitter );
433  attachmentView->hideIfEmpty();
434  connect(attachmentView,SIGNAL(modified(bool)),SLOT(setModified(bool)));
435  KMail::AttachmentController* attachmentController = new KMail::AttachmentController( attachmentModel, attachmentView, this );
436 
437  mComposerBase->setAttachmentModel( attachmentModel );
438  mComposerBase->setAttachmentController( attachmentController );
439 
440  mAttachmentMissing = new AttachmentMissingWarning(this);
441  connect(mAttachmentMissing, SIGNAL(attachMissingFile()), this, SLOT(slotAttachMissingFile()));
442  connect(mAttachmentMissing, SIGNAL(closeAttachMissingFile()), this, SLOT(slotCloseAttachMissingFile()));
443  connect(mAttachmentMissing, SIGNAL(explicitClosedMissingAttachment()), this, SLOT(slotExplicitClosedMissingAttachment()));
444  v->addWidget(mAttachmentMissing);
445 
446  m_verifyMissingAttachment = new QTimer(this);
447  m_verifyMissingAttachment->start(1000*5);
448  connect( m_verifyMissingAttachment, SIGNAL(timeout()), this, SLOT(slotVerifyMissingAttachmentTimeout()) );
449  connect( attachmentController, SIGNAL(fileAttached()), mAttachmentMissing, SLOT(slotFileAttached()) );
450 
451  mExternalEditorWarning = new ExternalEditorWarning(this);
452  v->addWidget(mExternalEditorWarning);
453 
454  readConfig();
455  setupStatusBar(attachmentView->widget());
456  setupActions();
457  setupEditor();
458  rethinkFields();
459  slotUpdateSignatureAndEncrypionStateIndicators();
460 
461  applyMainWindowSettings( KMKernel::self()->config()->group( "Composer") );
462 
463  connect( mEdtSubject, SIGNAL(textChanged()),
464  SLOT(slotUpdWinTitle()) );
465  connect( identity, SIGNAL(identityChanged(uint)),
466  SLOT(slotIdentityChanged(uint)) );
467  connect( kmkernel->identityManager(), SIGNAL(changed(uint)),
468  SLOT(slotIdentityChanged(uint)) );
469 
470  connect( mEdtFrom, SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
471  SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)) );
472  connect( kmkernel->folderCollectionMonitor(), SIGNAL(collectionRemoved(Akonadi::Collection)),
473  SLOT(slotFolderRemoved(Akonadi::Collection)) );
474  connect( kmkernel, SIGNAL(configChanged()),
475  this, SLOT(slotConfigChanged()) );
476 
477  mMainWidget->resize( 480, 510 );
478  setCentralWidget( mMainWidget );
479 
480  if ( GlobalSettings::self()->useHtmlMarkup() )
481  enableHtml();
482  else
483  disableHtml( MessageComposer::ComposerViewBase::LetUserConfirm );
484 
485  if ( GlobalSettings::self()->useExternalEditor() ) {
486  editor->setUseExternalEditor( true );
487  editor->setExternalEditorPath( GlobalSettings::self()->externalEditor() );
488  }
489 
490  if ( aMsg ) {
491  setMessage( aMsg, lastSignState, lastEncryptState );
492  }
493 
494  mComposerBase->recipientsEditor()->setFocus();
495  editor->updateActionStates(); // set toolbar buttons to correct values
496 
497  mDone = true;
498 
499  mDummyComposer = new MessageComposer::Composer( this );
500  mDummyComposer->globalPart()->setParentWidgetForGui( this );
501 }
502 
503 //-----------------------------------------------------------------------------
504 KMComposeWin::~KMComposeWin()
505 {
506  writeConfig();
507 
508  // When we have a collection set, store the message back to that collection.
509  // Note that when we save the message or sent it, mFolder is set back to 0.
510  // So this for example kicks in when opening a draft and then closing the window.
511  if ( mFolder.isValid() && mMsg && isModified() ) {
512  Akonadi::Item item;
513  item.setPayload( mMsg );
514  item.setMimeType( KMime::Message::mimeType() );
515  MessageStatus status;
516  status.setRead();
517  item.setFlags( status.statusFlags() );
518  new Akonadi::ItemCreateJob( item, mFolder );
519  // FIXME: listen to the result signal. The whole thing needs to be moved
520  // out of the destructor for this
521  }
522 
523  delete mComposerBase;
524 }
525 
526 
527 void KMComposeWin::slotSpellCheckingLanguage(const QString& language)
528 {
529  mComposerBase->editor()->setSpellCheckingLanguage(language );
530  mEdtSubject->setSpellCheckingLanguage(language );
531 }
532 
533 QString KMComposeWin::dbusObjectPath() const
534 {
535  return mdbusObjectPath;
536 }
537 
538 void KMComposeWin::slotEditorTextChanged()
539 {
540  const bool textIsNotEmpty = !mComposerBase->editor()->document()->isEmpty();
541  mFindText->setEnabled( textIsNotEmpty );
542  mFindNextText->setEnabled( textIsNotEmpty );
543  mReplaceText->setEnabled( textIsNotEmpty );
544  mSelectAll->setEnabled( textIsNotEmpty );
545 }
546 
547 //-----------------------------------------------------------------------------
548 void KMComposeWin::send( int how )
549 {
550  switch ( how ) {
551  case 1:
552  slotSendNow();
553  break;
554  default:
555  case 0:
556  // TODO: find out, what the default send method is and send it this way
557  case 2:
558  slotSendLater();
559  break;
560  }
561 }
562 
563 //-----------------------------------------------------------------------------
564 void KMComposeWin::addAttachmentsAndSend( const KUrl::List &urls, const QString &comment, int how )
565 {
566  kDebug() << "addAttachment and sending!";
567  const int nbUrl = urls.count();
568  for ( int i =0; i < nbUrl; ++i ) {
569  mComposerBase->addAttachmentUrlSync( urls[i], comment );
570  }
571 
572  send( how );
573 }
574 
575 //-----------------------------------------------------------------------------
576 void KMComposeWin::addAttachment( const KUrl &url, const QString &comment )
577 {
578  mComposerBase->addAttachment( url, comment );
579 }
580 
581 
582 void KMComposeWin::addAttachment( const QString& name,
583  KMime::Headers::contentEncoding cte,
584  const QString& charset,
585  const QByteArray& data,
586  const QByteArray& mimeType )
587 {
588  Q_UNUSED( cte );
589  mComposerBase->addAttachment( name, name, charset, data, mimeType );
590 }
591 
592 //-----------------------------------------------------------------------------
593 void KMComposeWin::readConfig( bool reload /* = false */ )
594 {
595  mBtnIdentity->setChecked( GlobalSettings::self()->stickyIdentity() );
596  if (mBtnIdentity->isChecked()) {
597  mId = ( GlobalSettings::self()->previousIdentity() != 0 ) ?
598  GlobalSettings::self()->previousIdentity() : mId;
599  }
600  mBtnFcc->setChecked( GlobalSettings::self()->stickyFcc() );
601  mBtnTransport->setChecked( GlobalSettings::self()->stickyTransport() );
602  const int currentTransport = GlobalSettings::self()->currentTransport().isEmpty() ? -1 : GlobalSettings::self()->currentTransport().toInt();
603  mBtnDictionary->setChecked( GlobalSettings::self()->stickyDictionary() );
604 
605  mEdtFrom->setCompletionMode( (KGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
606  mComposerBase->recipientsEditor()->setCompletionMode( (KGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
607  mEdtReplyTo->setCompletionMode( (KGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
608 
609  if ( MessageCore::GlobalSettings::self()->useDefaultFonts() ) {
610  mBodyFont = KGlobalSettings::generalFont();
611  mFixedFont = KGlobalSettings::fixedFont();
612  } else {
613  mBodyFont = GlobalSettings::self()->composerFont();
614  mFixedFont = MessageViewer::GlobalSettings::self()->fixedFont();
615  }
616 
617  slotUpdateFont();
618  mEdtFrom->setFont( mBodyFont );
619  mEdtReplyTo->setFont( mBodyFont );
620  mEdtSubject->setFont( mBodyFont );
621 
622  if ( !reload ) {
623  QSize siz = GlobalSettings::self()->composerSize();
624  if ( siz.width() < 200 ) {
625  siz.setWidth( 200 );
626  }
627  if ( siz.height() < 200 ) {
628  siz.setHeight( 200 );
629  }
630  resize( siz );
631 
632  if ( !GlobalSettings::self()->snippetSplitterPosition().isEmpty() ) {
633  mSnippetSplitter->setSizes( GlobalSettings::self()->snippetSplitterPosition() );
634  } else {
635  QList<int> defaults;
636  defaults << (int)(width() * 0.8) << (int)(width() * 0.2);
637  mSnippetSplitter->setSizes( defaults );
638  }
639  }
640 
641  mComposerBase->identityCombo()->setCurrentIdentity( mId );
642  kDebug() << mComposerBase->identityCombo()->currentIdentityName();
643  const KPIMIdentities::Identity & ident =
644  kmkernel->identityManager()->identityForUoid( mId );
645 
646  if ( mBtnTransport->isChecked() && currentTransport != -1 ) {
647  const Transport *transport = TransportManager::self()->transportById( currentTransport );
648  if ( transport )
649  mComposerBase->transportComboBox()->setCurrentTransport( transport->id() );
650  }
651 
652  mComposerBase->setAutoSaveInterval( GlobalSettings::self()->autosaveInterval() * 1000 * 60 );
653 
654 
655  if ( mBtnDictionary->isChecked() ) {
656  mDictionaryCombo->setCurrentByDictionaryName( GlobalSettings::self()->previousDictionary() );
657  } else {
658  mDictionaryCombo->setCurrentByDictionaryName( ident.dictionary() );
659  }
660 
661  QString fccName;
662  if ( mBtnFcc->isChecked() ) {
663  fccName = GlobalSettings::self()->previousFcc();
664  } else if ( !ident.fcc().isEmpty() ) {
665  fccName = ident.fcc();
666  }
667  setFcc( fccName );
668 }
669 
670 //-----------------------------------------------------------------------------
671 void KMComposeWin::writeConfig( void )
672 {
673  GlobalSettings::self()->setHeaders( mShowHeaders );
674  GlobalSettings::self()->setStickyFcc( mBtnFcc->isChecked() );
675  if ( !mIgnoreStickyFields ) {
676  GlobalSettings::self()->setCurrentTransport( mComposerBase->transportComboBox()->currentText() );
677  GlobalSettings::self()->setStickyTransport( mBtnTransport->isChecked() );
678  GlobalSettings::self()->setStickyDictionary( mBtnDictionary->isChecked() );
679  GlobalSettings::self()->setStickyIdentity( mBtnIdentity->isChecked() );
680  GlobalSettings::self()->setPreviousIdentity( mComposerBase->identityCombo()->currentIdentity() );
681  }
682  GlobalSettings::self()->setPreviousFcc( QString::number(mFccFolder->collection().id()) );
683  GlobalSettings::self()->setPreviousDictionary( mDictionaryCombo->currentDictionaryName() );
684  GlobalSettings::self()->setAutoSpellChecking(
685  mAutoSpellCheckingAction->isChecked() );
686  MessageViewer::GlobalSettings::self()->setUseFixedFont( mFixedFontAction->isChecked() );
687  if ( !mForceDisableHtml )
688  GlobalSettings::self()->setUseHtmlMarkup( mComposerBase->editor()->textMode() == KMeditor::Rich );
689  GlobalSettings::self()->setComposerSize( size() );
690  GlobalSettings::self()->setShowSnippetManager( mSnippetAction->isChecked() );
691 
692  saveMainWindowSettings( KMKernel::self()->config()->group( "Composer" ) );
693  if ( mSnippetAction->isChecked() )
694  GlobalSettings::setSnippetSplitterPosition( mSnippetSplitter->sizes() );
695 
696  // make sure config changes are written to disk, cf. bug 127538
697  KMKernel::self()->slotSyncConfig();
698 }
699 
700 MessageComposer::Composer* KMComposeWin::createSimpleComposer()
701 {
702  QList< QByteArray > charsets = mCodecAction->mimeCharsets();
703  if( !mOriginalPreferredCharset.isEmpty() ) {
704  charsets.insert( 0, mOriginalPreferredCharset );
705  }
706  mComposerBase->setFrom( from() );
707  mComposerBase->setReplyTo( replyTo() );
708  mComposerBase->setSubject( subject() );
709  mComposerBase->setCharsets( charsets );
710  return mComposerBase->createSimpleComposer();
711 }
712 
713 //-----------------------------------------------------------------------------
714 void KMComposeWin::slotView( void )
715 {
716  if ( !mDone ) {
717  return; // otherwise called from rethinkFields during the construction
718  // which is not the intended behavior
719  }
720 
721  //This sucks awfully, but no, I cannot get an activated(int id) from
722  // actionContainer()
723  KToggleAction *act = ::qobject_cast<KToggleAction *>( sender() );
724  if ( !act ) {
725  return;
726  }
727  int id;
728 
729  if ( act == mAllFieldsAction ) {
730  id = 0;
731  } else if ( act == mIdentityAction ) {
732  id = HDR_IDENTITY;
733  } else if ( act == mTransportAction ) {
734  id = HDR_TRANSPORT;
735  } else if ( act == mFromAction ) {
736  id = HDR_FROM;
737  } else if ( act == mReplyToAction ) {
738  id = HDR_REPLY_TO;
739  } else if ( act == mSubjectAction ) {
740  id = HDR_SUBJECT;
741  } else if ( act == mFccAction ) {
742  id = HDR_FCC;
743  } else if ( act == mDictionaryAction ) {
744  id = HDR_DICTIONARY;
745  } else {
746  id = 0;
747  kDebug() <<"Something is wrong (Oh, yeah?)";
748  return;
749  }
750 
751  // sanders There's a bug here this logic doesn't work if no
752  // fields are shown and then show all fields is selected.
753  // Instead of all fields being shown none are.
754  if ( !act->isChecked() ) {
755  // hide header
756  if ( id > 0 ) {
757  mShowHeaders = mShowHeaders & ~id;
758  } else {
759  mShowHeaders = abs( mShowHeaders );
760  }
761  } else {
762  // show header
763  if ( id > 0 ) {
764  mShowHeaders |= id;
765  } else {
766  mShowHeaders = -abs( mShowHeaders );
767  }
768  }
769  rethinkFields( true );
770 }
771 
772 int KMComposeWin::calcColumnWidth( int which, long allShowing, int width ) const
773 {
774  if ( ( allShowing & which ) == 0 ) {
775  return width;
776  }
777 
778  QLabel *w;
779  if ( which == HDR_IDENTITY ) {
780  w = mLblIdentity;
781  } else if ( which == HDR_DICTIONARY ) {
782  w = mDictionaryLabel;
783  } else if ( which == HDR_FCC ) {
784  w = mLblFcc;
785  } else if ( which == HDR_TRANSPORT ) {
786  w = mLblTransport;
787  } else if ( which == HDR_FROM ) {
788  w = mLblFrom;
789  } else if ( which == HDR_REPLY_TO ) {
790  w = mLblReplyTo;
791  } else if ( which == HDR_SUBJECT ) {
792  w = mLblSubject;
793  } else {
794  return width;
795  }
796 
797  w->setBuddy( mComposerBase->editor() ); // set dummy so we don't calculate width of '&' for this label.
798  w->adjustSize();
799  w->show();
800  return qMax( width, w->sizeHint().width() );
801 }
802 
803 void KMComposeWin::rethinkFields( bool fromSlot )
804 {
805  //This sucks even more but again no ids. sorry (sven)
806  int mask, row;
807  long showHeaders;
808 
809  if ( mShowHeaders < 0 ) {
810  showHeaders = HDR_ALL;
811  } else {
812  showHeaders = mShowHeaders;
813  }
814 
815  for ( mask=1, mNumHeaders=0; mask<=showHeaders; mask<<=1 ) {
816  if ( ( showHeaders & mask ) != 0 ) {
817  mNumHeaders++;
818  }
819  }
820 
821  delete mGrid;
822  mGrid = new QGridLayout( mHeadersArea );
823  mGrid->setSpacing( KDialog::spacingHint() );
824  mGrid->setMargin( KDialog::marginHint() / 2 );
825  mGrid->setColumnStretch( 0, 1 );
826  mGrid->setColumnStretch( 1, 100 );
827  mGrid->setColumnStretch( 2, 1 );
828  mGrid->setRowStretch( mNumHeaders + 1, 100 );
829 
830  row = 0;
831  kDebug();
832 
833  mLabelWidth = mComposerBase->recipientsEditor()->setFirstColumnWidth( 0 );
834  mLabelWidth = calcColumnWidth( HDR_IDENTITY, showHeaders, mLabelWidth );
835  mLabelWidth = calcColumnWidth( HDR_DICTIONARY, showHeaders, mLabelWidth );
836  mLabelWidth = calcColumnWidth( HDR_FCC, showHeaders, mLabelWidth );
837  mLabelWidth = calcColumnWidth( HDR_TRANSPORT, showHeaders, mLabelWidth );
838  mLabelWidth = calcColumnWidth( HDR_FROM, showHeaders, mLabelWidth );
839  mLabelWidth = calcColumnWidth( HDR_REPLY_TO, showHeaders, mLabelWidth );
840  mLabelWidth = calcColumnWidth( HDR_SUBJECT, showHeaders, mLabelWidth );
841 
842  if ( !fromSlot ) {
843  mAllFieldsAction->setChecked( showHeaders == HDR_ALL );
844  }
845 
846  if ( !fromSlot ) {
847  mIdentityAction->setChecked( abs( mShowHeaders )&HDR_IDENTITY );
848  }
849  rethinkHeaderLine( showHeaders,HDR_IDENTITY, row, mLblIdentity, mComposerBase->identityCombo(),
850  mBtnIdentity );
851 
852  if ( !fromSlot ) {
853  mDictionaryAction->setChecked( abs( mShowHeaders )&HDR_DICTIONARY );
854  }
855  rethinkHeaderLine( showHeaders,HDR_DICTIONARY, row, mDictionaryLabel,
856  mDictionaryCombo, mBtnDictionary );
857 
858  if ( !fromSlot ) {
859  mFccAction->setChecked( abs( mShowHeaders )&HDR_FCC );
860  }
861  rethinkHeaderLine( showHeaders,HDR_FCC, row, mLblFcc, mFccFolder, mBtnFcc );
862 
863  if ( !fromSlot ) {
864  mTransportAction->setChecked( abs( mShowHeaders )&HDR_TRANSPORT );
865  }
866  rethinkHeaderLine( showHeaders,HDR_TRANSPORT, row, mLblTransport, mComposerBase->transportComboBox(),
867  mBtnTransport );
868 
869  if ( !fromSlot ) {
870  mFromAction->setChecked( abs( mShowHeaders )&HDR_FROM );
871  }
872  rethinkHeaderLine( showHeaders,HDR_FROM, row, mLblFrom, mEdtFrom );
873 
874  QWidget *prevFocus = mEdtFrom;
875 
876  if ( !fromSlot ) {
877  mReplyToAction->setChecked( abs( mShowHeaders )&HDR_REPLY_TO );
878  }
879  rethinkHeaderLine( showHeaders, HDR_REPLY_TO, row, mLblReplyTo, mEdtReplyTo );
880  if ( showHeaders & HDR_REPLY_TO ) {
881  prevFocus = connectFocusMoving( prevFocus, mEdtReplyTo );
882  }
883 
884  mGrid->addWidget( mComposerBase->recipientsEditor(), row, 0, 1, 3 );
885  ++row;
886  if ( showHeaders & HDR_REPLY_TO ) {
887  connect( mEdtReplyTo, SIGNAL(focusDown()), mComposerBase->recipientsEditor(),
888  SLOT(setFocusTop()) );
889  connect( mComposerBase->recipientsEditor(), SIGNAL(focusUp()), mEdtReplyTo,
890  SLOT(setFocus()) );
891  } else {
892  connect( mEdtFrom, SIGNAL(focusDown()), mComposerBase->recipientsEditor(),
893  SLOT(setFocusTop()) );
894  connect( mComposerBase->recipientsEditor(), SIGNAL(focusUp()), mEdtFrom,
895  SLOT(setFocus()) );
896  }
897 
898  connect( mComposerBase->recipientsEditor(), SIGNAL(focusDown()), mEdtSubject,
899  SLOT(setFocus()) );
900  connect( mEdtSubject, SIGNAL(focusUp()), mComposerBase->recipientsEditor(),
901  SLOT(setFocusBottom()) );
902 
903  prevFocus = mComposerBase->recipientsEditor();
904 
905  if ( !fromSlot ) {
906  mSubjectAction->setChecked( abs( mShowHeaders )&HDR_SUBJECT );
907  }
908  rethinkHeaderLine(showHeaders,HDR_SUBJECT, row, mLblSubject, mEdtSubject );
909  connectFocusMoving( mEdtSubject, mComposerBase->editor() );
910 
911  assert( row <= mNumHeaders + 1 );
912 
913 
914  mHeadersArea->setMaximumHeight( mHeadersArea->sizeHint().height() );
915 
916  mIdentityAction->setEnabled(!mAllFieldsAction->isChecked());
917  mDictionaryAction->setEnabled( !mAllFieldsAction->isChecked() );
918  mTransportAction->setEnabled(!mAllFieldsAction->isChecked());
919  mFromAction->setEnabled(!mAllFieldsAction->isChecked());
920  if ( mReplyToAction ) {
921  mReplyToAction->setEnabled( !mAllFieldsAction->isChecked() );
922  }
923  mFccAction->setEnabled( !mAllFieldsAction->isChecked() );
924  mSubjectAction->setEnabled( !mAllFieldsAction->isChecked() );
925  mComposerBase->recipientsEditor()->setFirstColumnWidth( mLabelWidth );
926 }
927 
928 QWidget *KMComposeWin::connectFocusMoving( QWidget *prev, QWidget *next )
929 {
930  connect( prev, SIGNAL(focusDown()), next, SLOT(setFocus()) );
931  connect( next, SIGNAL(focusUp()), prev, SLOT(setFocus()) );
932 
933  return next;
934 }
935 
936 //-----------------------------------------------------------------------------
937 void KMComposeWin::rethinkHeaderLine( int aValue, int aMask, int &aRow,
938  QLabel *aLbl, QWidget *aEdt,
939  QPushButton *aBtn )
940 {
941  if ( aValue & aMask ) {
942  aLbl->setFixedWidth( mLabelWidth );
943  aLbl->setBuddy( aEdt );
944  mGrid->addWidget( aLbl, aRow, 0 );
945  aEdt->show();
946 
947  if ( aBtn ) {
948  mGrid->addWidget( aEdt, aRow, 1 );
949  mGrid->addWidget( aBtn, aRow, 2 );
950  aBtn->show();
951  } else {
952  mGrid->addWidget( aEdt, aRow, 1, 1, 2 );
953  }
954  aRow++;
955  } else {
956  aLbl->hide();
957  aEdt->hide();
958  if ( aBtn ) {
959  aBtn->hide();
960  }
961  }
962 }
963 
964 //-----------------------------------------------------------------------------
965 void KMComposeWin::rethinkHeaderLine( int aValue, int aMask, int &aRow,
966  QLabel *aLbl, QWidget *aCbx,
967  QCheckBox *aChk )
968 {
969  if ( aValue & aMask ) {
970  aLbl->setBuddy( aCbx );
971  mGrid->addWidget( aLbl, aRow, 0 );
972 
973  mGrid->addWidget( aCbx, aRow, 1 );
974  aCbx->show();
975  if ( aChk ) {
976  mGrid->addWidget( aChk, aRow, 2 );
977  aChk->show();
978  }
979  aRow++;
980  } else {
981  aLbl->hide();
982  aCbx->hide();
983  if ( aChk ) {
984  aChk->hide();
985  }
986  }
987 }
988 
989 //-----------------------------------------------------------------------------
990 void KMComposeWin::applyTemplate( uint uoid, uint uOldId )
991 {
992  const KPIMIdentities::Identity &ident = kmkernel->identityManager()->identityForUoid( uoid );
993  if ( ident.isNull() )
994  return;
995  KMime::Headers::Generic *header = new KMime::Headers::Generic( "X-KMail-Templates", mMsg.get(), ident.templates(), "utf-8" );
996  mMsg->setHeader( header );
997 
998  TemplateParser::TemplateParser::Mode mode;
999  switch ( mContext ) {
1000  case New:
1001  mode = TemplateParser::TemplateParser::NewMessage;
1002  break;
1003  case Reply:
1004  mode = TemplateParser::TemplateParser::Reply;
1005  break;
1006  case ReplyToAll:
1007  mode = TemplateParser::TemplateParser::ReplyAll;
1008  break;
1009  case Forward:
1010  mode = TemplateParser::TemplateParser::Forward;
1011  break;
1012  default:
1013  return;
1014  }
1015 
1016  if ( mode == TemplateParser::TemplateParser::NewMessage ) {
1017  TemplateParser::TemplateParser parser( mMsg, mode );
1018  parser.setSelection( mTextSelection );
1019  parser.setAllowDecryption( MessageViewer::GlobalSettings::self()->automaticDecrypt() );
1020  parser.setIdentityManager( KMKernel::self()->identityManager() );
1021  if ( !mCustomTemplate.isEmpty() )
1022  parser.process( mCustomTemplate, mMsg, mCollectionForNewMessage );
1023  else
1024  parser.processWithIdentity( uoid, mMsg, mCollectionForNewMessage );
1025  mComposerBase->updateTemplate( mMsg );
1026  updateSignature(uoid, uOldId);
1027  return;
1028  }
1029 
1030  if ( mMsg->headerByType( "X-KMail-Link-Message" ) ) {
1031  Akonadi::Item::List items;
1032  foreach( const QString& serNumStr, mMsg->headerByType( "X-KMail-Link-Message" )->asUnicodeString().split( QLatin1Char(',') ) )
1033  items << Akonadi::Item( serNumStr.toLongLong() );
1034 
1035 
1036  Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob( items, this );
1037  job->fetchScope().fetchFullPayload( true );
1038  job->fetchScope().setAncestorRetrieval( Akonadi::ItemFetchScope::Parent );
1039  job->setProperty( "mode", (int)mode );
1040  job->setProperty( "uoid", uoid );
1041  job->setProperty( "uOldid", uOldId );
1042  connect( job, SIGNAL(result(KJob*)), SLOT(slotDelayedApplyTemplate(KJob*)) );
1043  }
1044 }
1045 
1046 void KMComposeWin::slotDelayedApplyTemplate( KJob *job )
1047 {
1048  const Akonadi::ItemFetchJob *fetchJob = qobject_cast<Akonadi::ItemFetchJob*>( job );
1049  const Akonadi::Item::List items = fetchJob->items();
1050 
1051  const TemplateParser::TemplateParser::Mode mode = static_cast<TemplateParser::TemplateParser::Mode>( fetchJob->property( "mode" ).toInt() );
1052  const uint uoid = fetchJob->property( "uoid" ).toUInt();
1053  const uint uOldId = fetchJob->property( "uOldid" ).toUInt();
1054 
1055  TemplateParser::TemplateParser parser( mMsg, mode );
1056  parser.setSelection( mTextSelection );
1057  parser.setAllowDecryption( MessageViewer::GlobalSettings::self()->automaticDecrypt() );
1058  parser.setWordWrap( MessageComposer::MessageComposerSettings::self()->wordWrap(), MessageComposer::MessageComposerSettings::self()->lineWrapWidth() );
1059  parser.setIdentityManager( KMKernel::self()->identityManager() );
1060  foreach ( const Akonadi::Item &item, items ) {
1061  if ( !mCustomTemplate.isEmpty() )
1062  parser.process( mCustomTemplate, MessageCore::Util::message( item ) );
1063  else
1064  parser.processWithIdentity( uoid, MessageCore::Util::message( item ) );
1065  }
1066  mComposerBase->updateTemplate( mMsg );
1067  updateSignature(uoid, uOldId);
1068 }
1069 
1070 void KMComposeWin::updateSignature(uint uoid, uint uOldId)
1071 {
1072  const KPIMIdentities::Identity &ident = kmkernel->identityManager()->identityForUoid( uoid );
1073  const KPIMIdentities::Identity &oldIdentity = kmkernel->identityManager()->identityForUoid( uOldId );
1074  mComposerBase->identityChanged( ident, oldIdentity, true );
1075 }
1076 
1077 void KMComposeWin::setCollectionForNewMessage( const Akonadi::Collection& folder)
1078 {
1079  mCollectionForNewMessage = folder;
1080 }
1081 
1082 void KMComposeWin::setQuotePrefix( uint uoid )
1083 {
1084  QString quotePrefix = mMsg->headerByType( "X-KMail-QuotePrefix" ) ? mMsg->headerByType( "X-KMail-QuotePrefix" )->asUnicodeString() : QString();
1085  if ( quotePrefix.isEmpty() ) {
1086  // no quote prefix header, set quote prefix according in identity
1087  // TODO port templates to ComposerViewBase
1088 
1089  if ( mCustomTemplate.isEmpty() ) {
1090  const KPIMIdentities::Identity &identity = kmkernel->identityManager()->identityForUoidOrDefault( uoid );
1091  // Get quote prefix from template
1092  // ( custom templates don't specify custom quotes prefixes )
1093  TemplateParser::Templates quoteTemplate(
1094  TemplateParser::TemplatesConfiguration::configIdString( identity.uoid() ) );
1095  quotePrefix = quoteTemplate.quoteString();
1096  }
1097  }
1098  mComposerBase->editor()->setQuotePrefixName( MessageCore::StringUtil::formatString( quotePrefix,
1099  mMsg->from()->asUnicodeString() ) );
1100 }
1101 
1102 //-----------------------------------------------------------------------------
1103 void KMComposeWin::getTransportMenu()
1104 {
1105  mActNowMenu->clear();
1106  mActLaterMenu->clear();
1107 
1108  const QList<Transport*> transports = TransportManager::self()->transports();
1109  foreach ( Transport *transport, transports ) {
1110  const QString name = transport->name().replace( QLatin1Char('&'), QLatin1String("&&") );
1111  QAction *action1 = new QAction( name, mActNowMenu );
1112  QAction *action2 = new QAction( name, mActLaterMenu );
1113  action1->setData( transport->id() );
1114  action2->setData( transport->id() );
1115  mActNowMenu->addAction( action1 );
1116  mActLaterMenu->addAction( action2 );
1117  }
1118 }
1119 
1120 //-----------------------------------------------------------------------------
1121 void KMComposeWin::setupActions( void )
1122 {
1123  KActionMenu *actActionNowMenu, *actActionLaterMenu;
1124 
1125  if ( MessageComposer::MessageComposerSettings::self()->sendImmediate() ) {
1126  //default = send now, alternative = queue
1127  KAction *action = new KAction(KIcon(QLatin1String("mail-send")), i18n("&Send Mail"), this);
1128  actionCollection()->addAction(QLatin1String("send_default"), action );
1129  action->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_Return ) );
1130  connect( action, SIGNAL(triggered(bool)), SLOT(slotSendNow()));
1131 
1132  // FIXME: change to mail_send_via icon when this exist.
1133  actActionNowMenu = new KActionMenu( KIcon( QLatin1String("mail-send") ), i18n("&Send Mail Via"), this );
1134  actActionNowMenu->setIconText( i18n( "Send" ) );
1135  actionCollection()->addAction( QLatin1String("send_default_via"), actActionNowMenu );
1136 
1137  action = new KAction( KIcon( QLatin1String("mail-queue") ), i18n("Send &Later"), this );
1138  actionCollection()->addAction( QLatin1String("send_alternative"), action );
1139  connect( action, SIGNAL(triggered(bool)), SLOT(slotSendLater()) );
1140  actActionLaterMenu = new KActionMenu( KIcon( QLatin1String("mail-queue") ), i18n("Send &Later Via"), this );
1141  actActionLaterMenu->setIconText( i18nc( "Queue the message for sending at a later date", "Queue" ) );
1142  actionCollection()->addAction( QLatin1String("send_alternative_via"), actActionLaterMenu );
1143 
1144  } else {
1145  //default = queue, alternative = send now
1146  KAction *action = new KAction( KIcon( QLatin1String("mail-queue") ), i18n("Send &Later"), this );
1147  actionCollection()->addAction( QLatin1String("send_default"), action );
1148  connect( action, SIGNAL(triggered(bool)), SLOT(slotSendLater()) );
1149  action->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_Return ) );
1150  actActionLaterMenu = new KActionMenu( KIcon( QLatin1String("mail-queue") ), i18n("Send &Later Via"), this );
1151  actionCollection()->addAction( QLatin1String("send_default_via"), actActionLaterMenu );
1152 
1153  action = new KAction( KIcon( QLatin1String("mail-send") ), i18n("&Send Mail"), this );
1154  actionCollection()->addAction( QLatin1String("send_alternative"), action );
1155  connect( action, SIGNAL(triggered(bool)), SLOT(slotSendNow()) );
1156 
1157  // FIXME: change to mail_send_via icon when this exits.
1158  actActionNowMenu = new KActionMenu( KIcon( QLatin1String("mail-send") ), i18n("&Send Mail Via"), this );
1159  actionCollection()->addAction( QLatin1String("send_alternative_via"), actActionNowMenu );
1160 
1161  }
1162 
1163  // needed for sending "default transport"
1164  actActionNowMenu->setDelayed( true );
1165  actActionLaterMenu->setDelayed( true );
1166 
1167  connect( actActionNowMenu, SIGNAL(triggered(bool)), this,
1168  SLOT(slotSendNow()) );
1169  connect( actActionLaterMenu, SIGNAL(triggered(bool)), this,
1170  SLOT(slotSendLater()) );
1171 
1172  mActNowMenu = actActionNowMenu->menu();
1173  mActLaterMenu = actActionLaterMenu->menu();
1174 
1175  connect( mActNowMenu, SIGNAL(triggered(QAction*)), this,
1176  SLOT(slotSendNowVia(QAction*)) );
1177  connect( mActNowMenu, SIGNAL(aboutToShow()), this,
1178  SLOT(getTransportMenu()) );
1179 
1180  connect( mActLaterMenu, SIGNAL(triggered(QAction*)), this,
1181  SLOT(slotSendLaterVia(QAction*)) );
1182  connect( mActLaterMenu, SIGNAL(aboutToShow()), this,
1183  SLOT(getTransportMenu()) );
1184 
1185  KAction *action = new KAction( KIcon( QLatin1String("document-save") ), i18n("Save as &Draft"), this );
1186  actionCollection()->addAction(QLatin1String("save_in_drafts"), action );
1187  action->setHelpText(i18n("Save email in Draft folder"));
1188  action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S));
1189  connect( action, SIGNAL(triggered(bool)), SLOT(slotSaveDraft()) );
1190 
1191  action = new KAction( KIcon( QLatin1String("document-save") ), i18n("Save as &Template"), this );
1192  action->setHelpText(i18n("Save email in Template folder"));
1193  actionCollection()->addAction( QLatin1String("save_in_templates"), action );
1194  connect( action, SIGNAL(triggered(bool)), SLOT(slotSaveTemplate()) );
1195 
1196  action = new KAction( KIcon( QLatin1String("document-save") ), i18n("Save as &File"), this );
1197  action->setHelpText(i18n("Save email as text or html file"));
1198  actionCollection()->addAction( QLatin1String("save_as_file"), action );
1199  connect( action, SIGNAL(triggered(bool)), SLOT(slotSaveAsFile()) );
1200 
1201  action = new KAction(KIcon( QLatin1String( "contact-new" ) ), i18n("New AddressBook Contact..."),this);
1202  actionCollection()->addAction(QLatin1String("kmail_new_addressbook_contact"), action );
1203  connect(action, SIGNAL(triggered(bool)), this, SLOT(slotCreateAddressBookContact()));
1204 
1205 
1206 
1207  action = new KAction(KIcon(QLatin1String("document-open")), i18n("&Insert Text File..."), this);
1208  actionCollection()->addAction(QLatin1String("insert_file"), action );
1209  connect(action, SIGNAL(triggered(bool)), SLOT(slotInsertFile()));
1210 
1211  mRecentAction = new KRecentFilesAction( KIcon( QLatin1String("document-open") ),
1212  i18n( "&Insert Recent Text File" ), this );
1213  actionCollection()->addAction(QLatin1String("insert_file_recent"), mRecentAction );
1214  connect(mRecentAction, SIGNAL(urlSelected(KUrl)),
1215  SLOT(slotInsertRecentFile(KUrl)));
1216  connect(mRecentAction, SIGNAL(recentListCleared()),
1217  SLOT(slotRecentListFileClear()));
1218  mRecentAction->loadEntries( KMKernel::self()->config()->group( QString() ) );
1219 
1220  action = new KAction(KIcon(QLatin1String("x-office-address-book")), i18n("&Address Book"), this);
1221  action->setHelpText(i18n("Open Address Book"));
1222  actionCollection()->addAction(QLatin1String("addressbook"), action );
1223  if (KStandardDirs::findExe(QLatin1String("kaddressbook")).isEmpty())
1224  action->setEnabled(false);
1225  connect(action, SIGNAL(triggered(bool)), SLOT(slotAddrBook()));
1226  action = new KAction(KIcon(QLatin1String("mail-message-new")), i18n("&New Composer"), this);
1227  actionCollection()->addAction(QLatin1String("new_composer"), action );
1228  connect(action, SIGNAL(triggered(bool)), SLOT(slotNewComposer()));
1229  action->setShortcuts( KStandardShortcut::shortcut( KStandardShortcut::New ) );
1230  action = new KAction( KIcon( QLatin1String("window-new") ), i18n("New Main &Window"), this );
1231  actionCollection()->addAction( QLatin1String("open_mailreader"), action );
1232  connect( action, SIGNAL(triggered(bool)), SLOT(slotNewMailReader()) );
1233 
1234  action = new KAction( i18n("Select &Recipients..."), this );
1235  actionCollection()->addAction( QLatin1String("select_recipients"), action );
1236  connect( action, SIGNAL(triggered(bool)),
1237  mComposerBase->recipientsEditor(), SLOT(selectRecipients()) );
1238  action = new KAction( i18n("Save &Distribution List..."), this );
1239  actionCollection()->addAction( QLatin1String("save_distribution_list"), action );
1240  connect( action, SIGNAL(triggered(bool)),
1241  mComposerBase->recipientsEditor(), SLOT(saveDistributionList()) );
1242 
1243  KStandardAction::print( this, SLOT(slotPrint()), actionCollection() );
1244  if(KPrintPreview::isAvailable())
1245  KStandardAction::printPreview( this, SLOT(slotPrintPreview()), actionCollection() );
1246  KStandardAction::close( this, SLOT(slotClose()), actionCollection() );
1247 
1248  KStandardAction::undo( this, SLOT(slotUndo()), actionCollection() );
1249  KStandardAction::redo( this, SLOT(slotRedo()), actionCollection() );
1250  KStandardAction::cut( this, SLOT(slotCut()), actionCollection() );
1251  KStandardAction::copy( this, SLOT(slotCopy()), actionCollection() );
1252  KStandardAction::pasteText( this, SLOT(slotPaste()), actionCollection() );
1253  mSelectAll = KStandardAction::selectAll( this, SLOT(slotMarkAll()), actionCollection() );
1254 
1255  mFindText = KStandardAction::find( mComposerBase->editor(), SLOT(slotFind()), actionCollection() );
1256  mFindNextText = KStandardAction::findNext( mComposerBase->editor(), SLOT(slotFindNext()), actionCollection() );
1257 
1258  mReplaceText = KStandardAction::replace( mComposerBase->editor(), SLOT(slotReplace()), actionCollection() );
1259  actionCollection()->addAction( KStandardAction::Spelling, QLatin1String("spellcheck"),
1260  mComposerBase->editor(), SLOT(checkSpelling()) );
1261 
1262  action = new KAction( i18n("Paste as Attac&hment"), this );
1263  actionCollection()->addAction( QLatin1String("paste_att"), action );
1264  connect( action, SIGNAL(triggered(bool)), SLOT(slotPasteAsAttachment()) );
1265 
1266  action = new KAction( i18n("Cl&ean Spaces"), this );
1267  actionCollection()->addAction( QLatin1String("clean_spaces"), action );
1268  connect( action, SIGNAL(triggered(bool)), mComposerBase->signatureController(), SLOT(cleanSpace()) );
1269 
1270  mFixedFontAction = new KToggleAction( i18n("Use Fi&xed Font"), this );
1271  actionCollection()->addAction( QLatin1String("toggle_fixedfont"), mFixedFontAction );
1272  connect( mFixedFontAction, SIGNAL(triggered(bool)), SLOT(slotUpdateFont()) );
1273  mFixedFontAction->setChecked( MessageViewer::GlobalSettings::self()->useFixedFont() );
1274 
1275  //these are checkable!!!
1276  mUrgentAction = new KToggleAction(
1277  i18nc("@action:inmenu Mark the email as urgent.","&Urgent"), this );
1278  actionCollection()->addAction( QLatin1String("urgent"), mUrgentAction );
1279  mRequestMDNAction = new KToggleAction( i18n("&Request Disposition Notification"), this );
1280  actionCollection()->addAction(QLatin1String("options_request_mdn"), mRequestMDNAction );
1281  mRequestMDNAction->setChecked(GlobalSettings::self()->requestMDN());
1282  //----- Message-Encoding Submenu
1283  mCodecAction = new CodecAction( CodecAction::ComposerMode, this );
1284  actionCollection()->addAction( QLatin1String("charsets"), mCodecAction );
1285  mWordWrapAction = new KToggleAction( i18n( "&Wordwrap" ), this );
1286  actionCollection()->addAction( QLatin1String("wordwrap"), mWordWrapAction );
1287  mWordWrapAction->setChecked( MessageComposer::MessageComposerSettings::self()->wordWrap() );
1288  connect( mWordWrapAction, SIGNAL(toggled(bool)), SLOT(slotWordWrapToggled(bool)) );
1289 
1290  mSnippetAction = new KToggleAction( i18n("&Snippets"), this );
1291  actionCollection()->addAction( QLatin1String("snippets"), mSnippetAction );
1292  connect( mSnippetAction, SIGNAL(toggled(bool)),
1293  mSnippetWidget, SLOT(setVisible(bool)) );
1294  mSnippetAction->setChecked( GlobalSettings::self()->showSnippetManager() );
1295 
1296  mAutoSpellCheckingAction = new KToggleAction( KIcon( QLatin1String("tools-check-spelling") ),
1297  i18n("&Automatic Spellchecking"),
1298  this );
1299  actionCollection()->addAction( QLatin1String("options_auto_spellchecking"), mAutoSpellCheckingAction );
1300  const bool spellChecking = GlobalSettings::self()->autoSpellChecking();
1301  const bool useKmailEditor = !GlobalSettings::self()->useExternalEditor();
1302  const bool spellCheckingEnabled = useKmailEditor && spellChecking;
1303  mAutoSpellCheckingAction->setEnabled( useKmailEditor );
1304 
1305  mAutoSpellCheckingAction->setChecked( spellCheckingEnabled );
1306  slotAutoSpellCheckingToggled( spellCheckingEnabled );
1307  connect( mAutoSpellCheckingAction, SIGNAL(toggled(bool)),
1308  this, SLOT(slotAutoSpellCheckingToggled(bool)) );
1309  connect( mComposerBase->editor(), SIGNAL(checkSpellingChanged(bool)),
1310  this, SLOT(slotAutoSpellCheckingToggled(bool)) );
1311 
1312  connect( mComposerBase->editor(), SIGNAL(textModeChanged(KRichTextEdit::Mode)),
1313  this, SLOT(slotTextModeChanged(KRichTextEdit::Mode)) );
1314  connect( mComposerBase->editor(), SIGNAL(externalEditorClosed()), this, SLOT(slotExternalEditorClosed()));
1315  connect( mComposerBase->editor(), SIGNAL(externalEditorStarted()), this, SLOT(slotExternalEditorStarted()));
1316  //these are checkable!!!
1317  markupAction = new KToggleAction( i18n("Rich Text Editing"), this );
1318  markupAction->setIcon( KIcon( QLatin1String("preferences-desktop-font" )) );
1319  markupAction->setIconText( i18n("Rich Text") );
1320  markupAction->setToolTip( i18n( "Toggle rich text editing mode" ) );
1321  actionCollection()->addAction( QLatin1String("html"), markupAction );
1322  connect( markupAction, SIGNAL(triggered(bool)), SLOT(slotToggleMarkup()) );
1323 
1324  mAllFieldsAction = new KToggleAction( i18n("&All Fields"), this);
1325  actionCollection()->addAction( QLatin1String("show_all_fields"), mAllFieldsAction );
1326  connect( mAllFieldsAction, SIGNAL(triggered(bool)), SLOT(slotView()));
1327  mIdentityAction = new KToggleAction(i18n("&Identity"), this);
1328  actionCollection()->addAction(QLatin1String("show_identity"), mIdentityAction );
1329  connect( mIdentityAction, SIGNAL(triggered(bool)), SLOT(slotView()));
1330  mDictionaryAction = new KToggleAction(i18n("&Dictionary"), this);
1331  actionCollection()->addAction(QLatin1String("show_dictionary"), mDictionaryAction );
1332  connect( mDictionaryAction, SIGNAL(triggered(bool)), SLOT(slotView()));
1333  mFccAction = new KToggleAction(i18n("&Sent-Mail Folder"), this);
1334  actionCollection()->addAction(QLatin1String("show_fcc"), mFccAction );
1335  connect( mFccAction, SIGNAL(triggered(bool)), SLOT(slotView()));
1336  mTransportAction = new KToggleAction(i18n("&Mail Transport"), this);
1337  actionCollection()->addAction(QLatin1String("show_transport"), mTransportAction );
1338  connect( mTransportAction, SIGNAL(triggered(bool)), SLOT(slotView()));
1339  mFromAction = new KToggleAction(i18n("&From"), this);
1340  actionCollection()->addAction(QLatin1String("show_from"), mFromAction );
1341  connect( mFromAction, SIGNAL(triggered(bool)), SLOT(slotView()));
1342  mReplyToAction = new KToggleAction(i18n("&Reply To"), this);
1343  actionCollection()->addAction(QLatin1String("show_reply_to"), mReplyToAction );
1344  connect( mReplyToAction, SIGNAL(triggered(bool)), SLOT(slotView()));
1345  mSubjectAction = new KToggleAction(
1346  i18nc("@action:inmenu Show the subject in the composer window.", "S&ubject"), this);
1347  actionCollection()->addAction(QLatin1String("show_subject"), mSubjectAction );
1348  connect(mSubjectAction, SIGNAL(triggered(bool)), SLOT(slotView()));
1349  //end of checkable
1350 
1351  action = new KAction( i18n("Append S&ignature"), this );
1352  actionCollection()->addAction( QLatin1String("append_signature"), action );
1353  connect( action, SIGNAL(triggered(bool)), mComposerBase->signatureController(), SLOT(appendSignature()));
1354  action = new KAction( i18n("Pr&epend Signature"), this );
1355  actionCollection()->addAction( QLatin1String("prepend_signature"), action );
1356  connect( action, SIGNAL(triggered(bool)), mComposerBase->signatureController(), SLOT(prependSignature()) );
1357  action = new KAction( i18n("Insert Signature At C&ursor Position"), this );
1358  actionCollection()->addAction( QLatin1String("insert_signature_at_cursor_position"), action );
1359  connect( action, SIGNAL(triggered(bool)), mComposerBase->signatureController(), SLOT(insertSignatureAtCursor()) );
1360 
1361 
1362  action = new KAction( i18n("Insert Special Character..."), this );
1363  actionCollection()->addAction( QLatin1String("insert_special_character"), action );
1364  connect( action, SIGNAL(triggered(bool)), this, SLOT(insertSpecialCharacter()) );
1365 
1366  mUpperCase = new KAction( i18n("Uppercase"), this );
1367  actionCollection()->addAction( QLatin1String("change_to_uppercase"), mUpperCase );
1368  connect( mUpperCase, SIGNAL(triggered(bool)), this, SLOT(slotUpperCase()) );
1369 
1370  mLowerCase = new KAction( i18n("Lowercase"), this );
1371  actionCollection()->addAction( QLatin1String("change_to_lowercase"), mLowerCase );
1372  connect( mLowerCase, SIGNAL(triggered(bool)), this, SLOT(slotLowerCase()) );
1373 
1374  mComposerBase->attachmentController()->createActions();
1375 
1376  setStandardToolBarMenuEnabled( true );
1377 
1378  KStandardAction::keyBindings( this, SLOT(slotEditKeys()), actionCollection());
1379  KStandardAction::configureToolbars( this, SLOT(slotEditToolbars()), actionCollection());
1380  KStandardAction::preferences( kmkernel, SLOT(slotShowConfigurationDialog()), actionCollection() );
1381 
1382  action = new KAction( i18n("&Spellchecker..."), this );
1383  action->setIconText( i18n("Spellchecker") );
1384  actionCollection()->addAction( QLatin1String("setup_spellchecker"), action );
1385  connect( action, SIGNAL(triggered(bool)), SLOT(slotSpellcheckConfig()) );
1386 
1387  mTranslateAction = new KToggleAction( i18n("&Translator"), this );
1388  action->setShortcut( QKeySequence( Qt::CTRL + Qt::ALT + Qt::Key_T ) );
1389  actionCollection()->addAction( QLatin1String("translator"), mTranslateAction );
1390  mTranslateAction->setChecked(false);
1391  connect(mTranslateAction, SIGNAL(triggered(bool)), mTranslatorWidget,SLOT(setVisible(bool)));
1392 
1393  //Chiamus not supported in kmail2
1394 #if 0
1395  if ( Kleo::CryptoBackendFactory::instance()->protocol( QLatin1String("Chiasmus") ) ) {
1396  KToggleAction *a = new KToggleAction( KIcon( "chiasmus_chi" ), i18n("Encrypt Message with Chiasmus..."), this );
1397  actionCollection()->addAction( "encrypt_message_chiasmus", a );
1398  a->setCheckedState( KGuiItem( i18n( "Encrypt Message with Chiasmus..." ), "chiencrypted" ) );
1399  mEncryptChiasmusAction = a;
1400  connect( mEncryptChiasmusAction, SIGNAL(toggled(bool)),
1401  this, SLOT(slotEncryptChiasmusToggled(bool)) );
1402  } else {
1403  mEncryptChiasmusAction = 0;
1404  }
1405 #endif
1406 
1407  mEncryptAction = new KToggleAction(KIcon(QLatin1String("document-encrypt")), i18n("&Encrypt Message"), this);
1408  mEncryptAction->setIconText( i18n( "Encrypt" ) );
1409  actionCollection()->addAction(QLatin1String("encrypt_message"), mEncryptAction );
1410  mSignAction = new KToggleAction(KIcon(QLatin1String("document-sign")), i18n("&Sign Message"), this);
1411  mSignAction->setIconText( i18n( "Sign" ) );
1412  actionCollection()->addAction(QLatin1String("sign_message"), mSignAction );
1413  const KPIMIdentities::Identity &ident =
1414  KMKernel::self()->identityManager()->identityForUoidOrDefault( mComposerBase->identityCombo()->currentIdentity() );
1415  // PENDING(marc): check the uses of this member and split it into
1416  // smime/openpgp and or enc/sign, if necessary:
1417  mLastIdentityHasSigningKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
1418  mLastIdentityHasEncryptionKey = !ident.pgpEncryptionKey().isEmpty() || !ident.smimeEncryptionKey().isEmpty();
1419 
1420  mLastEncryptActionState = false;
1421  mLastSignActionState = ident.pgpAutoSign();
1422 
1423  changeCryptoAction();
1424 
1425  connect( mEncryptAction, SIGNAL(triggered(bool)),
1426  SLOT(slotEncryptToggled(bool)) );
1427  connect( mSignAction, SIGNAL(triggered(bool)),
1428  SLOT(slotSignToggled(bool)) );
1429 
1430  QStringList l;
1431  for ( int i=0 ; i<numCryptoMessageFormats ; ++i ) {
1432  l.push_back( Kleo::cryptoMessageFormatToLabel( cryptoMessageFormats[i] ) );
1433  }
1434 
1435  mCryptoModuleAction = new KSelectAction(i18n("&Cryptographic Message Format"), this);
1436  actionCollection()->addAction(QLatin1String("options_select_crypto"), mCryptoModuleAction );
1437  connect(mCryptoModuleAction, SIGNAL(triggered(int)), SLOT(slotSelectCryptoModule()));
1438  mCryptoModuleAction->setItems( l );
1439  mCryptoModuleAction->setToolTip( i18n( "Select a cryptographic format for this message" ) );
1440 
1441  mComposerBase->editor()->createActions( actionCollection() );
1442 
1443  createGUI( QLatin1String("kmcomposerui.rc") );
1444  connect( toolBar( QLatin1String("htmlToolBar") )->toggleViewAction(),
1445  SIGNAL(toggled(bool)),
1446  SLOT(htmlToolBarVisibilityChanged(bool)) );
1447 
1448 
1449  // In Kontact, this entry would read "Configure Kontact", but bring
1450  // up KMail's config dialog. That's sensible, though, so fix the label.
1451  QAction *configureAction = actionCollection()->action( QLatin1String("options_configure") );
1452  if ( configureAction ) {
1453  configureAction->setText( i18n("Configure KMail..." ) );
1454  }
1455 }
1456 
1457 void KMComposeWin::changeCryptoAction()
1458 {
1459  const KPIMIdentities::Identity &ident =
1460  KMKernel::self()->identityManager()->identityForUoidOrDefault( mComposerBase->identityCombo()->currentIdentity() );
1461  if ( !Kleo::CryptoBackendFactory::instance()->openpgp() && !Kleo::CryptoBackendFactory::instance()->smime() ) {
1462  // no crypto whatsoever
1463  mEncryptAction->setEnabled( false );
1464  setEncryption( false );
1465  mSignAction->setEnabled( false );
1466  setSigning( false );
1467  } else {
1468  const bool canOpenPGPSign = Kleo::CryptoBackendFactory::instance()->openpgp() &&
1469  !ident.pgpSigningKey().isEmpty();
1470  const bool canSMIMESign = Kleo::CryptoBackendFactory::instance()->smime() &&
1471  !ident.smimeSigningKey().isEmpty();
1472 
1473  setEncryption( false );
1474  setSigning( ( canOpenPGPSign || canSMIMESign ) && ident.pgpAutoSign() );
1475  }
1476 
1477 }
1478 
1479 //-----------------------------------------------------------------------------
1480 void KMComposeWin::setupStatusBar( QWidget *w )
1481 {
1482  statusBar()->addWidget(w);
1483  statusBar()->insertItem( QString(), 0, 1 );
1484  statusBar()->setItemAlignment( 0, Qt::AlignLeft | Qt::AlignVCenter );
1485  statusBar()->insertPermanentItem( overwriteModeStr(), 4,0 );
1486 
1487  statusBar()->insertPermanentItem( i18n(" Spellcheck: %1 ", QLatin1String( " " )), 3, 0) ;
1488  statusBar()->insertPermanentItem( i18n(" Column: %1 ", QLatin1String( " " ) ), 2, 0 );
1489  statusBar()->insertPermanentItem(
1490  i18nc("Shows the linenumber of the cursor position.", " Line: %1 "
1491  , QLatin1String( " " ) ), 1, 0 );
1492 }
1493 
1494 //-----------------------------------------------------------------------------
1495 void KMComposeWin::setupEditor( void )
1496 {
1497  QFontMetrics fm( mBodyFont );
1498  mComposerBase->editor()->setTabStopWidth( fm.width( QLatin1Char(' ') ) * 8 );
1499 
1500  slotWordWrapToggled( MessageComposer::MessageComposerSettings::self()->wordWrap() );
1501 
1502  // Font setup
1503  slotUpdateFont();
1504 
1505  connect( mComposerBase->editor(), SIGNAL(cursorPositionChanged()),
1506  this, SLOT(slotCursorPositionChanged()) );
1507  slotCursorPositionChanged();
1508 }
1509 
1510 //-----------------------------------------------------------------------------
1511 QString KMComposeWin::subject() const
1512 {
1513  return MessageComposer::Util::cleanedUpHeaderString( mEdtSubject->toPlainText() );
1514 }
1515 
1516 //-----------------------------------------------------------------------------
1517 QString KMComposeWin::from() const
1518 {
1519  return MessageComposer::Util::cleanedUpHeaderString( mEdtFrom->text() );
1520 }
1521 
1522 //-----------------------------------------------------------------------------
1523 QString KMComposeWin::replyTo() const
1524 {
1525  if ( mEdtReplyTo ) {
1526  return MessageComposer::Util::cleanedUpHeaderString( mEdtReplyTo->text() );
1527  } else {
1528  return QString();
1529  }
1530 }
1531 
1532 //-----------------------------------------------------------------------------
1533 void KMComposeWin::decryptOrStripOffCleartextSignature( QByteArray &body )
1534 {
1535  QList<Kpgp::Block> pgpBlocks;
1536  QList<QByteArray> nonPgpBlocks;
1537  if ( Kpgp::Module::prepareMessageForDecryption( body,
1538  pgpBlocks, nonPgpBlocks ) ) {
1539  // Only decrypt/strip off the signature if there is only one OpenPGP
1540  // block in the message
1541  if ( pgpBlocks.count() == 1 ) {
1542  Kpgp::Block &block = pgpBlocks.first();
1543  if ( ( block.type() == Kpgp::PgpMessageBlock ) ||
1544  ( block.type() == Kpgp::ClearsignedBlock ) ) {
1545  if ( block.type() == Kpgp::PgpMessageBlock ) {
1546  // try to decrypt this OpenPGP block
1547  block.decrypt();
1548  } else {
1549  // strip off the signature
1550  block.verify();
1551  }
1552  body = nonPgpBlocks.first();
1553  body.append( block.text() );
1554  body.append( nonPgpBlocks.last() );
1555  }
1556  }
1557  }
1558 }
1559 
1560 void KMComposeWin::setCurrentTransport( int transportId )
1561 {
1562  mComposerBase->transportComboBox()->setCurrentTransport( transportId );
1563 }
1564 
1565 void KMComposeWin::setCurrentReplyTo(const QString& replyTo)
1566 {
1567  if ( mEdtReplyTo ) {
1568  mEdtReplyTo->setText( replyTo );
1569  }
1570 }
1571 
1572 //-----------------------------------------------------------------------------
1573 void KMComposeWin::setMessage( const KMime::Message::Ptr &newMsg, bool lastSignState, bool lastEncryptState, bool mayAutoSign,
1574  bool allowDecryption, bool isModified )
1575 {
1576  if ( !newMsg ) {
1577  kDebug() << "newMsg == 0!";
1578  return;
1579  }
1580 
1581  if( lastSignState )
1582  mLastSignActionState = true;
1583 
1584  if ( lastEncryptState )
1585  mLastEncryptActionState = true;
1586 
1587  mComposerBase->setMessage( newMsg );
1588  mMsg = newMsg;
1589  KPIMIdentities::IdentityManager * im = KMKernel::self()->identityManager();
1590 
1591  mEdtFrom->setText( mMsg->from()->asUnicodeString() );
1592  mEdtSubject->setText( mMsg->subject()->asUnicodeString() );
1593 
1594 
1595  // Restore the quote prefix. We can't just use the global quote prefix here,
1596  // since the prefix is different for each message, it might for example depend
1597  // on the original sender in a reply.
1598  if ( mMsg->headerByType( "X-KMail-QuotePrefix" ) )
1599  mComposerBase->editor()->setQuotePrefixName( mMsg->headerByType( "X-KMail-QuotePrefix" )->asUnicodeString() );
1600 
1601  const bool stickyIdentity = mBtnIdentity->isChecked() && !mIgnoreStickyFields;
1602  bool messageHasIdentity = false;
1603  if( newMsg->headerByType("X-KMail-Identity") &&
1604  !newMsg->headerByType("X-KMail-Identity")->asUnicodeString().isEmpty() )
1605  messageHasIdentity = true;
1606  if ( !stickyIdentity && messageHasIdentity )
1607  mId = newMsg->headerByType( "X-KMail-Identity" )->asUnicodeString().toUInt();
1608 
1609  // don't overwrite the header values with identity specific values
1610  // unless the identity is sticky
1611  if ( !stickyIdentity ) {
1612  disconnect( mComposerBase->identityCombo(),SIGNAL(identityChanged(uint)),
1613  this, SLOT(slotIdentityChanged(uint)) ) ;
1614  }
1615 
1616  // load the mId into the gui, sticky or not, without emitting
1617  mComposerBase->identityCombo()->setCurrentIdentity( mId );
1618  const uint idToApply = mId;
1619  if ( !stickyIdentity ) {
1620  connect( mComposerBase->identityCombo(),SIGNAL(identityChanged(uint)),
1621  this, SLOT(slotIdentityChanged(uint)) );
1622  } else {
1623  // load the message's state into the mId, without applying it to the gui
1624  // that's so we can detect that the id changed (because a sticky was set)
1625  // on apply()
1626  if ( messageHasIdentity ) {
1627  mId = newMsg->headerByType("X-KMail-Identity")->asUnicodeString().toUInt();
1628  } else {
1629  mId = im->defaultIdentity().uoid();
1630  }
1631  }
1632 
1633  // manually load the identity's value into the fields; either the one from the
1634  // messge, where appropriate, or the one from the sticky identity. What's in
1635  // mId might have changed meanwhile, thus the save value
1636  slotIdentityChanged( idToApply, true /*initalChange*/ );
1637 
1638  const KPIMIdentities::Identity &ident = im->identityForUoid( mComposerBase->identityCombo()->currentIdentity() );
1639 
1640  const bool stickyTransport = mBtnTransport->isChecked() && !mIgnoreStickyFields;
1641  if( stickyTransport ) {
1642  mComposerBase->transportComboBox()->setCurrentTransport( ident.transport().toInt() );
1643  }
1644 
1645  // TODO move the following to ComposerViewBase
1646  // however, requires the actions to be there as well in order to share with mobile client
1647 
1648  // check for the presence of a DNT header, indicating that MDN's were requested
1649  if( newMsg->headerByType( "Disposition-Notification-To" ) ) {
1650  QString mdnAddr = newMsg->headerByType( "Disposition-Notification-To" )->asUnicodeString();
1651  mRequestMDNAction->setChecked( ( !mdnAddr.isEmpty() &&
1652  im->thatIsMe( mdnAddr ) ) ||
1653  GlobalSettings::self()->requestMDN() );
1654  }
1655  // check for presence of a priority header, indicating urgent mail:
1656  if ( newMsg->headerByType( "X-PRIORITY" ) && newMsg->headerByType("Priority" ) )
1657  {
1658  const QString xpriority = newMsg->headerByType( "X-PRIORITY" )->asUnicodeString();
1659  const QString priority = newMsg->headerByType( "Priority" )->asUnicodeString();
1660  if ( xpriority == QLatin1String( "2 (High)" ) && priority == QLatin1String( "urgent" ) )
1661  mUrgentAction->setChecked( true );
1662  }
1663 
1664  if ( !ident.isXFaceEnabled() || ident.xface().isEmpty() ) {
1665  if( mMsg->headerByType( "X-Face" ) )
1666  mMsg->headerByType( "X-Face" )->clear();
1667  } else {
1668  QString xface = ident.xface();
1669  if ( !xface.isEmpty() ) {
1670  int numNL = ( xface.length() - 1 ) / 70;
1671  for ( int i = numNL; i > 0; --i ) {
1672  xface.insert( i * 70, QLatin1String("\n\t") );
1673  }
1674  mMsg->setHeader( new KMime::Headers::Generic( "X-Face", mMsg.get(), xface, "utf-8" ) );
1675  }
1676  }
1677 
1678  // if these headers are present, the state of the message should be overruled
1679  if ( mMsg->headerByType( "X-KMail-SignatureActionEnabled" ) )
1680  mLastSignActionState = (mMsg->headerByType( "X-KMail-SignatureActionEnabled" )->as7BitString().contains( "true" ));
1681  if ( mMsg->headerByType( "X-KMail-EncryptActionEnabled" ) )
1682  mLastEncryptActionState = (mMsg->headerByType( "X-KMail-EncryptActionEnabled" )->as7BitString().contains( "true") );
1683  if ( mMsg->headerByType( "X-KMail-CryptoMessageFormat" ) ) {
1684  mCryptoModuleAction->setCurrentItem( format2cb( static_cast<Kleo::CryptoMessageFormat>(
1685  mMsg->headerByType( "X-KMail-CryptoMessageFormat" )->asUnicodeString().toInt() ) ) );
1686  }
1687 
1688  mLastIdentityHasSigningKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
1689  mLastIdentityHasEncryptionKey = !ident.pgpEncryptionKey().isEmpty() || !ident.smimeEncryptionKey().isEmpty();
1690 
1691  if ( Kleo::CryptoBackendFactory::instance()->openpgp() || Kleo::CryptoBackendFactory::instance()->smime() ) {
1692  const bool canOpenPGPSign = Kleo::CryptoBackendFactory::instance()->openpgp() &&
1693  !ident.pgpSigningKey().isEmpty();
1694  const bool canSMIMESign = Kleo::CryptoBackendFactory::instance()->smime() &&
1695  !ident.smimeSigningKey().isEmpty();
1696 
1697  setEncryption( mLastEncryptActionState );
1698  setSigning( ( canOpenPGPSign || canSMIMESign ) && mLastSignActionState );
1699  }
1700  slotUpdateSignatureAndEncrypionStateIndicators();
1701 
1702  QString kmailFcc;
1703  if ( mMsg->headerByType( "X-KMail-Fcc" ) ) {
1704  kmailFcc = mMsg->headerByType( "X-KMail-Fcc" )->asUnicodeString();
1705  }
1706  if ( !mBtnFcc->isChecked() ) {
1707  if ( kmailFcc.isEmpty() ) {
1708  setFcc( ident.fcc() );
1709  }
1710  else
1711  setFcc( kmailFcc );
1712  }
1713 
1714  const bool stickyDictionary = mBtnDictionary->isChecked() && !mIgnoreStickyFields;
1715  if ( !stickyDictionary ) {
1716  mDictionaryCombo->setCurrentByDictionaryName( ident.dictionary() );
1717  }
1718 
1719  mEdtReplyTo->setText( mMsg->replyTo()->asUnicodeString() );
1720 
1721  KMime::Content *msgContent = new KMime::Content;
1722  msgContent->setContent( mMsg->encodedContent() );
1723  msgContent->parse();
1724  MessageViewer::EmptySource emptySource;
1725  MessageViewer::ObjectTreeParser otp( &emptySource );//All default are ok
1726  emptySource.setAllowDecryption( allowDecryption );
1727  otp.parseObjectTree( msgContent );
1728 
1729  bool shouldSetCharset = false;
1730  if ( ( mContext == Reply || mContext == ReplyToAll || mContext == Forward ) && MessageComposer::MessageComposerSettings::forceReplyCharset() )
1731  shouldSetCharset = true;
1732  if ( shouldSetCharset && !otp.plainTextContentCharset().isEmpty() )
1733  mOriginalPreferredCharset = otp.plainTextContentCharset();
1734  // always set auto charset, but prefer original when composing if force reply is set.
1735  setAutoCharset();
1736 
1737  delete msgContent;
1738 #if 0 //TODO port to kmime
1739 
1740  /* Handle the special case of non-mime mails */
1741  if ( mMsg->numBodyParts() == 0 && otp.textualContent().isEmpty() ) {
1742  mCharset=mMsg->charset();
1743  if ( mCharset.isEmpty() || mCharset == "default" ) {
1744  mCharset = Util::defaultCharset();
1745  }
1746 
1747  QByteArray bodyDecoded = mMsg->bodyDecoded();
1748 
1749  if ( allowDecryption ) {
1750  decryptOrStripOffCleartextSignature( bodyDecoded );
1751  }
1752 
1753  const QTextCodec *codec = KMail::Util::codecForName( mCharset );
1754  if ( codec ) {
1755  mEditor->setText( codec->toUnicode( bodyDecoded ) );
1756  } else {
1757  mEditor->setText( QString::fromLocal8Bit( bodyDecoded ) );
1758  }
1759  }
1760 #endif
1761 
1762  if( (MessageComposer::MessageComposerSettings::self()->autoTextSignature()==QLatin1String( "auto" )) && mayAutoSign ) {
1763  //
1764  // Espen 2000-05-16
1765  // Delay the signature appending. It may start a fileseletor.
1766  // Not user friendy if this modal fileseletor opens before the
1767  // composer.
1768  //
1769  if ( MessageComposer::MessageComposerSettings::self()->prependSignature() ) {
1770  QTimer::singleShot( 0, mComposerBase->signatureController(), SLOT(prependSignature()) );
1771  } else {
1772  QTimer::singleShot( 0, mComposerBase->signatureController(), SLOT(appendSignature()) );
1773  }
1774  } else {
1775  mComposerBase->editor()->startExternalEditor();
1776  }
1777 
1778  setModified( isModified );
1779 
1780  // honor "keep reply in this folder" setting even when the identity is changed later on
1781  mPreventFccOverwrite = ( !kmailFcc.isEmpty() && ident.fcc() != kmailFcc );
1782  QTimer::singleShot( 0, this, SLOT(forceAutoSaveMessage()) ); //Force autosaving to make sure this composer reappears if a crash happens before the autosave timer kicks in.
1783 }
1784 
1785 void KMComposeWin::setAutoSaveFileName(const QString& fileName)
1786 {
1787  mComposerBase->setAutoSaveFileName( fileName );
1788 }
1789 
1790 //-----------------------------------------------------------------------------
1791 void KMComposeWin::setTextSelection( const QString& selection )
1792 {
1793  mTextSelection = selection;
1794 }
1795 
1796 //-----------------------------------------------------------------------------
1797 void KMComposeWin::setCustomTemplate( const QString& customTemplate )
1798 {
1799  mCustomTemplate = customTemplate;
1800 }
1801 
1802 //-----------------------------------------------------------------------------
1803 void KMComposeWin::setFcc( const QString &idString )
1804 {
1805  // check if the sent-mail folder still exists
1806  Akonadi::Collection col;
1807  if ( idString.isEmpty() )
1808  col = CommonKernel->sentCollectionFolder();
1809  else
1810  col = Akonadi::Collection( idString.toLongLong() );
1811 
1812  mComposerBase->setFcc( col );
1813  mFccFolder->setCollection( col );
1814 }
1815 
1816 bool KMComposeWin::isComposerModified() const
1817 {
1818  return ( mComposerBase->editor()->document()->isModified() ||
1819  mEdtFrom->isModified() ||
1820  ( mEdtReplyTo && mEdtReplyTo->isModified() ) ||
1821  mComposerBase->recipientsEditor()->isModified() ||
1822  mEdtSubject->document()->isModified() );
1823 }
1824 
1825 //-----------------------------------------------------------------------------
1826 bool KMComposeWin::isModified() const
1827 {
1828  return mWasModified || isComposerModified();
1829 }
1830 
1831 //-----------------------------------------------------------------------------
1832 void KMComposeWin::setModified( bool modified )
1833 {
1834  mWasModified = modified;
1835  changeModifiedState( modified );
1836 }
1837 
1838 
1839 void KMComposeWin::changeModifiedState( bool modified )
1840 {
1841  mComposerBase->editor()->document()->setModified( modified );
1842  if ( !modified ) {
1843  mEdtFrom->setModified( false );
1844  if ( mEdtReplyTo ) mEdtReplyTo->setModified( false );
1845  mComposerBase->recipientsEditor()->clearModified();
1846  mEdtSubject->document()->setModified( false );
1847  }
1848 }
1849 
1850 //-----------------------------------------------------------------------------
1851 bool KMComposeWin::queryClose ()
1852 {
1853  if ( !mComposerBase->editor()->checkExternalEditorFinished() ) {
1854  return false;
1855  }
1856  if ( kmkernel->shuttingDown() || kapp->sessionSaving() ) {
1857  return true;
1858  }
1859 
1860  if ( isModified() ) {
1861  const bool istemplate = ( mFolder.isValid() && CommonKernel->folderIsTemplates( mFolder ) );
1862  const QString savebut = ( istemplate ?
1863  i18n("Re&save as Template") :
1864  i18n("&Save as Draft") );
1865  const QString savetext = ( istemplate ?
1866  i18n("Resave this message in the Templates folder. "
1867  "It can then be used at a later time.") :
1868  i18n("Save this message in the Drafts folder. "
1869  "It can then be edited and sent at a later time.") );
1870 
1871  const int rc = KMessageBox::warningYesNoCancel( this,
1872  i18n("Do you want to save the message for later or discard it?"),
1873  i18n("Close Composer"),
1874  KGuiItem(savebut, QLatin1String("document-save"), QString(), savetext),
1875  KStandardGuiItem::discard(),
1876  KStandardGuiItem::cancel());
1877  if ( rc == KMessageBox::Cancel ) {
1878  return false;
1879  } else if ( rc == KMessageBox::Yes ) {
1880  // doSend will close the window. Just return false from this method
1881  if (istemplate)
1882  slotSaveTemplate();
1883  else
1884  slotSaveDraft();
1885  return false;
1886  }
1887  //else fall through: return true
1888  }
1889  mComposerBase->cleanupAutoSave();
1890 
1891  if( !mMiscComposers.isEmpty() ) {
1892  kWarning() << "Tried to close while composer was active";
1893  return false;
1894  }
1895  return true;
1896 }
1897 
1898 //-----------------------------------------------------------------------------
1899 MessageComposer::ComposerViewBase::MissingAttachment KMComposeWin::userForgotAttachment()
1900 {
1901  bool checkForForgottenAttachments = mCheckForForgottenAttachments && GlobalSettings::self()->showForgottenAttachmentWarning();
1902 
1903  if ( !checkForForgottenAttachments )
1904  return MessageComposer::ComposerViewBase::NoMissingAttachmentFound;
1905 
1906  mComposerBase->setSubject( subject() ); //be sure the composer knows the subject
1907  MessageComposer::ComposerViewBase::MissingAttachment missingAttachments = mComposerBase->checkForMissingAttachments( GlobalSettings::self()->attachmentKeywords() );
1908 
1909  return missingAttachments;
1910 }
1911 
1912 void KMComposeWin::forceAutoSaveMessage()
1913 {
1914  autoSaveMessage( true );
1915 }
1916 
1917 void KMComposeWin::autoSaveMessage(bool force)
1918 {
1919  if ( isComposerModified() || force ) {
1920  applyComposerSetting( mComposerBase );
1921  mComposerBase->autoSaveMessage();
1922  if ( !force ) {
1923  mWasModified = true;
1924  changeModifiedState( false );
1925  }
1926  } else {
1927  mComposerBase->updateAutoSave();
1928  }
1929 }
1930 
1931 bool KMComposeWin::encryptToSelf()
1932 {
1933  // return !Kpgp::Module::getKpgp() || Kpgp::Module::getKpgp()->encryptToSelf();
1934  return MessageComposer::MessageComposerSettings::self()->cryptoEncryptToSelf();
1935 }
1936 
1937 
1938 
1939 void KMComposeWin::slotSendFailed( const QString& msg,MessageComposer::ComposerViewBase::FailedType type)
1940 {
1941  // setModified( false );
1942  setEnabled( true );
1943  KMessageBox::sorry( mMainWidget, msg,
1944  (type == MessageComposer::ComposerViewBase::AutoSave) ? i18n( "Autosave Message Failed" ) : i18n( "Sending Message Failed" ) );
1945 }
1946 
1947 void KMComposeWin::slotSendSuccessful()
1948 {
1949  setModified( false );
1950  mComposerBase->cleanupAutoSave();
1951  mFolder = Akonadi::Collection(); // see dtor
1952  close();
1953 }
1954 
1955 
1956 const KPIMIdentities::Identity &KMComposeWin::identity() const
1957 {
1958  return KMKernel::self()->identityManager()->identityForUoidOrDefault( mComposerBase->identityCombo()->currentIdentity() );
1959 }
1960 
1961 Kleo::CryptoMessageFormat KMComposeWin::cryptoMessageFormat() const
1962 {
1963  if ( !mCryptoModuleAction ) {
1964  return Kleo::AutoFormat;
1965  }
1966  return cb2format( mCryptoModuleAction->currentItem() );
1967 }
1968 
1969 //-----------------------------------------------------------------------------
1970 void KMComposeWin::addAttach( KMime::Content *msgPart )
1971 {
1972  mComposerBase->addAttachmentPart( msgPart );
1973  setModified( true );
1974 }
1975 //-----------------------------------------------------------------------------
1976 
1977 QString KMComposeWin::prettyMimeType( const QString &type )
1978 {
1979  const QString t = type.toLower();
1980  const KMimeType::Ptr st = KMimeType::mimeType( t );
1981 
1982  if ( !st ) {
1983  kWarning() <<"unknown mimetype" << t;
1984  return t;
1985  }
1986 
1987  const QString pretty = !st->isDefault() ? st->comment() : t;
1988  if ( pretty.isEmpty() )
1989  return type;
1990  else
1991  return pretty;
1992 }
1993 
1994 void KMComposeWin::setAutoCharset()
1995 {
1996  mCodecAction->setCurrentItem( 0 );
1997 }
1998 
1999 // We can't simply use KCodecAction::setCurrentCodec(), since that doesn't
2000 // use fixEncoding().
2001 static QString selectCharset( KSelectAction *root, const QString &encoding )
2002 {
2003  foreach( QAction *action, root->actions() ) {
2004  KSelectAction *subMenu = dynamic_cast<KSelectAction *>( action );
2005  if ( subMenu ) {
2006  const QString codecNameToSet = selectCharset( subMenu, encoding );
2007  if ( !codecNameToSet.isEmpty() )
2008  return codecNameToSet;
2009  }
2010  else {
2011  const QString fixedActionText = MessageViewer::NodeHelper::fixEncoding( action->text() );
2012  if ( KGlobal::charsets()->codecForName(
2013  KGlobal::charsets()->encodingForName( fixedActionText ) )
2014  == KGlobal::charsets()->codecForName( encoding ) ) {
2015  return action->text();
2016  }
2017  }
2018  }
2019  return QString();
2020 }
2021 
2022 //-----------------------------------------------------------------------------
2023 void KMComposeWin::setCharset( const QByteArray &charset )
2024 {
2025  const QString codecNameToSet = selectCharset( mCodecAction, QString::fromLatin1(charset) );
2026  if ( codecNameToSet.isEmpty() ) {
2027  kWarning() << "Could not find charset" << charset;
2028  setAutoCharset();
2029  }
2030  else
2031  mCodecAction->setCurrentCodec( codecNameToSet );
2032 }
2033 
2034 //-----------------------------------------------------------------------------
2035 void KMComposeWin::slotAddrBook()
2036 {
2037  KRun::runCommand(QLatin1String("kaddressbook"), window());
2038 }
2039 
2040 //-----------------------------------------------------------------------------
2041 void KMComposeWin::slotInsertFile()
2042 {
2043  KUrl u = mComposerBase->editor()->insertFile();
2044  if ( u.isEmpty() )
2045  return;
2046 
2047  mRecentAction->addUrl( u );
2048  // Prevent race condition updating list when multiple composers are open
2049  {
2050  const QString encoding = MessageViewer::NodeHelper::encodingForName( u.fileEncoding() );
2051  QStringList urls = GlobalSettings::self()->recentUrls();
2052  QStringList encodings = GlobalSettings::self()->recentEncodings();
2053  // Prevent config file from growing without bound
2054  // Would be nicer to get this constant from KRecentFilesAction
2055  const int mMaxRecentFiles = 30;
2056  while ( urls.count() > mMaxRecentFiles )
2057  urls.removeLast();
2058  while ( encodings.count() > mMaxRecentFiles )
2059  encodings.removeLast();
2060  // sanity check
2061  if ( urls.count() != encodings.count() ) {
2062  urls.clear();
2063  encodings.clear();
2064  }
2065  urls.prepend( u.prettyUrl() );
2066  encodings.prepend( encoding );
2067  GlobalSettings::self()->setRecentUrls( urls );
2068  GlobalSettings::self()->setRecentEncodings( encodings );
2069  mRecentAction->saveEntries( KMKernel::self()->config()->group( QString() ) );
2070  }
2071  slotInsertRecentFile( u );
2072 }
2073 
2074 
2075 void KMComposeWin::slotRecentListFileClear()
2076 {
2077  KSharedConfig::Ptr config = KMKernel::self()->config();
2078  KConfigGroup group( config, "Composer" );
2079  group.deleteEntry("recent-urls");
2080  group.deleteEntry("recent-encodings");
2081  mRecentAction->saveEntries( config->group( QString() ) );
2082 }
2083 //-----------------------------------------------------------------------------
2084 void KMComposeWin::slotInsertRecentFile( const KUrl &u )
2085 {
2086  if ( u.fileName().isEmpty() ) {
2087  return;
2088  }
2089 
2090  // Get the encoding previously used when inserting this file
2091  QString encoding;
2092  const QStringList urls = GlobalSettings::self()->recentUrls();
2093  const QStringList encodings = GlobalSettings::self()->recentEncodings();
2094  const int index = urls.indexOf( u.prettyUrl() );
2095  if ( index != -1 ) {
2096  encoding = encodings[ index ];
2097  } else {
2098  kDebug()<<" encoding not found so we can't insert text"; //see InsertTextFileJob
2099  return;
2100  }
2101 
2102 
2103  MessageComposer::InsertTextFileJob *job = new MessageComposer::InsertTextFileJob( mComposerBase->editor(), u );
2104  job->setEncoding( encoding );
2105  job->start();
2106  // Don't care about the result for now
2107  // TODO: we should probably show an error message if it fails...
2108 }
2109 
2110 //-----------------------------------------------------------------------------
2111 void KMComposeWin::slotSelectCryptoModule( bool init )
2112 {
2113  if ( !init )
2114  setModified( true );
2115 
2116  mComposerBase->attachmentModel()->setEncryptEnabled( canSignEncryptAttachments() );
2117  mComposerBase->attachmentModel()->setSignEnabled( canSignEncryptAttachments() );
2118 }
2119 
2120 //-----------------------------------------------------------------------------
2121 void KMComposeWin::slotUpdateFont()
2122 {
2123  kDebug();
2124  if ( !mFixedFontAction ) {
2125  return;
2126  }
2127  mComposerBase->editor()->setFontForWholeText( mFixedFontAction->isChecked() ?
2128  mFixedFont : mBodyFont );
2129 }
2130 
2131 QString KMComposeWin::smartQuote( const QString & msg )
2132 {
2133  return MessageCore::StringUtil::smartQuote( msg, MessageComposer::MessageComposerSettings::self()->lineWrapWidth() );
2134 }
2135 
2136 
2137 bool KMComposeWin::insertFromMimeData( const QMimeData *source, bool forceAttachment )
2138 {
2139  // If this is a PNG image, either add it as an attachment or as an inline image
2140  if ( source->hasImage() && source->hasFormat( QLatin1String("image/png") ) ) {
2141  // Get the image data before showing the dialog, since that processes events which can delete
2142  // the QMimeData object behind our back
2143  const QByteArray imageData = source->data( QLatin1String("image/png") );
2144  if ( imageData.isEmpty() ) {
2145  return true;
2146  }
2147  if ( !forceAttachment ) {
2148  if ( mComposerBase->editor()->textMode() == KRichTextEdit::Rich && mComposerBase->editor()->isEnableImageActions() ) {
2149  QImage image = qvariant_cast<QImage>( source->imageData() );
2150  QFileInfo fi( source->text() );
2151 
2152  KMenu menu;
2153  const QAction *addAsInlineImageAction = menu.addAction( i18n("Add as &Inline Image") );
2154  /*const QAction *addAsAttachmentAction = */menu.addAction( i18n("Add as &Attachment") );
2155  const QAction *selectedAction = menu.exec( QCursor::pos() );
2156  if ( selectedAction == addAsInlineImageAction ) {
2157  // Let the textedit from kdepimlibs handle inline images
2158  mComposerBase->editor()->insertImage( image, fi );
2159  return true;
2160  } else if( !selectedAction ) {
2161  return true;
2162  }
2163  // else fall through
2164  }
2165  }
2166  // Ok, when we reached this point, the user wants to add the image as an attachment.
2167  // Ask for the filename first.
2168  bool ok;
2169  const QString attName =
2170  KInputDialog::getText( i18n("KMail"), i18n( "Name of the attachment:" ), QString(), &ok, this );
2171  if ( !ok ) {
2172  return true;
2173  }
2174  addAttachment( attName, KMime::Headers::CEbase64, QString(), imageData, "image/png" );
2175  return true;
2176  }
2177 
2178  // If this is a URL list, add those files as attachments or text
2179  const KUrl::List urlList = KUrl::List::fromMimeData( source );
2180  if ( !urlList.isEmpty() ) {
2181  //Search if it's message items.
2182  Akonadi::Item::List items;
2183  Akonadi::Collection::List collections;
2184  bool allLocalURLs = true;
2185 
2186  foreach ( const KUrl &url, urlList ) {
2187  if ( !url.isLocalFile() ) {
2188  allLocalURLs = false;
2189  }
2190  const Akonadi::Item item = Akonadi::Item::fromUrl( url );
2191  if ( item.isValid() ) {
2192  items << item;
2193  } else {
2194  const Akonadi::Collection collection = Akonadi::Collection::fromUrl( url );
2195  if ( collection.isValid() )
2196  collections << collection;
2197  }
2198  }
2199 
2200  if ( items.isEmpty() && collections.isEmpty() ) {
2201  if ( allLocalURLs || forceAttachment ) {
2202  foreach( const KUrl &url, urlList ) {
2203  addAttachment( url, QString() );
2204  }
2205  } else {
2206  KMenu p;
2207  const QAction *addAsTextAction = p.addAction( i18np("Add URL into Message as &Text", "Add URLs into Message as &Text", urlList.size() ) );
2208  const QAction *addAsAttachmentAction = p.addAction( i18np("Add File as &Attachment", "Add Files as &Attachment", urlList.size() ) );
2209  const QAction *selectedAction = p.exec( QCursor::pos() );
2210 
2211  if ( selectedAction == addAsTextAction ) {
2212  foreach( const KUrl &url, urlList ) {
2213  mComposerBase->editor()->textCursor().insertText(url.url() + QLatin1Char('\n'));
2214  }
2215  } else if ( selectedAction == addAsAttachmentAction ) {
2216  foreach( const KUrl &url, urlList ) {
2217  addAttachment( url, QString() );
2218  }
2219  }
2220  }
2221  return true;
2222  } else {
2223  if ( !items.isEmpty() ){
2224  Akonadi::ItemFetchJob *itemFetchJob = new Akonadi::ItemFetchJob( items, this );
2225  itemFetchJob->fetchScope().fetchFullPayload( true );
2226  itemFetchJob->fetchScope().setAncestorRetrieval( Akonadi::ItemFetchScope::Parent );
2227  connect( itemFetchJob, SIGNAL(result(KJob*)), this, SLOT(slotFetchJob(KJob*)) );
2228  }
2229  if ( !collections.isEmpty() ) {
2230  //TODO
2231  }
2232  return true;
2233  }
2234  }
2235  return false;
2236 }
2237 
2238 void KMComposeWin::slotPasteAsAttachment()
2239 {
2240  const QMimeData *mimeData = QApplication::clipboard()->mimeData();
2241  if ( insertFromMimeData( mimeData, true ) )
2242  return;
2243  if( mimeData->hasText() ) {
2244  bool ok;
2245  const QString attName = KInputDialog::getText(
2246  i18n( "Insert clipboard text as attachment" ),
2247  i18n( "Name of the attachment:" ),
2248  QString(), &ok, this );
2249  if( ok ) {
2250  mComposerBase->addAttachment( attName, attName, QLatin1String("utf-8"), QApplication::clipboard()->text().toUtf8(), "text/plain" );
2251  }
2252  return;
2253  }
2254 }
2255 
2256 
2257 void KMComposeWin::slotFetchJob(KJob*job)
2258 {
2259  if ( job->error() ) {
2260  if ( static_cast<KIO::Job*>(job)->ui() )
2261  static_cast<KIO::Job*>(job)->ui()->showErrorMessage();
2262  else
2263  kDebug()<<" job->errorString() :"<<job->errorString();
2264  return;
2265  }
2266  Akonadi::ItemFetchJob *fjob = dynamic_cast<Akonadi::ItemFetchJob*>( job );
2267  if ( !fjob )
2268  return;
2269  const Akonadi::Item::List items = fjob->items();
2270 
2271  if ( items.isEmpty() )
2272  return;
2273 
2274  if ( items.first().mimeType() == KMime::Message::mimeType() ) {
2275  uint identity = 0;
2276  if ( items.at( 0 ).isValid() && items.at( 0 ).parentCollection().isValid() ) {
2277  QSharedPointer<MailCommon::FolderCollection> fd( MailCommon::FolderCollection::forCollection( items.at( 0 ).parentCollection(), false ) );
2278  if ( fd )
2279  identity = fd->identity();
2280  }
2281  KMCommand *command = new KMForwardAttachedCommand( this, items,identity, this );
2282  command->start();
2283  } else {
2284  foreach ( const Akonadi::Item &item, items ) {
2285  QString attachmentName = QLatin1String( "attachment" );
2286  if ( item.hasPayload<KABC::Addressee>() ) {
2287  const KABC::Addressee contact = item.payload<KABC::Addressee>();
2288  attachmentName = contact.realName() + QLatin1String( ".vcf" );
2289  //Workaround about broken kaddressbook fields.
2290  QByteArray data = item.payloadData();
2291  data.replace("X-messaging/aim-All",("X-AIM"));
2292  data.replace("X-messaging/icq-All",("X-ICQ"));
2293  data.replace("X-messaging/xmpp-All",("X-JABBER"));
2294  data.replace("X-messaging/msn-All",("X-MSN"));
2295  data.replace("X-messaging/yahoo-All",("X-YAHOO"));
2296  data.replace("X-messaging/gadu-All",("X-GADUGADU"));
2297  data.replace("X-messaging/skype-All",("X-SKYPE"));
2298  data.replace("X-messaging/groupwise-All",("X-GROUPWISE"));
2299  data.replace(("X-messaging/sms-All"),("X-SMS"));
2300  data.replace(("X-messaging/meanwhile-All"),("X-MEANWHILE"));
2301  data.replace(("X-messaging/irc-All"),("X-IRC"));
2302  data.replace(("X-messaging/googletalk-All"),("X-GOOGLETALK"));
2303  addAttachment( attachmentName, KMime::Headers::CEbase64, QString(), data, item.mimeType().toLatin1() );
2304  } else {
2305  addAttachment( attachmentName, KMime::Headers::CEbase64, QString(), item.payloadData(), item.mimeType().toLatin1() );
2306  }
2307  }
2308  }
2309 }
2310 
2311 QString KMComposeWin::addQuotesToText( const QString &inputText ) const
2312 {
2313  QString answer( inputText );
2314  const QString indentStr = mComposerBase->editor()->quotePrefixName();
2315  answer.replace( QLatin1Char('\n'), QLatin1Char('\n') + indentStr );
2316  answer.prepend( indentStr );
2317  answer += QLatin1Char('\n');
2318  return MessageCore::StringUtil::smartQuote( answer, MessageComposer::MessageComposerSettings::self()->lineWrapWidth() );
2319 }
2320 
2321 //-----------------------------------------------------------------------------
2322 void KMComposeWin::slotUndo()
2323 {
2324  QWidget *fw = focusWidget();
2325  if ( !fw ) {
2326  return;
2327  }
2328 
2329  if (::qobject_cast<MessageComposer::SubjectLineEditWithAutoCorrection*>( fw )) {
2330  static_cast<MessageComposer::SubjectLineEditWithAutoCorrection*>( fw )->undo();
2331  }else if ( ::qobject_cast<KMComposerEditor*>( fw ) ) {
2332  static_cast<KTextEdit*>( fw )->undo();
2333  } else if (::qobject_cast<KLineEdit*>( fw )) {
2334  static_cast<KLineEdit*>( fw )->undo();
2335  }
2336 }
2337 
2338 void KMComposeWin::slotRedo()
2339 {
2340  QWidget *fw = focusWidget();
2341  if ( !fw ) {
2342  return;
2343  }
2344 
2345  if (::qobject_cast<MessageComposer::SubjectLineEditWithAutoCorrection*>( fw )) {
2346  static_cast<MessageComposer::SubjectLineEditWithAutoCorrection*>( fw )->redo();
2347  } else if ( ::qobject_cast<KMComposerEditor*>( fw ) ) {
2348  static_cast<KTextEdit*>( fw )->redo();
2349  } else if (::qobject_cast<KLineEdit*>( fw )) {
2350  static_cast<KLineEdit*>( fw )->redo();
2351  }
2352 }
2353 
2354 //-----------------------------------------------------------------------------
2355 void KMComposeWin::slotCut()
2356 {
2357  QWidget *fw = focusWidget();
2358  if ( !fw ) {
2359  return;
2360  }
2361 
2362  if ( ::qobject_cast<MessageComposer::SubjectLineEditWithAutoCorrection*>( fw ) ) {
2363  static_cast<MessageComposer::SubjectLineEditWithAutoCorrection*>( fw )->cut();
2364  } else if ( ::qobject_cast<KMComposerEditor*>( fw ) ) {
2365  static_cast<KTextEdit*>(fw)->cut();
2366  } else if ( ::qobject_cast<KLineEdit*>( fw ) ) {
2367  static_cast<KLineEdit*>( fw )->cut();
2368  }
2369 }
2370 
2371 //-----------------------------------------------------------------------------
2372 void KMComposeWin::slotCopy()
2373 {
2374  QWidget *fw = focusWidget();
2375  if ( !fw ) {
2376  return;
2377  }
2378 
2379  if ( ::qobject_cast<MessageComposer::SubjectLineEditWithAutoCorrection*>( fw ) ) {
2380  static_cast<MessageComposer::SubjectLineEditWithAutoCorrection*>( fw )->copy();
2381  } else if ( ::qobject_cast<KMComposerEditor*>( fw ) ) {
2382  static_cast<KTextEdit*>(fw)->copy();
2383  } else if ( ::qobject_cast<KLineEdit*>( fw ) ) {
2384  static_cast<KLineEdit*>( fw )->copy();
2385  }
2386 }
2387 
2388 //-----------------------------------------------------------------------------
2389 void KMComposeWin::slotPaste()
2390 {
2391  QWidget * const fw = focusWidget();
2392  if ( !fw ) {
2393  return;
2394  }
2395  if ( ::qobject_cast<MessageComposer::SubjectLineEditWithAutoCorrection*>( fw ) ) {
2396  static_cast<MessageComposer::SubjectLineEditWithAutoCorrection*>( fw )->paste();
2397  } else if ( ::qobject_cast<KMComposerEditor*>( fw ) ) {
2398  static_cast<KTextEdit*>(fw)->paste();
2399  } else if ( ::qobject_cast<KLineEdit*>( fw ) ) {
2400  static_cast<KLineEdit*>( fw )->paste();
2401  }
2402 }
2403 
2404 //-----------------------------------------------------------------------------
2405 void KMComposeWin::slotMarkAll()
2406 {
2407  QWidget *fw = focusWidget();
2408  if ( !fw ) {
2409  return;
2410  }
2411 
2412  if (::qobject_cast<MessageComposer::SubjectLineEditWithAutoCorrection*>( fw )) {
2413  static_cast<MessageComposer::SubjectLineEditWithAutoCorrection*>( fw )->selectAll();
2414  } else if ( ::qobject_cast<KLineEdit*>( fw ) ) {
2415  static_cast<KLineEdit*>( fw )->selectAll();
2416  } else if (::qobject_cast<KMComposerEditor*>( fw )) {
2417  static_cast<KTextEdit*>( fw )->selectAll();
2418  }
2419 }
2420 
2421 //-----------------------------------------------------------------------------
2422 void KMComposeWin::slotClose()
2423 {
2424  close();
2425 }
2426 
2427 //-----------------------------------------------------------------------------
2428 void KMComposeWin::slotNewComposer()
2429 {
2430  KMComposeWin *win;
2431  KMime::Message::Ptr msg( new KMime::Message );
2432 
2433  MessageHelper::initHeader( msg, KMKernel::self()->identityManager() );
2434  win = new KMComposeWin( msg, false, false );
2435  win->show();
2436 }
2437 
2438 //-----------------------------------------------------------------------------
2439 void KMComposeWin::slotNewMailReader()
2440 {
2441  KMMainWin *kmmwin = new KMMainWin( 0 );
2442  kmmwin->show();
2443 }
2444 
2445 //-----------------------------------------------------------------------------
2446 void KMComposeWin::slotUpdWinTitle()
2447 {
2448  QString s( mEdtSubject->toPlainText() );
2449  // Remove characters that show badly in most window decorations:
2450  // newlines tend to become boxes.
2451  if ( s.isEmpty() ) {
2452  setCaption( QLatin1Char('(') + i18n("unnamed") + QLatin1Char(')') );
2453  } else {
2454  setCaption( s.replace( QLatin1Char('\n'), QLatin1Char(' ') ) );
2455  }
2456 }
2457 
2458 //-----------------------------------------------------------------------------
2459 void KMComposeWin::slotEncryptToggled( bool on )
2460 {
2461  setEncryption( on, true );
2462  slotUpdateSignatureAndEncrypionStateIndicators();
2463 }
2464 
2465 //-----------------------------------------------------------------------------
2466 void KMComposeWin::setEncryption( bool encrypt, bool setByUser )
2467 {
2468  bool wasModified = isModified();
2469  if ( setByUser ) {
2470  setModified( true );
2471  }
2472  if ( !mEncryptAction->isEnabled() ) {
2473  encrypt = false;
2474  }
2475  // check if the user wants to encrypt messages to himself and if he defined
2476  // an encryption key for the current identity
2477  else if ( encrypt && encryptToSelf() && !mLastIdentityHasEncryptionKey ) {
2478  if ( setByUser ) {
2479  KMessageBox::sorry( this,
2480  i18n("<qt><p>You have requested that messages be "
2481  "encrypted to yourself, but the currently selected "
2482  "identity does not define an (OpenPGP or S/MIME) "
2483  "encryption key to use for this.</p>"
2484  "<p>Please select the key(s) to use "
2485  "in the identity configuration.</p>"
2486  "</qt>"),
2487  i18n("Undefined Encryption Key") );
2488  setModified( wasModified );
2489  }
2490  encrypt = false;
2491  }
2492 
2493  // make sure the mEncryptAction is in the right state
2494  mEncryptAction->setChecked( encrypt );
2495  if(!setByUser) {
2496  slotUpdateSignatureAndEncrypionStateIndicators();
2497  }
2498  // show the appropriate icon
2499  if ( encrypt ) {
2500  mEncryptAction->setIcon( KIcon( QLatin1String("document-encrypt") ) );
2501  } else {
2502  mEncryptAction->setIcon( KIcon( QLatin1String("document-decrypt") ) );
2503  }
2504 
2505  // mark the attachments for (no) encryption
2506  if( canSignEncryptAttachments() ) {
2507  mComposerBase->attachmentModel()->setEncryptSelected( encrypt );
2508  }
2509 }
2510 
2511 //-----------------------------------------------------------------------------
2512 void KMComposeWin::slotSignToggled( bool on )
2513 {
2514  setSigning( on, true );
2515  slotUpdateSignatureAndEncrypionStateIndicators();
2516 }
2517 
2518 //-----------------------------------------------------------------------------
2519 void KMComposeWin::setSigning( bool sign, bool setByUser )
2520 {
2521  bool wasModified = isModified();
2522  if ( setByUser ) {
2523  setModified( true );
2524  }
2525  if ( !mSignAction->isEnabled() ) {
2526  sign = false;
2527  }
2528 
2529  // check if the user defined a signing key for the current identity
2530  if ( sign && !mLastIdentityHasSigningKey ) {
2531  if ( setByUser ) {
2532  KMessageBox::sorry( this,
2533  i18n("<qt><p>In order to be able to sign "
2534  "this message you first have to "
2535  "define the (OpenPGP or S/MIME) signing key "
2536  "to use.</p>"
2537  "<p>Please select the key to use "
2538  "in the identity configuration.</p>"
2539  "</qt>"),
2540  i18n("Undefined Signing Key") );
2541  setModified( wasModified );
2542  }
2543  sign = false;
2544  }
2545 
2546  // make sure the mSignAction is in the right state
2547  mSignAction->setChecked( sign );
2548 
2549  if(!setByUser) {
2550  slotUpdateSignatureAndEncrypionStateIndicators();
2551  }
2552  // mark the attachments for (no) signing
2553  if ( canSignEncryptAttachments() ) {
2554  mComposerBase->attachmentModel()->setSignSelected( sign );
2555  }
2556 }
2557 
2558 //-----------------------------------------------------------------------------
2559 void KMComposeWin::slotWordWrapToggled( bool on )
2560 {
2561  if ( on )
2562  mComposerBase->editor()->enableWordWrap( MessageComposer::MessageComposerSettings::self()->lineWrapWidth() );
2563  else
2564  disableWordWrap();
2565 }
2566 
2567 //-----------------------------------------------------------------------------
2568 void KMComposeWin::disableWordWrap()
2569 {
2570  mComposerBase->editor()->disableWordWrap();
2571 }
2572 
2573 //-----------------------------------------------------------------------------
2574 void KMComposeWin::forceDisableHtml()
2575 {
2576  mForceDisableHtml = true;
2577  disableHtml( MessageComposer::ComposerViewBase::NoConfirmationNeeded );
2578  markupAction->setEnabled( false );
2579  // FIXME: Remove the toggle toolbar action somehow
2580 }
2581 
2582 void KMComposeWin::disableForgottenAttachmentsCheck()
2583 {
2584  mCheckForForgottenAttachments = false;
2585 }
2586 
2587 void KMComposeWin::ignoreStickyFields()
2588 {
2589  mIgnoreStickyFields = true;
2590  mBtnTransport->setChecked( false );
2591  mBtnDictionary->setChecked( false );
2592  mBtnIdentity->setChecked( false );
2593  mBtnTransport->setEnabled( false );
2594  mBtnDictionary->setEnabled( false );
2595  mBtnIdentity->setEnabled( false );
2596 }
2597 
2598 
2599 void KMComposeWin::slotPrint()
2600 {
2601  printComposer(false);
2602 }
2603 
2604 void KMComposeWin::slotPrintPreview()
2605 {
2606  printComposer(true);
2607 }
2608 
2609 void KMComposeWin::printComposer(bool preview)
2610 {
2611  MessageComposer::Composer* composer = createSimpleComposer();
2612  mMiscComposers.append( composer );
2613  composer->setProperty("preview",preview);
2614  connect( composer, SIGNAL(result(KJob*)),
2615  this, SLOT(slotPrintComposeResult(KJob*)) );
2616  composer->start();
2617 }
2618 
2619 void KMComposeWin::slotPrintComposeResult( KJob *job )
2620 {
2621  const bool preview = job->property("preview").toBool();
2622  printComposeResult( job, preview );
2623 }
2624 
2625 void KMComposeWin::printComposeResult( KJob *job, bool preview )
2626 {
2627  Q_ASSERT( dynamic_cast< MessageComposer::Composer* >( job ) );
2628  MessageComposer::Composer* composer = dynamic_cast< MessageComposer::Composer* >( job );
2629  Q_ASSERT( mMiscComposers.contains( composer ) );
2630  mMiscComposers.removeAll( composer );
2631 
2632  if( composer->error() == MessageComposer::Composer::NoError ) {
2633 
2634  Q_ASSERT( composer->resultMessages().size() == 1 );
2635  Akonadi::Item printItem;
2636  printItem.setPayload<KMime::Message::Ptr>( composer->resultMessages().first() );
2637  const bool isHtml = ( mComposerBase->editor()->textMode() == KMeditor::Rich );
2638  KMPrintCommand *command = new KMPrintCommand( this, printItem,0,
2639  0, isHtml, isHtml );
2640  command->setPrintPreview( preview );
2641  command->start();
2642  } else {
2643  if ( static_cast<KIO::Job*>(job)->ui() ) {
2644  static_cast<KIO::Job*>(job)->ui()->showErrorMessage();
2645  } else {
2646  kWarning() << "Composer for printing failed:" << composer->errorString();
2647  }
2648  }
2649 
2650 }
2651 
2652 //----------------------------------------------------------------------------
2653 void KMComposeWin::doSend( MessageComposer::MessageSender::SendMethod method,
2654  MessageComposer::MessageSender::SaveIn saveIn )
2655 {
2656  // TODO integrate with MDA online status
2657  if ( method == MessageComposer::MessageSender::SendImmediate ) {
2658  if( !MessageComposer::Util::sendMailDispatcherIsOnline() ) {
2659  method = MessageComposer::MessageSender::SendLater;
2660  }
2661  }
2662 
2663 
2664  if ( saveIn == MessageComposer::MessageSender::SaveInNone ) { // don't save as draft or template, send immediately
2665  if ( KPIMUtils::firstEmailAddress( from() ).isEmpty() ) {
2666  if ( !( mShowHeaders & HDR_FROM ) ) {
2667  mShowHeaders |= HDR_FROM;
2668  rethinkFields( false );
2669  }
2670  mEdtFrom->setFocus();
2671  KMessageBox::sorry( this,
2672  i18n("You must enter your email address in the "
2673  "From: field. You should also set your email "
2674  "address for all identities, so that you do "
2675  "not have to enter it for each message.") );
2676  return;
2677  }
2678  if ( mComposerBase->to().isEmpty() ) {
2679  if ( mComposerBase->cc().isEmpty() && mComposerBase->bcc().isEmpty() ) {
2680  KMessageBox::information( this,
2681  i18n("You must specify at least one receiver, "
2682  "either in the To: field or as CC or as BCC.") );
2683 
2684  return;
2685  } else {
2686  int rc = KMessageBox::questionYesNo( this,
2687  i18n("To: field is empty. "
2688  "Send message anyway?"),
2689  i18n("No To: specified"),
2690  KStandardGuiItem::yes(),
2691  KStandardGuiItem::no(),
2692  QLatin1String(":kmail_no_to_field_specified") );
2693  if ( rc == KMessageBox::No ) {
2694  return;
2695  }
2696  }
2697  }
2698 
2699  if ( subject().isEmpty() ) {
2700  mEdtSubject->setFocus();
2701  int rc =
2702  KMessageBox::questionYesNo( this,
2703  i18n("You did not specify a subject. "
2704  "Send message anyway?"),
2705  i18n("No Subject Specified"),
2706  KGuiItem(i18n("S&end as Is")),
2707  KGuiItem(i18n("&Specify the Subject")),
2708  QLatin1String("no_subject_specified") );
2709  if ( rc == KMessageBox::No ) {
2710  return;
2711  }
2712  }
2713 
2714  const MessageComposer::ComposerViewBase::MissingAttachment forgotAttachment = userForgotAttachment();
2715  if ( (forgotAttachment == MessageComposer::ComposerViewBase::FoundMissingAttachmentAndAddedAttachment) ||
2716  (forgotAttachment == MessageComposer::ComposerViewBase::FoundMissingAttachmentAndCancel) ) {
2717  return;
2718  }
2719 
2720 
2721  setEnabled( false );
2722  // Validate the To:, CC: and BCC fields
2723  const QStringList recipients = QStringList() << mComposerBase->to().trimmed() << mComposerBase->cc().trimmed() << mComposerBase->bcc().trimmed();
2724 
2725  AddressValidationJob *job = new AddressValidationJob( recipients.join( QLatin1String( ", ") ), this, this );
2726  job->setProperty( "method", static_cast<int>( method ) );
2727  job->setProperty( "saveIn", static_cast<int>( saveIn ) );
2728  connect( job, SIGNAL(result(KJob*)), SLOT(slotDoDelayedSend(KJob*)) );
2729  job->start();
2730 
2731  // we'll call send from within slotDoDelaySend
2732  } else {
2733  if( saveIn == MessageComposer::MessageSender::SaveInDrafts && mEncryptAction->isChecked() &&
2734  !GlobalSettings::self()->neverEncryptDrafts() &&
2735  mComposerBase->to().isEmpty() && mComposerBase->cc().isEmpty() ) {
2736 
2737  KMessageBox::information( this, i18n("You must specify at least one receiver "
2738  "in order to be able to encrypt a draft.")
2739  );
2740  return;
2741  }
2742  doDelayedSend( method, saveIn );
2743  }
2744 }
2745 
2746 void KMComposeWin::slotDoDelayedSend( KJob *job )
2747 {
2748  if ( job->error() ) {
2749  KMessageBox::error( this, job->errorText() );
2750  setEnabled(true);
2751  return;
2752  }
2753 
2754  const AddressValidationJob *validateJob = qobject_cast<AddressValidationJob*>( job );
2755 
2756  // Abort sending if one of the recipient addresses is invalid ...
2757  if ( !validateJob->isValid() ) {
2758  setEnabled(true);
2759  return;
2760  }
2761 
2762  // ... otherwise continue as usual
2763  const MessageComposer::MessageSender::SendMethod method = static_cast<MessageComposer::MessageSender::SendMethod>( job->property( "method" ).toInt() );
2764  const MessageComposer::MessageSender::SaveIn saveIn = static_cast<MessageComposer::MessageSender::SaveIn>( job->property( "saveIn" ).toInt() );
2765 
2766  doDelayedSend( method, saveIn );
2767 }
2768 
2769 void KMComposeWin::applyComposerSetting( MessageComposer::ComposerViewBase* mComposerBase )
2770 {
2771 
2772  QList< QByteArray > charsets = mCodecAction->mimeCharsets();
2773  if( !mOriginalPreferredCharset.isEmpty() ) {
2774  charsets.insert( 0, mOriginalPreferredCharset );
2775  }
2776  mComposerBase->setFrom( from() );
2777  mComposerBase->setReplyTo( replyTo() );
2778  mComposerBase->setSubject( subject() );
2779  mComposerBase->setCharsets( charsets );
2780  mComposerBase->setUrgent( mUrgentAction->isChecked() );
2781  mComposerBase->setMDNRequested( mRequestMDNAction->isChecked() );
2782 }
2783 
2784 
2785 void KMComposeWin::doDelayedSend( MessageComposer::MessageSender::SendMethod method, MessageComposer::MessageSender::SaveIn saveIn )
2786 {
2787 #ifndef QT_NO_CURSOR
2788  MessageViewer::KCursorSaver busy( MessageViewer::KBusyPtr::busy() );
2789 #endif
2790  applyComposerSetting( mComposerBase );
2791  if ( mForceDisableHtml )
2792  disableHtml( MessageComposer::ComposerViewBase::NoConfirmationNeeded );
2793  bool sign = mSignAction->isChecked();
2794  bool encrypt = mEncryptAction->isChecked();
2795 
2796  mComposerBase->setCryptoOptions( sign, encrypt, cryptoMessageFormat(),
2797  ( ( saveIn != MessageComposer::MessageSender::SaveInNone && GlobalSettings::self()->neverEncryptDrafts() )
2798  || mSigningAndEncryptionExplicitlyDisabled ) );
2799 
2800  const int num = GlobalSettings::self()->customMessageHeadersCount();
2801  QMap<QByteArray, QString> customHeader;
2802  for (int ix=0; ix<num; ++ix) {
2803  CustomMimeHeader customMimeHeader( QString::number(ix) );
2804  customMimeHeader.readConfig();
2805  customHeader.insert(customMimeHeader.custHeaderName().toLatin1(), customMimeHeader.custHeaderValue() );
2806  }
2807 
2808  QMapIterator<QByteArray, QString> extraCustomHeader(mExtraHeaders);
2809  while (extraCustomHeader.hasNext()) {
2810  extraCustomHeader.next();
2811  customHeader.insert(extraCustomHeader.key(), extraCustomHeader.value() );
2812  }
2813 
2814  mComposerBase->setCustomHeader( customHeader );
2815  mComposerBase->send( method, saveIn, false );
2816 }
2817 
2818 //----------------------------------------------------------------------------
2819 void KMComposeWin::slotSendLater()
2820 {
2821  if ( !TransportManager::self()->showTransportCreationDialog( this, TransportManager::IfNoTransportExists ) )
2822  return;
2823  if ( !checkRecipientNumber() )
2824  return;
2825  if ( mComposerBase->editor()->checkExternalEditorFinished() ) {
2826  const bool wasRegistered = (SendLater::SendLaterUtil::sentLaterAgentWasRegistered() && SendLater::SendLaterUtil::sentLaterAgentEnabled());
2827  if (wasRegistered) {
2828  SendLater::SendLaterInfo *info = 0;
2829  QPointer<SendLater::SendLaterDialog> dlg = new SendLater::SendLaterDialog(info, this);
2830  if (dlg->exec()) {
2831  info = dlg->info();
2832  const SendLater::SendLaterDialog::SendLaterAction action = dlg->action();
2833  delete dlg;
2834  switch (action) {
2835  case SendLater::SendLaterDialog::Unknown:
2836  kDebug()<<"Sendlater action \"Unknown\": Need to fix it.";
2837  break;
2838  case SendLater::SendLaterDialog::Canceled:
2839  return;
2840  break;
2841  case SendLater::SendLaterDialog::PutInOutbox:
2842  doSend( MessageComposer::MessageSender::SendLater );
2843  break;
2844  case SendLater::SendLaterDialog::SendDeliveryAtTime:
2845  {
2846  mComposerBase->setSendLaterInfo(info);
2847  if (info->isRecurrence()) {
2848  doSend( MessageComposer::MessageSender::SendLater, MessageComposer::MessageSender::SaveInTemplates );
2849  } else {
2850  doSend( MessageComposer::MessageSender::SendLater, MessageComposer::MessageSender::SaveInDrafts );
2851  }
2852  break;
2853  }
2854  }
2855  } else {
2856  delete dlg;
2857  }
2858  } else {
2859  doSend( MessageComposer::MessageSender::SendLater );
2860  }
2861  }
2862 }
2863 
2864 //----------------------------------------------------------------------------
2865 void KMComposeWin::slotSaveDraft()
2866 {
2867  if ( mComposerBase->editor()->checkExternalEditorFinished() ) {
2868  doSend( MessageComposer::MessageSender::SendLater, MessageComposer::MessageSender::SaveInDrafts );
2869  }
2870 }
2871 
2872 //----------------------------------------------------------------------------
2873 void KMComposeWin::slotSaveTemplate()
2874 {
2875  if ( mComposerBase->editor()->checkExternalEditorFinished() ) {
2876  doSend( MessageComposer::MessageSender::SendLater, MessageComposer::MessageSender::SaveInTemplates );
2877  }
2878 }
2879 
2880 //----------------------------------------------------------------------------
2881 void KMComposeWin::slotSendNowVia( QAction *item )
2882 {
2883  const QList<int> availTransports= TransportManager::self()->transportIds();
2884  const int transport = item->data().toInt();
2885  if ( availTransports.contains( transport ) ) {
2886  mComposerBase->transportComboBox()->setCurrentTransport( transport );
2887  slotSendNow();
2888  }
2889 }
2890 
2891 //----------------------------------------------------------------------------
2892 void KMComposeWin::slotSendLaterVia( QAction *item )
2893 {
2894  const QList<int> availTransports= TransportManager::self()->transportIds();
2895  const int transport = item->data().toInt();
2896  if ( availTransports.contains( transport ) ) {
2897  mComposerBase->transportComboBox()->setCurrentTransport( transport );
2898  slotSendLater();
2899  }
2900 }
2901 
2902 //----------------------------------------------------------------------------
2903 void KMComposeWin::slotSendNow()
2904 {
2905  if ( !mComposerBase->editor()->checkExternalEditorFinished() ) {
2906  return;
2907  }
2908  if ( !TransportManager::self()->showTransportCreationDialog( this, TransportManager::IfNoTransportExists ) )
2909  return;
2910  if ( !checkRecipientNumber() )
2911  return;
2912 
2913  if( GlobalSettings::self()->checkSpellingBeforeSend()) {
2914 #ifdef HAVE_FORCESPELLCHECKING
2915  mComposerBase->editor()->forceSpellChecking();
2916 #else
2917  slotCheckSendNow();
2918 #endif
2919  } else {
2920  slotCheckSendNow();
2921  }
2922 }
2923 
2924 void KMComposeWin::slotCheckSendNow()
2925 {
2926  if ( GlobalSettings::self()->confirmBeforeSend() ) {
2927  int rc = KMessageBox::warningYesNoCancel( mMainWidget,
2928  i18n("About to send email..."),
2929  i18n("Send Confirmation"),
2930  KGuiItem( i18n("&Send Now") ),
2931  KGuiItem( i18n("Send &Later") ) );
2932 
2933  if ( rc == KMessageBox::Yes ) {
2934  doSend( MessageComposer::MessageSender::SendImmediate );
2935  } else if ( rc == KMessageBox::No ) {
2936  doSend( MessageComposer::MessageSender::SendLater );
2937  }
2938  } else {
2939  doSend( MessageComposer::MessageSender::SendImmediate );
2940  }
2941 }
2942 
2943 //----------------------------------------------------------------------------
2944 bool KMComposeWin::checkRecipientNumber() const
2945 {
2946  const int thresHold = GlobalSettings::self()->recipientThreshold();
2947  if ( GlobalSettings::self()->tooManyRecipients() && mComposerBase->recipientsEditor()->recipients().count() > thresHold ) {
2948  if ( KMessageBox::questionYesNo( mMainWidget,
2949  i18n("You are trying to send the mail to more than %1 recipients. Send message anyway?", thresHold),
2950  i18n("Too many recipients"),
2951  KGuiItem( i18n("&Send as Is") ),
2952  KGuiItem( i18n("&Edit Recipients") ) ) == KMessageBox::No ) {
2953  return false;
2954  }
2955  }
2956  return true;
2957 }
2958 
2959 //-----------------------------------------------------------------------------
2960 void KMComposeWin::slotHelp()
2961 {
2962  KToolInvocation::invokeHelp();
2963 }
2964 
2965 //-----------------------------------------------------------------------------
2966 void KMComposeWin::enableHtml()
2967 {
2968  if ( mForceDisableHtml ) {
2969  disableHtml( MessageComposer::ComposerViewBase::NoConfirmationNeeded );
2970  return;
2971  }
2972 
2973  mComposerBase->editor()->enableRichTextMode();
2974  if ( !toolBar( QLatin1String("htmlToolBar") )->isVisible() ) {
2975  // Use singleshot, as we we might actually be called from a slot that wanted to disable the
2976  // toolbar (but the messagebox in disableHtml() prevented that and called us).
2977  // The toolbar can't correctly deal with being enabled right in a slot called from the "disabled"
2978  // signal, so wait one event loop run for that.
2979  QTimer::singleShot( 0, toolBar( QLatin1String("htmlToolBar") ), SLOT(show()) );
2980  }
2981  if ( !markupAction->isChecked() )
2982  markupAction->setChecked( true );
2983 
2984  mComposerBase->editor()->updateActionStates();
2985  mComposerBase->editor()->setActionsEnabled( true );
2986 }
2987 
2988 
2989 
2990 //-----------------------------------------------------------------------------
2991 void KMComposeWin::disableHtml( MessageComposer::ComposerViewBase::Confirmation confirmation )
2992 {
2993  bool forcePlainTextMarkup = false;
2994  if ( confirmation == MessageComposer::ComposerViewBase::LetUserConfirm && mComposerBase->editor()->isFormattingUsed() && !mForceDisableHtml ) {
2995  int choice = KMessageBox::warningYesNoCancel( this, i18n( "Turning HTML mode off "
2996  "will cause the text to lose the formatting. Are you sure?" ),
2997  i18n( "Lose the formatting?" ), KGuiItem( i18n( "Lose Formatting" ) ), KGuiItem( i18n( "Add Markup Plain Text" ) ) , KStandardGuiItem::cancel(),
2998  QLatin1String("LoseFormattingWarning") );
2999 
3000  switch(choice) {
3001  case KMessageBox::Cancel:
3002  enableHtml();
3003  return;
3004  case KMessageBox::No:
3005  forcePlainTextMarkup = true;
3006  break;
3007  case KMessageBox::Yes:
3008  break;
3009  }
3010  }
3011 
3012  mComposerBase->editor()->forcePlainTextMarkup(forcePlainTextMarkup);
3013  mComposerBase->editor()->switchToPlainText();
3014  mComposerBase->editor()->setActionsEnabled( false );
3015 
3016  slotUpdateFont();
3017  if ( toolBar( QLatin1String("htmlToolBar") )->isVisible() ) {
3018  // See the comment in enableHtml() why we use a singleshot timer, similar situation here.
3019  QTimer::singleShot( 0, toolBar( QLatin1String("htmlToolBar") ), SLOT(hide()) );
3020  }
3021  if ( markupAction->isChecked() )
3022  markupAction->setChecked( false );
3023 }
3024 
3025 //-----------------------------------------------------------------------------
3026 void KMComposeWin::slotToggleMarkup()
3027 {
3028  htmlToolBarVisibilityChanged( markupAction->isChecked() );
3029 }
3030 
3031 //-----------------------------------------------------------------------------
3032 void KMComposeWin::slotTextModeChanged( MessageComposer::KMeditor::Mode mode )
3033 {
3034  if ( mode == KMeditor::Plain )
3035  disableHtml( MessageComposer::ComposerViewBase::NoConfirmationNeeded ); // ### Can this happen at all?
3036  else
3037  enableHtml();
3038 }
3039 
3040 //-----------------------------------------------------------------------------
3041 void KMComposeWin::htmlToolBarVisibilityChanged( bool visible )
3042 {
3043  if ( visible )
3044  enableHtml();
3045  else
3046  disableHtml( MessageComposer::ComposerViewBase::LetUserConfirm );
3047 }
3048 
3049 //-----------------------------------------------------------------------------
3050 void KMComposeWin::slotAutoSpellCheckingToggled( bool on )
3051 {
3052  mAutoSpellCheckingAction->setChecked( on );
3053  if ( on != mComposerBase->editor()->checkSpellingEnabled() )
3054  mComposerBase->editor()->setCheckSpellingEnabled( on );
3055  if ( on != mEdtSubject->checkSpellingEnabled() )
3056  mEdtSubject->setCheckSpellingEnabled( on );
3057 
3058 
3059  QString temp;
3060  if ( on ) {
3061  temp = i18n( "Spellcheck: on" );
3062  } else {
3063  temp = i18n( "Spellcheck: off" );
3064  }
3065  statusBar()->changeItem( temp, 3 );
3066 }
3067 
3068 void KMComposeWin::slotSpellCheckingStatus(const QString & status)
3069 {
3070  statusBar()->changeItem( status, 0 );
3071  QTimer::singleShot( 2000, this, SLOT(slotSpellcheckDoneClearStatus()) );
3072 }
3073 
3074 void KMComposeWin::slotSpellcheckDoneClearStatus()
3075 {
3076  statusBar()->changeItem(QString(), 0);
3077 }
3078 
3079 //-----------------------------------------------------------------------------
3080 void KMComposeWin::slotIdentityChanged( uint uoid, bool initalChange )
3081 {
3082  if( mMsg == 0 ) {
3083  kDebug() << "Trying to change identity but mMsg == 0!";
3084  return;
3085  }
3086 
3087  const KPIMIdentities::Identity &ident =
3088  KMKernel::self()->identityManager()->identityForUoid( uoid );
3089  if ( ident.isNull() ) {
3090  return;
3091  }
3092  bool wasModified(isModified());
3093  emit identityChanged( identity() );
3094  if ( !ident.fullEmailAddr().isNull() ) {
3095  mEdtFrom->setText( ident.fullEmailAddr() );
3096  }
3097 
3098  // make sure the From field is shown if it does not contain a valid email address
3099  if ( KPIMUtils::firstEmailAddress( from() ).isEmpty() ) {
3100  mShowHeaders |= HDR_FROM;
3101  }
3102  if ( mEdtReplyTo ) {
3103  mEdtReplyTo->setText( ident.replyToAddr() );
3104  }
3105 
3106  // remove BCC of old identity and add BCC of new identity (if they differ)
3107  const KPIMIdentities::Identity &oldIdentity =
3108  KMKernel::self()->identityManager()->identityForUoidOrDefault( mId );
3109 
3110 
3111  if ( ident.organization().isEmpty() ) {
3112  mMsg->organization()->clear();
3113  } else {
3114  KMime::Headers::Organization * const organization
3115  = new KMime::Headers::Organization( mMsg.get(), ident.organization(), "utf-8" );
3116  mMsg->setHeader( organization );
3117  }
3118  if ( !ident.isXFaceEnabled() || ident.xface().isEmpty() ) {
3119  mMsg->removeHeader( "X-Face" );
3120  } else {
3121  QString xface = ident.xface();
3122  if ( !xface.isEmpty() ) {
3123  int numNL = ( xface.length() - 1 ) / 70;
3124  for ( int i = numNL; i > 0; --i ) {
3125  xface.insert( i*70, QLatin1String("\n\t") );
3126  }
3127  KMime::Headers::Generic *header = new KMime::Headers::Generic( "X-Face", mMsg.get(), xface, "utf-8" );
3128  mMsg->setHeader( header );
3129  }
3130  }
3131  // If the transport sticky checkbox is not checked, set the transport
3132  // from the new identity
3133  if ( !mBtnTransport->isChecked() && !mIgnoreStickyFields ) {
3134  const int transportId = ident.transport().isEmpty() ? -1 : ident.transport().toInt();
3135  const Transport *transport = TransportManager::self()->transportById( transportId, true );
3136  if ( !transport ) {
3137  mMsg->removeHeader( "X-KMail-Transport" );
3138  mComposerBase->transportComboBox()->setCurrentTransport( TransportManager::self()->defaultTransportId() );
3139  } else {
3140  KMime::Headers::Generic *header = new KMime::Headers::Generic( "X-KMail-Transport", mMsg.get(), QString::number( transport->id() ), "utf-8" );
3141  mMsg->setHeader( header );
3142  mComposerBase->transportComboBox()->setCurrentTransport( transport->id() );
3143  }
3144  }
3145 
3146  const bool fccIsDisabled = ident.disabledFcc();
3147  if (fccIsDisabled) {
3148  KMime::Headers::Generic *header = new KMime::Headers::Generic( "X-KMail-FccDisabled", mMsg.get(), QLatin1String("true"), "utf-8" );
3149  mMsg->setHeader( header );
3150  } else {
3151  mMsg->removeHeader( "X-KMail-FccDisabled" );
3152  }
3153  mFccFolder->setEnabled(!fccIsDisabled);
3154 
3155 
3156  if ( !mBtnDictionary->isChecked() && !mIgnoreStickyFields ) {
3157  mDictionaryCombo->setCurrentByDictionaryName( ident.dictionary() );
3158  }
3159  slotSpellCheckingLanguage( mDictionaryCombo->currentDictionary() );
3160  if ( !mBtnFcc->isChecked() && !mPreventFccOverwrite ) {
3161  setFcc( ident.fcc() );
3162  }
3163 
3164  // if unmodified, apply new template, if one is set
3165  if ( !wasModified && !( ident.templates().isEmpty() && mCustomTemplate.isEmpty() ) &&
3166  !initalChange ) {
3167  applyTemplate( uoid, mId );
3168  } else {
3169  mComposerBase->identityChanged( ident, oldIdentity, false );
3170  mEdtSubject->setAutocorrectionLanguage(ident.autocorrectionLanguage());
3171  }
3172 
3173 
3174  // disable certain actions if there is no PGP user identity set
3175  // for this profile
3176  bool bNewIdentityHasSigningKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
3177  bool bNewIdentityHasEncryptionKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
3178  // save the state of the sign and encrypt button
3179  if ( !bNewIdentityHasEncryptionKey && mLastIdentityHasEncryptionKey ) {
3180  mLastEncryptActionState = mEncryptAction->isChecked();
3181  setEncryption( false );
3182  }
3183  if ( !bNewIdentityHasSigningKey && mLastIdentityHasSigningKey ) {
3184  mLastSignActionState = mSignAction->isChecked();
3185  setSigning( false );
3186  }
3187  // restore the last state of the sign and encrypt button
3188  if ( bNewIdentityHasEncryptionKey && !mLastIdentityHasEncryptionKey ) {
3189  setEncryption( mLastEncryptActionState );
3190  }
3191  if ( bNewIdentityHasSigningKey && !mLastIdentityHasSigningKey ) {
3192  setSigning( mLastSignActionState );
3193  }
3194 
3195  mCryptoModuleAction->setCurrentItem( format2cb(
3196  Kleo::stringToCryptoMessageFormat( ident.preferredCryptoMessageFormat() ) ) );
3197  slotSelectCryptoModule( true );
3198 
3199  mLastIdentityHasSigningKey = bNewIdentityHasSigningKey;
3200  mLastIdentityHasEncryptionKey = bNewIdentityHasEncryptionKey;
3201 
3202  mId = uoid;
3203  changeCryptoAction();
3204  // make sure the From and BCC fields are shown if necessary
3205  rethinkFields( false );
3206  setModified(wasModified);
3207 }
3208 
3209 //-----------------------------------------------------------------------------
3210 void KMComposeWin::slotSpellcheckConfig()
3211 {
3212  static_cast<KMComposerEditor *>(mComposerBase->editor())->showSpellConfigDialog( QLatin1String("kmail2rc") );
3213 }
3214 
3215 //-----------------------------------------------------------------------------
3216 void KMComposeWin::slotEditToolbars()
3217 {
3218  saveMainWindowSettings( KMKernel::self()->config()->group( "Composer") );
3219  KEditToolBar dlg( guiFactory(), this );
3220 
3221  connect( &dlg, SIGNAL(newToolBarConfig()),
3222  SLOT(slotUpdateToolbars()) );
3223 
3224  dlg.exec();
3225 }
3226 
3227 void KMComposeWin::slotUpdateToolbars()
3228 {
3229  createGUI( QLatin1String("kmcomposerui.rc") );
3230  applyMainWindowSettings( KMKernel::self()->config()->group( "Composer") );
3231 }
3232 
3233 void KMComposeWin::slotEditKeys()
3234 {
3235  KShortcutsDialog::configure( actionCollection(),
3236  KShortcutsEditor::LetterShortcutsDisallowed );
3237 }
3238 
3239 void KMComposeWin::setFocusToEditor()
3240 {
3241  // The cursor position is already set by setMsg(), so we only need to set the
3242  // focus here.
3243  mComposerBase->editor()->setFocus();
3244 }
3245 
3246 void KMComposeWin::setFocusToSubject()
3247 {
3248  mEdtSubject->setFocus();
3249 }
3250 
3251 void KMComposeWin::slotCompletionModeChanged( KGlobalSettings::Completion mode )
3252 {
3253  GlobalSettings::self()->setCompletionMode( (int) mode );
3254 
3255  // sync all the lineedits to the same completion mode
3256  mEdtFrom->setCompletionMode( mode );
3257  mEdtReplyTo->setCompletionMode( mode );
3258  mComposerBase->recipientsEditor()->setCompletionMode( mode );
3259 }
3260 
3261 void KMComposeWin::slotConfigChanged()
3262 {
3263  readConfig( true /*reload*/);
3264  mComposerBase->updateAutoSave();
3265  rethinkFields();
3266  slotWordWrapToggled( mWordWrapAction->isChecked() );
3267 }
3268 
3269 /*
3270  * checks if the drafts-folder has been deleted
3271  * that is not nice so we set the system-drafts-folder
3272  */
3273 void KMComposeWin::slotFolderRemoved( const Akonadi::Collection & col )
3274 {
3275  kDebug() << "you killed me.";
3276  // TODO: need to handle templates here?
3277  if ( ( mFolder.isValid() ) && ( col.id() == mFolder.id() ) ) {
3278  mFolder = CommonKernel->draftsCollectionFolder();
3279  kDebug() << "restoring drafts to" << mFolder.id();
3280  }
3281 }
3282 
3283 
3284 void KMComposeWin::slotOverwriteModeChanged()
3285 {
3286  mComposerBase->editor()->setCursorWidth( mComposerBase->editor()->overwriteMode () ? 5 : 1 );
3287  statusBar()->changeItem( overwriteModeStr(), 4 );
3288 }
3289 
3290 QString KMComposeWin::overwriteModeStr() const
3291 {
3292  return mComposerBase->editor()->overwriteMode () ? i18n("OVR") : i18n ("INS");
3293 }
3294 
3295 void KMComposeWin::slotCursorPositionChanged()
3296 {
3297  // Change Line/Column info in status bar
3298  int col, line;
3299  QString temp;
3300  line = mComposerBase->editor()->linePosition();
3301  col = mComposerBase->editor()->columnNumber();
3302  temp = i18nc("Shows the linenumber of the cursor position.", " Line: %1 ", line + 1 );
3303  statusBar()->changeItem( temp, 1 );
3304  temp = i18n( " Column: %1 ", col + 1 );
3305  statusBar()->changeItem( temp, 2 );
3306 
3307  // Show link target in status bar
3308  if ( mComposerBase->editor()->textCursor().charFormat().isAnchor() ) {
3309  const QString text = mComposerBase->editor()->currentLinkText();
3310  const QString url = mComposerBase->editor()->currentLinkUrl();
3311  statusBar()->changeItem( text + QLatin1String(" -> ") + url, 0 );
3312  }
3313  else {
3314  statusBar()->changeItem( QString(), 0 );
3315  }
3316 }
3317 
3318 #if 0
3319 namespace {
3320 class KToggleActionResetter {
3321  KToggleAction *mAction;
3322  bool mOn;
3323 
3324  public:
3325  KToggleActionResetter( KToggleAction *action, bool on )
3326  : mAction( action ), mOn( on ) {}
3327  ~KToggleActionResetter() {
3328  if ( mAction ) {
3329  mAction->setChecked( mOn );
3330  }
3331  }
3332  void disable() { mAction = 0; }
3333 };
3334 }
3335 
3336 void KMComposeWin::slotEncryptChiasmusToggled( bool on )
3337 {
3338  if ( !on ) {
3339  return;
3340  }
3341 
3342  KToggleActionResetter resetter( mEncryptChiasmusAction, false );
3343 
3344  const Kleo::CryptoBackend::Protocol *chiasmus =
3345  Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" );
3346 
3347  if ( !chiasmus ) {
3348  const QString msg = Kleo::CryptoBackendFactory::instance()->knowsAboutProtocol( "Chiasmus" ) ?
3349  i18n( "Please configure a Crypto Backend to use for "
3350  "Chiasmus encryption first.\n"
3351  "You can do this in the Crypto Backends tab of "
3352  "the configure dialog's Security page." ) :
3353  i18n( "It looks as though libkleopatra was compiled without "
3354  "Chiasmus support. You might want to recompile "
3355  "libkleopatra with --enable-chiasmus.");
3356  KMessageBox::information( this, msg, i18n("No Chiasmus Backend Configured" ) );
3357  return;
3358  }
3359 
3360  std::auto_ptr<Kleo::SpecialJob> job( chiasmus->specialJob( "x-obtain-keys", QMap<QString,QVariant>() ) );
3361  if ( !job.get() ) {
3362  const QString msg = i18n( "Chiasmus backend does not offer the "
3363  "\"x-obtain-keys\" function. Please report this bug." );
3364  KMessageBox::error( this, msg, i18n( "Chiasmus Backend Error" ) );
3365  return;
3366  }
3367 
3368  if ( job->exec() ) {
3369  job->showErrorDialog( this, i18n( "Chiasmus Backend Error" ) );
3370  return;
3371  }
3372 
3373  const QVariant result = job->property( "result" );
3374  if ( result.type() != QVariant::StringList ) {
3375  const QString msg = i18n( "Unexpected return value from Chiasmus backend: "
3376  "The \"x-obtain-keys\" function did not return a "
3377  "string list. Please report this bug." );
3378  KMessageBox::error( this, msg, i18n( "Chiasmus Backend Error" ) );
3379  return;
3380  }
3381 
3382  const QStringList keys = result.toStringList();
3383  if ( keys.empty() ) {
3384  const QString msg = i18n( "No keys have been found. Please check that a "
3385  "valid key path has been set in the Chiasmus "
3386  "configuration." );
3387  KMessageBox::information( this, msg, i18n( "No Chiasmus Keys Found" ) );
3388  return;
3389  }
3390 
3391  MessageViewer::ChiasmusKeySelector selectorDlg( this, i18n( "Chiasmus Encryption Key Selection" ),
3392  keys, GlobalSettings::chiasmusKey(),
3393  GlobalSettings::chiasmusOptions() );
3394 
3395  if ( selectorDlg.exec() != KDialog::Accepted ) {
3396  return;
3397  }
3398 
3399  GlobalSettings::setChiasmusOptions( selectorDlg.options() );
3400  GlobalSettings::setChiasmusKey( selectorDlg.key() );
3401  assert( !GlobalSettings::chiasmusKey().isEmpty() );
3402  resetter.disable();
3403 }
3404 #endif
3405 
3406 void KMComposeWin::recipientEditorSizeHintChanged()
3407 {
3408  QTimer::singleShot( 1, this, SLOT(setMaximumHeaderSize()) );
3409 }
3410 
3411 void KMComposeWin::setMaximumHeaderSize()
3412 {
3413  mHeadersArea->setMaximumHeight( mHeadersArea->sizeHint().height() );
3414 }
3415 
3416 void KMComposeWin::slotUpdateSignatureAndEncrypionStateIndicators()
3417 {
3418  const bool showIndicatorsAlways = false; // FIXME config option?
3419  mSignatureStateIndicator->setText( mSignAction->isChecked() ?
3420  i18n("Message will be signed") :
3421  i18n("Message will not be signed") );
3422  mEncryptionStateIndicator->setText( mEncryptAction->isChecked() ?
3423  i18n("Message will be encrypted") :
3424  i18n("Message will not be encrypted") );
3425  if ( !showIndicatorsAlways ) {
3426  mSignatureStateIndicator->setVisible( mSignAction->isChecked() );
3427  mEncryptionStateIndicator->setVisible( mEncryptAction->isChecked() );
3428  }
3429 }
3430 
3431 void KMComposeWin::slotLanguageChanged( const QString &language )
3432 {
3433  mDictionaryCombo->setCurrentByDictionary( language );
3434 }
3435 
3436 
3437 void KMComposeWin::slotFccFolderChanged(const Akonadi::Collection& collection)
3438 {
3439  mComposerBase->setFcc( collection );
3440 }
3441 
3442 void KMComposeWin::slotTranslatorWasClosed()
3443 {
3444  mTranslateAction->setChecked(false);
3445 }
3446 
3447 void KMComposeWin::insertSpecialCharacter()
3448 {
3449  if(!mSelectSpecialChar) {
3450  mSelectSpecialChar = new KPIMTextEdit::SelectSpecialChar(this);
3451  mSelectSpecialChar->setCaption(i18n("Insert Special Character"));
3452  mSelectSpecialChar->setOkButtonText(i18n("Insert"));
3453  connect(mSelectSpecialChar,SIGNAL(charSelected(QChar)),this,SLOT(charSelected(QChar)));
3454  }
3455  mSelectSpecialChar->show();
3456 }
3457 
3458 void KMComposeWin::charSelected(const QChar& c)
3459 {
3460  mComposerBase->editor()->insertPlainText(c);
3461 }
3462 
3463 void KMComposeWin::slotSaveAsFile()
3464 {
3465  QPointer<KFileDialog> dlg = new KFileDialog(KUrl(),QString(),this);
3466  dlg->setOperationMode(KFileDialog::Saving);
3467  dlg->setConfirmOverwrite(true);
3468  if(mComposerBase->editor()->textMode() == KMeditor::Rich ) {
3469  dlg->setFilter( QString::fromLatin1("text/html text/plain application/vnd.oasis.opendocument.text") );
3470  } else {
3471  dlg->setFilter( QString::fromLatin1("text/plain") );
3472  }
3473 
3474  if(dlg->exec()) {
3475  QTextDocumentWriter writer;
3476  const QString filename = dlg->selectedUrl().path();
3477  writer.setFileName(dlg->selectedUrl().path());
3478  if (dlg->currentFilter() == QString::fromLatin1("text/plain") || filename.endsWith(QLatin1String(".txt"))) {
3479  writer.setFormat("plaintext");
3480  } else if (dlg->currentFilter() == QString::fromLatin1("text/html")|| filename.endsWith(QLatin1String(".html"))) {
3481  writer.setFormat("HTML");
3482  } else if (dlg->currentFilter() == QString::fromLatin1("application/vnd.oasis.opendocument.text") || filename.endsWith(QLatin1String(".odf"))) {
3483  writer.setFormat("ODF");
3484  } else {
3485  writer.setFormat("plaintext");
3486  }
3487  if (!writer.write(mComposerBase->editor()->document())) {
3488  qDebug()<<" Error during writing";
3489  }
3490  }
3491  delete dlg;
3492 }
3493 
3494 void KMComposeWin::slotCreateAddressBookContact()
3495 {
3496  CreateNewContactJob *job = new CreateNewContactJob( this, this );
3497  job->start();
3498 }
3499 
3500 void KMComposeWin::slotAttachMissingFile()
3501 {
3502  mComposerBase->attachmentController()->showAddAttachmentDialog();
3503 }
3504 
3505 void KMComposeWin::slotCloseAttachMissingFile()
3506 {
3507  if(m_verifyMissingAttachment) {
3508  m_verifyMissingAttachment->start();
3509  }
3510 }
3511 
3512 void KMComposeWin::slotVerifyMissingAttachmentTimeout()
3513 {
3514  if( mComposerBase->hasMissingAttachments( GlobalSettings::self()->attachmentKeywords() )) {
3515  mAttachmentMissing->animatedShow();
3516  } else {
3517  m_verifyMissingAttachment->start();
3518  }
3519 }
3520 
3521 void KMComposeWin::slotExplicitClosedMissingAttachment()
3522 {
3523  if(m_verifyMissingAttachment) {
3524  m_verifyMissingAttachment->stop();
3525  delete m_verifyMissingAttachment;
3526  m_verifyMissingAttachment = 0;
3527  }
3528 }
3529 
3530 void KMComposeWin::addExtraCustomHeaders( const QMap<QByteArray, QString> &headers)
3531 {
3532  mExtraHeaders = headers;
3533 }
3534 
3535 void KMComposeWin::slotUpperCase()
3536 {
3537  QTextCursor textCursor = mComposerBase->editor()->textCursor();
3538  if (textCursor.hasSelection()) {
3539  const QString newText = textCursor.selectedText().toUpper();
3540  textCursor.insertText(newText);
3541  }
3542 }
3543 
3544 void KMComposeWin::slotLowerCase()
3545 {
3546  QTextCursor textCursor = mComposerBase->editor()->textCursor();
3547  if (textCursor.hasSelection()) {
3548  const QString newText = textCursor.selectedText().toLower();
3549  textCursor.insertText(newText);
3550  }
3551 }
3552 
3553 void KMComposeWin::slotExternalEditorStarted()
3554 {
3555  mComposerBase->identityCombo()->setEnabled(false);
3556  mExternalEditorWarning->show();
3557 }
3558 
3559 void KMComposeWin::slotExternalEditorClosed()
3560 {
3561  mComposerBase->identityCombo()->setEnabled(true);
3562  mExternalEditorWarning->hide();
3563 }
3564 
custommimeheader.h
AddressValidationJob
Definition: addressvalidationjob.h:28
globalsettings.h
KMComposeWin::htmlToolBarVisibilityChanged
void htmlToolBarVisibilityChanged(bool visible)
Definition: kmcomposewin.cpp:3041
KMComposeWin::slotSpellcheckDoneClearStatus
void slotSpellcheckDoneClearStatus()
Definition: kmcomposewin.cpp:3074
QSharedPointer< MailCommon::FolderCollection >
kmcomposereditor.h
KMail::AttachmentView
Definition: attachmentview.h:38
KMail::Composer::HDR_ALL
Definition: composer.h:55
KMComposeWin::setTextSelection
void setTextSelection(const QString &selection)
Set the text selection the message is a response to.
Definition: kmcomposewin.cpp:1791
kmmainwidget.h
KMMainWin
Definition: kmmainwin.h:34
ExternalEditorWarning
Definition: externaleditorwarning.h:23
KMComposeWin::disableWordWrap
void disableWordWrap()
Disables word wrap completely.
Definition: kmcomposewin.cpp:2568
KMail::Composer::HDR_REPLY_TO
Definition: composer.h:47
KMComposeWin::slotWordWrapToggled
void slotWordWrapToggled(bool)
Switch wordWrap on/off.
Definition: kmcomposewin.cpp:2559
text
virtual QByteArray text(quint32 serialNumber) const =0
KMComposeWin::create
static Composer * create(const KMime::Message::Ptr &msg, bool lastSignState, bool lastEncryptState, TemplateContext context=NoTemplate, uint identity=0, const QString &textSelection=QString(), const QString &customTemplate=QString())
Definition: kmcomposewin.cpp:177
AddressValidationJob::start
void start()
Definition: addressvalidationjob.cpp:111
KMail::SecondaryWindow::setCaption
virtual void setCaption(const QString &caption)
Reimplement because we have this bug #Bug 163978.
Definition: secondarywindow.cpp:80
KMComposeWin::addAttachmentsAndSend
Q_SCRIPTABLE void addAttachmentsAndSend(const KUrl::List &urls, const QString &comment, int how)
Definition: kmcomposewin.cpp:564
QWidget
KMComposeWin::setCollectionForNewMessage
void setCollectionForNewMessage(const Akonadi::Collection &folder)
Definition: kmcomposewin.cpp:1077
AddressValidationJob::isValid
bool isValid() const
Definition: addressvalidationjob.cpp:118
KMComposeWin::identity
const KPIMIdentities::Identity & identity() const
Definition: kmcomposewin.cpp:1956
KMail::AttachmentView::widget
QWidget * widget()
Definition: attachmentview.cpp:216
attachmentview.h
KMComposeWin
Definition: kmcomposewin.h:106
kmmainwin.h
KMComposeWin::addAttachment
Q_SCRIPTABLE void addAttachment(const KUrl &url, const QString &comment)
Definition: kmcomposewin.cpp:576
KMComposeWin::disableForgottenAttachmentsCheck
void disableForgottenAttachmentsCheck()
Don't check for forgotten attachments for a mail, eg.
Definition: kmcomposewin.cpp:2582
KMail::Composer::Forward
Definition: composer.h:44
nepomukwarning.h
KMail::Composer
Definition: composer.h:37
KMKernel::self
static KMKernel * self()
normal control stuff
Definition: kmkernel.cpp:1451
KMKernel::config
KSharedConfig::Ptr config()
Definition: kmkernel.cpp:1456
KMail::Composer::ReplyToAll
Definition: composer.h:44
KMComposeWin::identityChanged
void identityChanged(const KPIMIdentities::Identity &identity)
End of D-Bus callable stuff.
KPIM::NepomukWarning::missingNepomukWarning
static bool missingNepomukWarning(const char *neverShowAgainKey)
createnewcontactjob.h
KMComposeWin::forceDisableHtml
void forceDisableHtml()
Disables HTML completely.
Definition: kmcomposewin.cpp:2574
KMail::AttachmentController
Definition: attachmentcontroller.h:37
fromMimeData
static MailList fromMimeData(const QMimeData *md)
KMComposeWin::setCurrentReplyTo
void setCurrentReplyTo(const QString &)
Definition: kmcomposewin.cpp:1565
KMComposeWin::setCustomTemplate
void setCustomTemplate(const QString &customTemplate)
Set custom template to be used for the message.
Definition: kmcomposewin.cpp:1797
snippetwidget.h
KMail::Composer::HDR_DICTIONARY
Definition: composer.h:54
KMCommand
Small helper structure which encapsulates the KMMessage created when creating a reply, and.
Definition: kmcommands.h:44
KMComposeWin::smartQuote
QString smartQuote(const QString &msg)
Definition: kmcomposewin.cpp:2131
externaleditorwarning.h
KMCommand::start
void start()
Definition: kmcommands.cpp:234
KMComposeWin::setModified
void setModified(bool modified)
Set whether the message should be treated as modified or not.
Definition: kmcomposewin.cpp:1832
KMComposerEditor
Definition: kmcomposereditor.h:31
KPIM::NepomukWarning
CodecAction::ComposerMode
Used in the composer.
Definition: codecaction.h:38
KMail::Composer::HDR_FROM
Definition: composer.h:46
KMail::Composer::HDR_SUBJECT
Definition: composer.h:48
KMail::Composer::HDR_FCC
Definition: composer.h:53
QMimeData
util.h
CodecAction
Definition: codecaction.h:31
kmkernel
#define kmkernel
Definition: kmkernel.h:22
KMComposeWin::slotFetchJob
void slotFetchJob(KJob *)
Definition: kmcomposewin.cpp:2257
KMComposeWin::setFcc
void setFcc(const QString &idString)
Use the given folder as sent-mail folder if the given folder exists.
Definition: kmcomposewin.cpp:1803
KMForwardAttachedCommand
Definition: kmcommands.h:348
KMComposeWin::slotTextModeChanged
void slotTextModeChanged(KRichTextEdit::Mode)
Definition: kmcomposewin.cpp:3032
KMail::Composer::Reply
Definition: composer.h:44
attachmentcontroller.h
selectCharset
static QString selectCharset(KSelectAction *root, const QString &encoding)
Definition: kmcomposewin.cpp:2001
CreateNewContactJob
The CreateNewContactJob class The job will check if there is address book folder to store new contact...
Definition: createnewcontactjob.h:32
KMComposeWin::send
Q_SCRIPTABLE void send(int how)
Start of D-Bus callable stuff.
Definition: kmcomposewin.cpp:548
KPIM::NepomukWarning::setMissingFeatures
void setMissingFeatures(const QStringList &features)
KMComposeWin::setMessage
void setMessage(const KMime::Message::Ptr &newMsg, bool lastSignState=false, bool lastEncryptState=false, bool mayAutoSign=true, bool allowDecryption=false, bool isModified=false)
Set the message the composer shall work with.
Definition: kmcomposewin.cpp:1573
KMComposeWin::setFocusToSubject
void setFocusToSubject()
Sets the focus to the subject line edit.
Definition: kmcomposewin.cpp:3246
GlobalSettings::self
static GlobalSettings * self()
Definition: globalsettings.cpp:30
kmkernel.h
KLineEdit
KMComposeWin::setCurrentTransport
void setCurrentTransport(int transportId)
Definition: kmcomposewin.cpp:1560
KMComposeWin::addAttach
void addAttach(KMime::Content *msgPart)
Add an attachment to the list.
Definition: kmcomposewin.cpp:1970
KMail::Composer::HDR_IDENTITY
Definition: composer.h:51
KMPrintCommand::setPrintPreview
void setPrintPreview(bool preview)
Definition: kmcommands.cpp:1101
KMComposeWin::setFocusToEditor
void setFocusToEditor()
Sets the focus to the edit-widget.
Definition: kmcomposewin.cpp:3239
codecaction.h
KMComposeWin::addExtraCustomHeaders
void addExtraCustomHeaders(const QMap< QByteArray, QString > &header)
Definition: kmcomposewin.cpp:3530
KMComposeWin::slotToggleMarkup
void slotToggleMarkup()
Definition: kmcomposewin.cpp:3026
kmcomposewin.h
KMComposeWin::slotSendNow
void slotSendNow()
Definition: kmcomposewin.cpp:2903
QLabel
attachmentmissingwarning.h
SnippetWidget
Definition: snippetwidget.h:31
addressvalidationjob.h
CustomMimeHeader
Definition: custommimeheader.h:9
KMPrintCommand
Definition: kmcommands.h:377
KMKernel::identityManager
KPIMIdentities::IdentityManager * identityManager()
return the pointer to the identity manager
Definition: kmkernel.cpp:1418
AttachmentMissingWarning
Definition: attachmentmissingwarning.h:23
KMComposeWin::autoSaveMessage
void autoSaveMessage(bool force=false)
Definition: kmcomposewin.cpp:1917
KMail::Composer::New
Definition: composer.h:44
CreateNewContactJob::start
void start()
start the job
Definition: createnewcontactjob.cpp:49
kmcommands.h
KPIM::RecentAddresses
KMComposeWin::ignoreStickyFields
void ignoreStickyFields()
Ignore the "sticky" setting of the transport combo box and prefer the X-KMail-Transport header field ...
Definition: kmcomposewin.cpp:2587
KJob
KMKernel::slotSyncConfig
void slotSyncConfig()
Sync the config immediatley.
Definition: kmkernel.cpp:1344
QMap< QByteArray, QString >
KMail::AttachmentView::hideIfEmpty
void hideIfEmpty()
Definition: attachmentview.cpp:171
KMComposeWin::insertFromMimeData
bool insertFromMimeData(const QMimeData *source, bool forceAttachment=false)
Definition: kmcomposewin.cpp:2137
KTextEdit
QList
KMComposeWin::dbusObjectPath
QString dbusObjectPath() const
Definition: kmcomposewin.cpp:533
CodecAction::mimeCharsets
QList< QByteArray > mimeCharsets() const
The name of the charset, if a specific encoding was selected, or a list containing the names of the p...
Definition: codecaction.cpp:76
recentaddresses.h
KMail::Composer::HDR_TRANSPORT
Definition: composer.h:52
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:58:52 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kmail

Skip menu "kmail"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal