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

kmail

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

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