24 #include "kernel/mailkernel.h"
28 #include "customtemplatesmenu.h"
30 #include "messagecore/widgets/annotationdialog.h"
31 #include "messagecore/settings/globalsettings.h"
32 #include "messagecore/misc/mailinglist.h"
33 #include "messagecore/helpers/messagehelpers.h"
34 #include "messageviewer/viewer/csshelper.h"
35 #include "messageviewer/settings/globalsettings.h"
37 #include "pimcommon/baloodebug/baloodebugdialog.h"
42 #include <akonadi/itemfetchjob.h>
43 #include <akonadi/kmime/messageparts.h>
44 #include <Akonadi/ChangeRecorder>
46 #include <KActionMenu>
47 #include <KActionCollection>
49 #include <KLocalizedString>
50 #include <KXMLGUIClient>
51 #include <KStandardDirs>
54 #include <KUriFilterData>
55 #include <KToolInvocation>
57 #include <KStringHandler>
58 #include <KPrintPreview>
62 #include <akonadi/collection.h>
63 #include <akonadi/entityannotationsattribute.h>
64 #include <util/mailutil.h>
66 using namespace KMail;
73 mPrintPreviewAction( 0 ),
74 mCustomTemplatesMenu( 0 ),
75 mAddFollowupReminderAction( 0 ),
79 ac->addAction(
QLatin1String(
"message_reply_menu"), mReplyActionMenu );
80 connect( mReplyActionMenu, SIGNAL(triggered(
bool)),
81 this, SLOT(slotReplyToMsg()) );
83 mReplyAction =
new KAction( KIcon(
QLatin1String(
"mail-reply-sender")), i18n(
"&Reply..."),
this );
85 mReplyAction->setShortcut(Qt::Key_R);
86 connect( mReplyAction, SIGNAL(triggered(
bool)),
87 this, SLOT(slotReplyToMsg()) );
88 mReplyActionMenu->addAction( mReplyAction );
90 mReplyAuthorAction =
new KAction( KIcon(
QLatin1String(
"mail-reply-sender")), i18n(
"Reply to A&uthor..."),
this );
91 ac->addAction(
QLatin1String(
"reply_author"), mReplyAuthorAction );
92 mReplyAuthorAction->setShortcut(Qt::SHIFT+Qt::Key_A);
93 connect( mReplyAuthorAction, SIGNAL(triggered(
bool)),
94 this, SLOT(slotReplyAuthorToMsg()) );
95 mReplyActionMenu->addAction( mReplyAuthorAction );
97 mReplyAllAction =
new KAction( KIcon(
QLatin1String(
"mail-reply-all")), i18n(
"Reply to &All..."),
this );
99 mReplyAllAction->setShortcut( Qt::Key_A );
100 connect( mReplyAllAction, SIGNAL(triggered(
bool)),
101 this, SLOT(slotReplyAllToMsg()) );
102 mReplyActionMenu->addAction( mReplyAllAction );
104 mReplyListAction =
new KAction( KIcon(
QLatin1String(
"mail-reply-list")), i18n(
"Reply to Mailing-&List..."),
this );
105 ac->addAction(
QLatin1String(
"reply_list"), mReplyListAction );
106 mReplyListAction->setShortcut( Qt::Key_L );
107 connect( mReplyListAction, SIGNAL(triggered(
bool)),
108 this, SLOT(slotReplyListToMsg()) );
109 mReplyActionMenu->addAction( mReplyListAction );
111 mNoQuoteReplyAction =
new KAction( i18n(
"Reply Without &Quote..."),
this );
112 ac->addAction(
QLatin1String(
"noquotereply"), mNoQuoteReplyAction );
113 mNoQuoteReplyAction->setShortcut( Qt::SHIFT+Qt::Key_R );
114 connect( mNoQuoteReplyAction, SIGNAL(triggered(
bool)),
115 this, SLOT(slotNoQuoteReplyToMsg()) );
118 mListFilterAction =
new KAction(i18n(
"Filter on Mailing-&List..."),
this);
119 ac->addAction(
QLatin1String(
"mlist_filter"), mListFilterAction );
120 connect(mListFilterAction, SIGNAL(triggered(
bool)), SLOT(slotMailingListFilter()));
122 mStatusMenu =
new KActionMenu ( i18n(
"Mar&k Message" ),
this );
128 KAction * action = mainwin->
akonadiStandardAction( Akonadi::StandardMailActionManager::MarkMailAsRead );
129 mStatusMenu->addAction( action );
132 mStatusMenu->addAction( action );
134 mStatusMenu->addSeparator();
136 mStatusMenu->addAction( action );
139 mStatusMenu->addAction( action );
143 mEditAction =
new KAction( KIcon(
QLatin1String(
"accessories-text-editor")), i18n(
"&Edit Message"),
this );
145 connect( mEditAction, SIGNAL(triggered(
bool)),
147 mEditAction->setShortcut( Qt::Key_T );
149 mAnnotateAction =
new KAction( KIcon(
QLatin1String(
"view-pim-notes") ), i18n(
"Add Note..."),
this );
151 connect( mAnnotateAction, SIGNAL(triggered(
bool)),
154 mPrintAction = KStandardAction::print(
this, SLOT(slotPrintMsg()), ac );
155 if(KPrintPreview::isAvailable())
156 mPrintPreviewAction = KStandardAction::printPreview(
this, SLOT(slotPrintPreviewMsg()), ac );
159 ac->addAction(
QLatin1String(
"message_forward"), mForwardActionMenu );
161 mForwardAttachedAction =
new KAction( KIcon(
QLatin1String(
"mail-forward")),
162 i18nc(
"@action:inmenu Message->Forward->",
163 "As &Attachment..." ),
165 connect( mForwardAttachedAction, SIGNAL(triggered(
bool)),
166 parent, SLOT(slotForwardAttachedMsg()) );
167 ac->addAction(
QLatin1String(
"message_forward_as_attachment"), mForwardAttachedAction );
169 mForwardInlineAction =
new KAction( KIcon(
QLatin1String(
"mail-forward") ),
170 i18nc(
"@action:inmenu Message->Forward->",
173 connect( mForwardInlineAction, SIGNAL(triggered(
bool)),
174 parent, SLOT(slotForwardInlineMsg()) );
175 ac->addAction(
QLatin1String(
"message_forward_inline"), mForwardInlineAction );
179 mRedirectAction =
new KAction(i18nc(
"Message->Forward->",
"&Redirect..."),
this );
180 ac->addAction(
QLatin1String(
"message_forward_redirect"), mRedirectAction );
181 connect( mRedirectAction, SIGNAL(triggered(
bool)),
182 parent, SLOT(slotRedirectMsg()) );
183 mRedirectAction->setShortcut(
QKeySequence( Qt::Key_E ) );
184 mForwardActionMenu->addAction( mRedirectAction );
188 mMailingListActionMenu =
new KActionMenu( i18nc(
"Message->",
"Mailing-&List" ),
this );
189 connect( mMailingListActionMenu->menu(), SIGNAL(triggered(
QAction*)),
190 this, SLOT(slotRunUrl(
QAction*)) );
191 ac->addAction(
QLatin1String(
"mailing_list"), mMailingListActionMenu );
192 mMailingListActionMenu->setEnabled(
false);
195 connect(
kmkernel->folderCollectionMonitor(), SIGNAL(itemRemoved(Akonadi::Item)), SLOT(slotItemRemoved(Akonadi::Item)));
197 mCustomTemplatesMenu =
new TemplateParser::CustomTemplatesMenu( parent, ac );
199 connect( mCustomTemplatesMenu, SIGNAL(replyTemplateSelected(
QString)),
200 parent, SLOT(slotCustomReplyToMsg(
QString)) );
201 connect( mCustomTemplatesMenu, SIGNAL(replyAllTemplateSelected(
QString)),
202 parent, SLOT(slotCustomReplyAllToMsg(
QString)) );
203 connect( mCustomTemplatesMenu, SIGNAL(forwardTemplateSelected(
QString)),
204 parent, SLOT(slotCustomForwardMsg(
QString)) );
208 forwardMenu()->addAction( mCustomTemplatesMenu->forwardActionMenu() );
210 replyMenu()->addAction( mCustomTemplatesMenu->replyActionMenu() );
211 replyMenu()->addAction( mCustomTemplatesMenu->replyAllActionMenu() );
215 connect( mDebugBalooAction, SIGNAL(triggered(
bool)),
this, SLOT(slotDebugBaloo()) );
217 mAddFollowupReminderAction =
new KAction(i18n(
"Add Followup Reminder..."),
this );
218 ac->addAction(
QLatin1String(
"message_followup_reminder"), mAddFollowupReminderAction );
219 connect( mAddFollowupReminderAction, SIGNAL(triggered(
bool)),
this, SLOT(slotAddFollowupReminder()) );
226 delete mCustomTemplatesMenu;
231 return mCustomTemplatesMenu;
238 if (!items.isEmpty()) {
240 mVisibleItems = items;
242 mVisibleItems.clear();
246 if ( !msg.isValid() ) {
247 mVisibleItems.clear();
248 clearMailingListActions();
254 void MessageActions::slotItemRemoved(
const Akonadi::Item& item)
256 if ( item == mCurrentItem ) {
257 mCurrentItem = Akonadi::Item();
262 void MessageActions::slotItemModified(
const Akonadi::Item & item,
const QSet< QByteArray > & partIdentifiers )
264 Q_UNUSED( partIdentifiers );
265 if ( item == mCurrentItem ) {
267 const int numberOfVisibleItems = mVisibleItems.count();
268 for (
int i = 0; i < numberOfVisibleItems; ++i ) {
269 Akonadi::Item it = mVisibleItems.at(i);
271 mVisibleItems[i] = item;
278 void MessageActions::updateActions()
280 const bool hasPayload = mCurrentItem.hasPayload<KMime::Message::Ptr>();
281 bool itemValid = mCurrentItem.isValid();
282 Akonadi::Collection
parent;
284 parent = mCurrentItem.parentCollection();
285 if ( parent.isValid() ) {
286 if ( CommonKernel->folderIsTemplates(parent) )
290 const bool multiVisible = mVisibleItems.count() > 0 || mCurrentItem.isValid();
291 const bool uniqItem = ( itemValid||hasPayload ) && ( mVisibleItems.count()<=1 );
292 mReplyActionMenu->setEnabled( hasPayload );
293 mReplyAction->setEnabled( hasPayload );
294 mNoQuoteReplyAction->setEnabled( hasPayload );
295 mReplyAuthorAction->setEnabled( hasPayload );
296 mReplyAllAction->setEnabled( hasPayload );
297 mReplyListAction->setEnabled( hasPayload );
298 mNoQuoteReplyAction->setEnabled( hasPayload );
300 mAnnotateAction->setEnabled( uniqItem );
301 if ( !mCurrentItem.hasAttribute<Akonadi::EntityAnnotationsAttribute>() )
302 mAnnotateAction->setText( i18n(
"Add Note..." ) );
304 mAnnotateAction->setText( i18n(
"Edit Note...") );
306 mStatusMenu->setEnabled( multiVisible );
308 if ( mCurrentItem.hasPayload<KMime::Message::Ptr>() ) {
309 if ( mCurrentItem.loadedPayloadParts().contains(
"RFC822") ) {
310 updateMailingListActions( mCurrentItem );
312 Akonadi::ItemFetchJob *job =
new Akonadi::ItemFetchJob( mCurrentItem );
313 job->fetchScope().fetchAllAttributes();
314 job->fetchScope().fetchFullPayload(
true );
315 job->fetchScope().fetchPayloadPart( Akonadi::MessagePart::Header );
316 job->fetchScope().fetchAttribute<Akonadi::EntityAnnotationsAttribute>();
317 connect( job, SIGNAL(result(
KJob*)), SLOT(slotUpdateActionsFetchDone(
KJob*)) );
320 mEditAction->setEnabled( uniqItem );
323 void MessageActions::slotUpdateActionsFetchDone(
KJob* job)
328 Akonadi::ItemFetchJob *fetchJob =
static_cast<Akonadi::ItemFetchJob*
>( job );
329 if ( fetchJob->items().isEmpty() )
331 Akonadi::Item messageItem = fetchJob->items().first();
332 if ( messageItem == mCurrentItem ) {
333 mCurrentItem = messageItem;
334 updateMailingListActions( messageItem );
338 void MessageActions::clearMailingListActions()
340 mMailingListActionMenu->setEnabled(
false );
341 mListFilterAction->setEnabled(
false );
342 mListFilterAction->setText( i18n(
"Filter on Mailing-List...") );
345 void MessageActions::updateMailingListActions(
const Akonadi::Item& messageItem )
347 KMime::Message::Ptr message = messageItem.payload<KMime::Message::Ptr>();
348 const MessageCore::MailingList mailList = MessageCore::MailingList::detect( message );
350 if ( mailList.features() == MessageCore::MailingList::None ) {
351 clearMailingListActions();
356 if ( mailList.features() & MessageCore::MailingList::Id ) {
359 listId = mailList.id();
363 }
else if ( start == 0 ) {
368 listId = listId.
mid( 1, end-1 );
372 mMailingListActionMenu->menu()->clear();
373 qDeleteAll(mMailListActionList);
374 mMailListActionList.
clear();
376 mMailingListActionMenu->menu()->addTitle( listId );
378 if ( mailList.features() & MessageCore::MailingList::ArchivedAt )
380 addMailingListActions( i18n(
"Open Message in List Archive" ), mailList.archivedAtUrls() );
381 if ( mailList.features() & MessageCore::MailingList::Post )
382 addMailingListActions( i18n(
"Post New Message" ), mailList.postUrls() );
383 if ( mailList.features() & MessageCore::MailingList::Archive )
384 addMailingListActions( i18n(
"Go to Archive" ), mailList.archiveUrls() );
385 if ( mailList.features() & MessageCore::MailingList::Help )
386 addMailingListActions( i18n(
"Request Help" ), mailList.helpUrls() );
387 if ( mailList.features() & MessageCore::MailingList::Owner )
388 addMailingListActions( i18nc(
"Contact the owner of the mailing list",
"Contact Owner" ), mailList.ownerUrls() );
389 if ( mailList.features() & MessageCore::MailingList::Subscribe )
390 addMailingListActions( i18n(
"Subscribe to List" ), mailList.subscribeUrls() );
391 if ( mailList.features() & MessageCore::MailingList::Unsubscribe )
392 addMailingListActions( i18n(
"Unsubscribe from List" ), mailList.unsubscribeUrls() );
393 mMailingListActionMenu->setEnabled(
true );
397 const QString lname = MailingList::name( message, name, value );
399 mListFilterAction->setEnabled(
true );
400 mListFilterAction->setText( i18n(
"Filter on Mailing-List %1...", lname ) );
406 void MessageActions::replyCommand(MessageComposer::ReplyStrategy strategy)
408 if ( !mCurrentItem.hasPayload<KMime::Message::Ptr>() )
return;
419 mMessageView = msgView;
424 disconnect( mForwardActionMenu, SIGNAL(triggered(
bool)), 0, 0 );
425 mForwardActionMenu->removeAction( mForwardInlineAction );
426 mForwardActionMenu->removeAction( mForwardAttachedAction );
429 mForwardActionMenu->insertAction( mRedirectAction, mForwardInlineAction );
430 mForwardActionMenu->insertAction( mRedirectAction, mForwardAttachedAction );
431 mForwardInlineAction->setShortcut(
QKeySequence(Qt::Key_F));
432 mForwardAttachedAction->setShortcut(
QKeySequence(Qt::SHIFT+Qt::Key_F));
434 mParent, SLOT(slotForwardInlineMsg()) );
436 mForwardActionMenu->insertAction( mRedirectAction, mForwardAttachedAction );
437 mForwardActionMenu->insertAction( mRedirectAction, mForwardInlineAction );
438 mForwardInlineAction->setShortcut(
QKeySequence(Qt::Key_F));
439 mForwardAttachedAction->setShortcut(
QKeySequence(Qt::SHIFT+Qt::Key_F));
441 mParent, SLOT(slotForwardAttachedMsg()) );
448 guiClient->unplugActionList(
QLatin1String(
"forward_action_list") );
450 forwardActionList.
append( mForwardInlineAction );
451 forwardActionList.
append( mForwardAttachedAction );
453 forwardActionList.
append( mForwardAttachedAction );
454 forwardActionList.
append( mForwardInlineAction );
456 forwardActionList.
append( mRedirectAction );
457 guiClient->plugActionList(
QLatin1String(
"forward_action_list"), forwardActionList );
461 void MessageActions::slotReplyToMsg()
463 replyCommand( MessageComposer::ReplySmart );
466 void MessageActions::slotReplyAuthorToMsg()
468 replyCommand( MessageComposer::ReplyAuthor );
471 void MessageActions::slotReplyListToMsg()
473 replyCommand( MessageComposer::ReplyList );
476 void MessageActions::slotReplyAllToMsg()
478 replyCommand( MessageComposer::ReplyAll );
481 void MessageActions::slotNoQuoteReplyToMsg()
483 if ( !mCurrentItem.hasPayload<KMime::Message::Ptr>() )
489 void MessageActions::slotRunUrl(
QAction *urlAction )
492 if ( q.
type() == QVariant::String ) {
493 new KRun( KUrl( q.
toString() ) , mParent );
497 void MessageActions::slotMailingListFilter()
499 if ( !mCurrentItem.hasPayload<KMime::Message::Ptr>() )
506 void MessageActions::printMessage(
bool preview)
509 if ( mMessageView ) {
510 if (MessageViewer::GlobalSettings::self()->printSelectedText()) {
515 const bool useFixedFont = MessageViewer::GlobalSettings::self()->useFixedFont();
516 const QString overrideEncoding = MessageCore::GlobalSettings::self()->overrideCharacterEncoding();
518 const Akonadi::Item message = mCurrentItem;
521 mMessageView->
viewer()->headerStyle(), mMessageView->
viewer()->headerStrategy(),
522 mMessageView->
viewer()->displayFormatMessageOverwrite(), mMessageView->
viewer()->htmlLoadExternal(),
523 useFixedFont, overrideEncoding );
529 void MessageActions::slotPrintPreviewMsg()
534 void MessageActions::slotPrintMsg()
547 void MessageActions::addMailingListActions(
const QString &item,
const KUrl::List &list )
549 foreach (
const KUrl& url, list ) {
550 addMailingListAction( item, url );
558 void MessageActions::addMailingListAction(
const QString &item,
const KUrl &url )
561 QString prettyUrl = url.prettyUrl();
563 protocol = i18n(
"email" );
566 protocol = i18n(
"web" );
569 KAction *act =
new KAction( i18nc(
"%1 is a 'Contact Owner' or similar action. %2 is a protocol normally web or email though could be irc/ftp or other url variant",
"%1 (%2)", item, protocol ) ,
this );
570 mMailListActionList.
append(act);
573 act->setHelpText( prettyUrl );
574 mMailingListActionMenu->addAction( act );
580 if ( mCurrentItem.isValid() ) {
581 Akonadi::Collection col = mCurrentItem.parentCollection();
582 qDebug()<<
" mCurrentItem.parentCollection()"<<mCurrentItem.parentCollection();
586 && ( CommonKernel->folderIsDraftOrOutbox( col ) ||
587 CommonKernel->folderIsTemplates( col ) )
593 }
else if ( mCurrentItem.hasPayload<KMime::Message::Ptr>() ) {
601 if ( !mCurrentItem.isValid() )
604 MessageCore::AnnotationEditDialog *dialog =
new MessageCore::AnnotationEditDialog( mCurrentItem );
605 dialog->setAttribute( Qt::WA_DeleteOnClose );
620 KUriFilterData filterData( searchText );
622 filterData.setSearchFilteringOptions( KUriFilterData::RetrievePreferredSearchProvidersOnly );
624 if ( KUriFilter::self()->filterSearchUri( filterData, KUriFilter::NormalTextFilter ) ) {
625 const QStringList searchProviders = filterData.preferredSearchProviders();
627 if ( !searchProviders.
isEmpty() ) {
628 KMenu *webShortcutsMenu =
new KMenu( menu );
629 webShortcutsMenu->setIcon( KIcon(
QLatin1String(
"preferences-web-browser-shortcuts") ) );
631 const QString squeezedText = KStringHandler::rsqueeze( searchText, 21 );
632 webShortcutsMenu->setTitle( i18n(
"Search for '%1' with", squeezedText ) );
636 foreach(
const QString &searchProvider, searchProviders ) {
637 action =
new KAction( searchProvider, webShortcutsMenu );
638 action->setIcon( KIcon( filterData.iconNameForPreferredSearchProvider( searchProvider ) ) );
639 action->setData( filterData.queryForPreferredSearchProvider( searchProvider ) );
640 connect( action, SIGNAL(triggered()),
this, SLOT(slotHandleWebShortcutAction()) );
641 webShortcutsMenu->addAction( action );
644 webShortcutsMenu->addSeparator();
646 action =
new KAction( i18n(
"Configure Web Shortcuts..." ), webShortcutsMenu );
648 connect( action, SIGNAL(triggered()),
this, SLOT(slotConfigureWebShortcuts()) );
649 webShortcutsMenu->addAction( action );
651 menu->addMenu(webShortcutsMenu);
656 void MessageActions::slotHandleWebShortcutAction()
658 KAction *action = qobject_cast<KAction*>(
sender() );
661 KUriFilterData filterData( action->data().toString() );
662 if ( KUriFilter::self()->filterSearchUri( filterData, KUriFilter::WebShortcutFilter ) ) {
663 KToolInvocation::invokeBrowser( filterData.uri().url() );
668 void MessageActions::slotConfigureWebShortcuts()
673 void MessageActions::slotDebugBaloo()
675 if ( !mCurrentItem.isValid() )
678 dlg->setAkonadiId(mCurrentItem.id());
679 dlg->setAttribute( Qt::WA_DeleteOnClose );
680 dlg->setSearchType(PimCommon::BalooDebugSearchPathComboBox::Emails);
685 void MessageActions::slotAddFollowupReminder()
687 if (!mCurrentItem.isValid() )
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
void addWebShortcutsMenu(KMenu *menu, const QString &text)
void editCurrentMessage()
void truncate(int position)
void replyActionFinished()
KAction * akonadiStandardAction(Akonadi::StandardActionManager::Type type)
This class implements a "reader window", that is a window used for reading or viewing messages...
MessageViewer::Viewer * viewer()
virtual QByteArray text(quint32 serialNumber) const =0
QString simplified() const
MessageActions(KActionCollection *ac, QWidget *parent)
QString & remove(int position, int n)
TemplateParser::CustomTemplatesMenu * customTemplatesMenu() const
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
static KMKernel * self()
normal control stuff
void setupForwardingActionsList(KXMLGUIClient *guiClient)
Sets up action list for forward menu.
int lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
const char * name() const
void append(const T &value)
void setCollection(const Akonadi::Collection &collection)
Small helper structure which encapsulates the KMMessage created when creating a reply, and.
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
KActionMenu * forwardMenu() const
void setCurrentMessage(const Akonadi::Item &item, const Akonadi::Item::List &items=Akonadi::Item::List())
QString & replace(int position, int n, QChar after)
static GlobalSettings * self()
KActionMenu * replyMenu() const
QString mid(int position, int n) const
void setPrintPreview(bool preview)
void setMessageView(KMReaderWin *msgView)
QString copyText() const
Return selected text.
void setDate(const QDate &date)
bool printSelectedText(bool preview)
void setMessageItem(const Akonadi::Item &messageItem)
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void setupForwardActions()
This function adds or updates the actions of the forward action menu, taking the preference whether t...