2 This file is part of KMail, the KDE mail client.
3 Copyright (c) 2002 Don Sanders <sanders@kde.org>
5 KMail is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License, version 2, as
7 published by the Free Software Foundation.
9 KMail is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 // A toplevel KMainWindow derived class for displaying
20 // single messages or single message parts.
22 // Could be extended to include support for normal main window
23 // widgets like a toolbar.
25 #include "kmreadermainwin.h"
26 #include "kmreaderwin.h"
29 #include <kactionmenu.h>
30 #include <kedittoolbar.h>
32 #include <kstandardshortcut.h>
33 #include <kwindowsystem.h>
35 #include <kfontaction.h>
36 #include <kiconloader.h>
37 #include <kstandardaction.h>
38 #include <ktoggleaction.h>
41 #include <KFontAction>
42 #include <KFontSizeAction>
43 #include <kstatusbar.h>
45 #include "kmcommands.h"
48 #include "kmmainwidget.h"
49 #include "messageviewer/csshelper.h"
50 #include "customtemplatesmenu.h"
51 #include "messageactions.h"
53 #include "foldercollection.h"
55 #include <akonadi/contact/contactsearchjob.h>
56 #include <kpimutils/email.h>
57 #include <kmime/kmime_message.h>
59 #include <messageviewer/viewer.h>
60 #include <akonadi/item.h>
62 #include "messagecore/messagehelpers.h"
64 KMReaderMainWin::KMReaderMainWin( bool htmlOverride
, bool htmlLoadExtOverride
,
66 : KMail::SecondaryWindow( name
? name
: "readerwindow#" )
68 mReaderWin
= new KMReaderWin( this, this, actionCollection() );
69 //mReaderWin->setShowCompleteMessage( true );
70 mReaderWin
->setHtmlOverride( htmlOverride
);
71 mReaderWin
->setHtmlLoadExtOverride( htmlLoadExtOverride
);
72 mReaderWin
->setDecryptMessageOverwrite( true );
73 initKMReaderMainWin();
77 //-----------------------------------------------------------------------------
78 KMReaderMainWin::KMReaderMainWin( char *name
)
79 : KMail::SecondaryWindow( name
? name
: "readerwindow#" )
81 mReaderWin
= new KMReaderWin( this, this, actionCollection() );
82 initKMReaderMainWin();
86 //-----------------------------------------------------------------------------
87 KMReaderMainWin::KMReaderMainWin(KMime::Content
* aMsgPart
, bool aHTML
, const QString
& encoding
, char *name
)
88 : KMail::SecondaryWindow( name
? name
: "readerwindow#" )
90 mReaderWin
= new KMReaderWin( this, this, actionCollection() );
91 mReaderWin
->setOverrideEncoding( encoding
);
92 mReaderWin
->setHtmlOverride( aHTML
);
93 mReaderWin
->setMsgPart( aMsgPart
);
94 initKMReaderMainWin();
97 //-----------------------------------------------------------------------------
98 void KMReaderMainWin::initKMReaderMainWin()
100 setCentralWidget( mReaderWin
);
102 setupGUI( Keys
| StatusBar
| Create
, "kmreadermainwin.rc" );
103 mMsgActions
->setupForwardingActionsList( this );
104 applyMainWindowSettings( KMKernel::config()->group( "Separate Reader Window" ) );
105 if( ! mReaderWin
->message().isValid() ) {
107 toolBar( "mainToolBar" )->hide();
110 connect( kmkernel
, SIGNAL( configChanged() ),
111 this, SLOT( slotConfigChanged() ) );
112 connect( mReaderWin
, SIGNAL( showStatusBarMessage( const QString
& ) ),
113 statusBar(), SLOT( showMessage( const QString
& ) ) );
116 //-----------------------------------------------------------------------------
117 KMReaderMainWin::~KMReaderMainWin()
119 saveMainWindowSettings( KMKernel::config()->group( "Separate Reader Window" ) );
122 //-----------------------------------------------------------------------------
123 void KMReaderMainWin::setUseFixedFont( bool useFixedFont
)
125 mReaderWin
->setUseFixedFont( useFixedFont
);
128 void KMReaderMainWin::showMessage( const QString
& encoding
, const Akonadi::Item
&msg
)
130 mReaderWin
->setOverrideEncoding( encoding
);
131 mReaderWin
->setMessage( msg
, MessageViewer::Viewer::Force
);
132 KMime::Message::Ptr message
= MessageCore::Util::message( msg
);
134 setCaption( message
->subject()->asUnicodeString() );
135 mReaderWin
->slotTouchMessage();
137 mMsgActions
->setCurrentMessage( msg
);
139 const Akonadi::Collection parent
= msg
.parentCollection();
140 const bool canChange
= parent
.isValid() ? !( parent
.rights() & Akonadi::Collection::ReadOnly
) : false;
141 mTrashAction
->setEnabled( canChange
);
144 toolBar( "mainToolBar" )->show();
147 void KMReaderMainWin::showMessage( const QString
& encoding
, KMime::Message::Ptr message
)
149 mReaderWin
->setOverrideEncoding( encoding
);
150 mReaderWin
->setMessage( message
);
152 setCaption( message
->subject()->asUnicodeString() );
153 mReaderWin
->slotTouchMessage();
155 mTrashAction
->setEnabled( false );
158 toolBar( "mainToolBar" )->show();
162 void KMReaderMainWin::slotReplyOrForwardFinished()
164 if ( GlobalSettings::self()->closeAfterReplyOrForward() ) {
169 //-----------------------------------------------------------------------------
170 void KMReaderMainWin::slotTrashMsg()
172 if ( !mMsg
.isValid() )
174 KMTrashMsgCommand
*command
= new KMTrashMsgCommand( mMsg
.parentCollection(), mMsg
, -1 );
179 //-----------------------------------------------------------------------------
180 void KMReaderMainWin::slotForwardInlineMsg()
182 KMCommand
*command
= 0;
183 if ( mReaderWin
->message().isValid() && mReaderWin
->message().parentCollection().isValid() ) {
184 QSharedPointer
<FolderCollection
> fd
= FolderCollection::forCollection( mReaderWin
->message().parentCollection() );
186 command
= new KMForwardCommand( this, mReaderWin
->message(),
189 command
= new KMForwardCommand( this, mReaderWin
->message() );
191 command
= new KMForwardCommand( this, mReaderWin
->message() );
193 connect( command
, SIGNAL( completed( KMCommand
* ) ),
194 this, SLOT( slotReplyOrForwardFinished() ) );
198 //-----------------------------------------------------------------------------
199 void KMReaderMainWin::slotForwardAttachedMsg()
201 KMCommand
*command
= 0;
202 if ( mReaderWin
->message().isValid() && mReaderWin
->message().parentCollection().isValid() ) {
203 QSharedPointer
<FolderCollection
> fd
= FolderCollection::forCollection( mReaderWin
->message().parentCollection() );
205 command
= new KMForwardAttachedCommand( this, mReaderWin
->message(),
208 command
= new KMForwardAttachedCommand( this, mReaderWin
->message() );
210 command
= new KMForwardAttachedCommand( this, mReaderWin
->message() );
212 connect( command
, SIGNAL( completed( KMCommand
* ) ),
213 this, SLOT( slotReplyOrForwardFinished() ) );
217 //-----------------------------------------------------------------------------
218 void KMReaderMainWin::slotRedirectMsg()
220 KMCommand
*command
= new KMRedirectCommand( this, mReaderWin
->message() );
221 connect( command
, SIGNAL( completed( KMCommand
* ) ),
222 this, SLOT( slotReplyOrForwardFinished() ) );
226 //-----------------------------------------------------------------------------
227 void KMReaderMainWin::slotCustomReplyToMsg( const QString
&tmpl
)
229 KMCommand
*command
= new KMCustomReplyToCommand( this,
230 mReaderWin
->message(),
231 mReaderWin
->copyText(),
233 connect( command
, SIGNAL( completed( KMCommand
* ) ),
234 this, SLOT( slotReplyOrForwardFinished() ) );
238 //-----------------------------------------------------------------------------
239 void KMReaderMainWin::slotCustomReplyAllToMsg( const QString
&tmpl
)
241 KMCommand
*command
= new KMCustomReplyAllToCommand( this,
242 mReaderWin
->message(),
243 mReaderWin
->copyText(),
248 //-----------------------------------------------------------------------------
249 void KMReaderMainWin::slotCustomForwardMsg( const QString
&tmpl
)
251 KMCommand
*command
= new KMCustomForwardCommand( this,
252 mReaderWin
->message(),
257 //-----------------------------------------------------------------------------
258 void KMReaderMainWin::slotConfigChanged()
261 mMsgActions
->setupForwardActions();
262 mMsgActions
->setupForwardingActionsList( this );
265 void KMReaderMainWin::setupAccel()
267 if ( kmkernel
->xmlGuiInstance().isValid() )
268 setComponentData( kmkernel
->xmlGuiInstance() );
270 mMsgActions
= new KMail::MessageActions( actionCollection(), this );
271 mMsgActions
->setMessageView( mReaderWin
);
272 connect( mMsgActions
, SIGNAL( replyActionFinished() ),
273 this, SLOT( slotReplyOrForwardFinished() ) );
276 mSaveAsAction
= KStandardAction::saveAs( mReaderWin
->viewer(), SLOT( slotSaveMessage() ),
277 actionCollection() );
278 mSaveAsAction
->setShortcut( KStandardShortcut::shortcut( KStandardShortcut::Save
) );
280 mSaveAtmAction
= new KAction(KIcon("mail-attachment"), i18n("Save A&ttachments..."), actionCollection() );
281 connect( mSaveAtmAction
, SIGNAL(triggered(bool)), mReaderWin
->viewer(), SLOT(slotAttachmentSaveAs()) );
283 mTrashAction
= new KAction( KIcon( "user-trash" ), i18n("&Move to Trash"), this );
284 mTrashAction
->setIconText( i18nc( "@action:intoolbar Move to Trash", "Trash" ) );
285 mTrashAction
->setHelpText( i18n( "Move message to trashcan" ) );
286 mTrashAction
->setShortcut( QKeySequence( Qt::Key_Delete
) );
287 actionCollection()->addAction( "move_to_trash", mTrashAction
);
288 connect( mTrashAction
, SIGNAL(triggered()), this, SLOT(slotTrashMsg()) );
290 KAction
*closeAction
= KStandardAction::close( this, SLOT( close() ), actionCollection() );
291 KShortcut closeShortcut
= KShortcut(closeAction
->shortcuts());
292 closeShortcut
.setAlternate( QKeySequence(Qt::Key_Escape
));
293 closeAction
->setShortcuts(closeShortcut
);
296 mViewSourceAction
= new KAction(i18n("&View Source"), this);
297 actionCollection()->addAction("view_source", mViewSourceAction
);
298 connect(mViewSourceAction
, SIGNAL(triggered(bool) ), mReaderWin
->viewer(), SLOT(slotShowMessageSource()));
299 mViewSourceAction
->setShortcut(QKeySequence(Qt::Key_V
));
303 fontAction
= new KFontAction( i18n("Select Font"), this );
304 actionCollection()->addAction( "text_font", fontAction
);
305 fontAction
->setFont( mReaderWin
->cssHelper()->bodyFont().family() );
306 connect( fontAction
, SIGNAL( triggered( const QString
& ) ),
307 SLOT( slotFontAction( const QString
& ) ) );
308 fontSizeAction
= new KFontSizeAction( i18n( "Select Size" ), this );
309 fontSizeAction
->setFontSize( mReaderWin
->cssHelper()->bodyFont().pointSize() );
310 actionCollection()->addAction( "text_size", fontSizeAction
);
311 connect( fontSizeAction
, SIGNAL( fontSizeChanged( int ) ),
312 SLOT( slotSizeAction( int ) ) );
314 updateCustomTemplateMenus();
316 connect( mReaderWin
->viewer(), SIGNAL( popupMenu(const Akonadi::Item
&,const KUrl
&,const QPoint
&) ),
317 this, SLOT( slotMessagePopup(const Akonadi::Item
&,const KUrl
&,const QPoint
&) ) );
319 setStandardToolBarMenuEnabled(true);
320 KStandardAction::configureToolbars(this, SLOT(slotEditToolbars()), actionCollection());
324 //-----------------------------------------------------------------------------
325 void KMReaderMainWin::updateCustomTemplateMenus()
327 if ( !mCustomTemplateMenus
) {
328 mCustomTemplateMenus
.reset( new CustomTemplatesMenu( this, actionCollection() ) );
329 connect( mCustomTemplateMenus
.get(), SIGNAL(replyTemplateSelected( const QString
& )),
330 this, SLOT(slotCustomReplyToMsg( const QString
& )) );
331 connect( mCustomTemplateMenus
.get(), SIGNAL(replyAllTemplateSelected( const QString
& )),
332 this, SLOT(slotCustomReplyAllToMsg( const QString
& )) );
333 connect( mCustomTemplateMenus
.get(), SIGNAL(forwardTemplateSelected( const QString
& )),
334 this, SLOT(slotCustomForwardMsg( const QString
& )) );
335 connect( KMKernel::self(), SIGNAL(customTemplatesChanged()), mCustomTemplateMenus
.get(), SLOT(update()) );
338 mMsgActions
->forwardMenu()->addSeparator();
339 mMsgActions
->forwardMenu()->addAction( mCustomTemplateMenus
->forwardActionMenu() );
341 mMsgActions
->replyMenu()->addSeparator();
342 mMsgActions
->replyMenu()->addAction( mCustomTemplateMenus
->replyActionMenu() );
343 mMsgActions
->replyMenu()->addAction( mCustomTemplateMenus
->replyAllActionMenu() );
347 //-----------------------------------------------------------------------------
348 KAction
*KMReaderMainWin::copyActionMenu()
350 KMMainWidget
* mainwin
= kmkernel
->getKMMainWidget();
352 return mainwin
->akonadiStandardAction( Akonadi::StandardActionManager::CopyItemToMenu
);
356 void KMReaderMainWin::slotMessagePopup(const Akonadi::Item
&aMsg
,const KUrl
&aUrl
,const QPoint
& aPoint
)
361 const QString email
= KPIMUtils::firstEmailAddress( aUrl
.path() );
362 Akonadi::ContactSearchJob
*job
= new Akonadi::ContactSearchJob( this );
364 job
->setQuery( Akonadi::ContactSearchJob::Email
, email
, Akonadi::ContactSearchJob::ExactMatch
);
365 job
->setProperty( "point", aPoint
);
366 connect( job
, SIGNAL( result( KJob
* ) ), SLOT( slotDelayedMessagePopup( KJob
* ) ) );
369 void KMReaderMainWin::slotDelayedMessagePopup( KJob
*job
)
371 const Akonadi::ContactSearchJob
*searchJob
= qobject_cast
<Akonadi::ContactSearchJob
*>( job
);
372 const bool contactAlreadyExists
= !searchJob
->contacts().isEmpty();
374 const QPoint aPoint
= job
->property( "point" ).toPoint();
376 KMenu
*menu
= new KMenu
;
378 bool urlMenuAdded
= false;
379 bool copyAdded
= false;
380 if ( !mUrl
.isEmpty() ) {
381 if ( mUrl
.protocol() == "mailto" ) {
382 // popup on a mailto URL
383 menu
->addAction( mReaderWin
->mailToComposeAction() );
384 if ( mMsg
.isValid() ) {
385 menu
->addAction( mReaderWin
->mailToReplyAction() );
386 menu
->addAction( mReaderWin
->mailToForwardAction() );
387 menu
->addSeparator();
390 if ( contactAlreadyExists
) {
391 menu
->addAction( mReaderWin
->openAddrBookAction() );
393 menu
->addAction( mReaderWin
->addAddrBookAction() );
396 menu
->addAction( mReaderWin
->copyURLAction() );
399 // popup on a not-mailto URL
400 menu
->addAction( mReaderWin
->urlOpenAction() );
401 menu
->addAction( mReaderWin
->addBookmarksAction() );
402 menu
->addAction( mReaderWin
->urlSaveAsAction() );
403 menu
->addAction( mReaderWin
->copyURLAction() );
407 if ( !mReaderWin
->copyText().isEmpty() ) {
408 if ( urlMenuAdded
) {
409 menu
->addSeparator();
411 menu
->addAction( mMsgActions
->replyMenu() );
412 menu
->addSeparator();
414 menu
->addAction( mReaderWin
->copyAction() );
415 menu
->addAction( mReaderWin
->selectAllAction() );
416 } else if ( !urlMenuAdded
) {
417 // popup somewhere else (i.e., not a URL) on the message
418 if (!mMsg
.isValid()) {
423 if ( mMsg
.parentCollection().isValid() ) {
424 Akonadi::Collection col
= mMsg
.parentCollection();
425 if ( ! ( KMKernel::self()->folderIsSentMailFolder( col
) ||
426 KMKernel::self()->folderIsDrafts( col
) ||
427 KMKernel::self()->folderIsTemplates( col
) ) ) {
428 // add the reply and forward actions only if we are not in a sent-mail,
429 // templates or drafts folder
431 // FIXME: needs custom templates added to menu
432 // (see KMMainWidget::updateCustomTemplateMenus)
433 menu
->addAction( mMsgActions
->replyMenu() );
434 menu
->addAction( mMsgActions
->forwardMenu() );
435 menu
->addSeparator();
438 menu
->addAction( copyActionMenu() );
440 menu
->addSeparator();
441 menu
->addAction( mViewSourceAction
);
442 menu
->addAction( mReaderWin
->toggleFixFontAction() );
443 menu
->addAction( mReaderWin
->toggleMimePartTreeAction() );
444 menu
->addSeparator();
445 menu
->addAction( mMsgActions
->printAction() );
446 menu
->addAction( mSaveAsAction
);
447 menu
->addAction( mSaveAtmAction
);
448 menu
->addSeparator();
449 menu
->addAction( mMsgActions
->createTodoAction() );
451 menu
->exec( aPoint
, 0 );
455 void KMReaderMainWin::slotFontAction( const QString
& font
)
457 QFont
f( mReaderWin
->cssHelper()->bodyFont() );
459 mReaderWin
->cssHelper()->setBodyFont( f
);
460 mReaderWin
->cssHelper()->setPrintFont( f
);
461 mReaderWin
->update();
464 void KMReaderMainWin::slotSizeAction( int size
)
466 QFont
f( mReaderWin
->cssHelper()->bodyFont() );
467 f
.setPointSize( size
);
468 mReaderWin
->cssHelper()->setBodyFont( f
);
469 mReaderWin
->cssHelper()->setPrintFont( f
);
470 mReaderWin
->update();
473 void KMReaderMainWin::slotCreateTodo()
475 if ( !mReaderWin
->message().isValid() )
477 KMCommand
*command
= new CreateTodoCommand( this, mReaderWin
->message() );
481 void KMReaderMainWin::slotEditToolbars()
483 saveMainWindowSettings( KConfigGroup(KMKernel::config(), "ReaderWindow") );
484 KEditToolBar
dlg( guiFactory(), this );
485 connect( &dlg
, SIGNAL(newToolbarConfig()), SLOT(slotUpdateToolbars()) );
489 void KMReaderMainWin::slotUpdateToolbars()
491 createGUI("kmreadermainwin.rc");
492 applyMainWindowSettings( KConfigGroup(KMKernel::config(), "ReaderWindow") );
495 #include "kmreadermainwin.moc"