diff --git a/kmail/kmmainwidget.cpp b/kmail/kmmainwidget.cpp index ff8b68273b..f6139ff9b1 100644 --- a/kmail/kmmainwidget.cpp +++ b/kmail/kmmainwidget.cpp @@ -1,4864 +1,4864 @@ /* -*- mode: C++; c-file-style: "gnu" -*- This file is part of KMail, the KDE mail client. Copyright (c) 2002 Don Sanders Copyright (c) 2009, 2010, 2011, 2012 Montel Laurent Based on the work of Stefan Taferner KMail is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation. KMail is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ // KMail includes #include "kmreadermainwin.h" #include "editor/composer.h" #include "searchdialog/searchwindow.h" #include "antispam-virus/antispamwizard.h" #include "widgets/vacationscriptindicatorwidget.h" #include "undostack.h" #include "kmcommands.h" #include "kmmainwin.h" #include "kmsystemtray.h" #include "customtemplatesmenu.h" #include "folderselectiondialog.h" #include "foldertreewidget.h" #include "util.h" #include "util/mailutil.h" #include "kernel/mailkernel.h" #include "dialog/archivefolderdialog.h" #include "settings/globalsettings.h" #include "foldertreeview.h" #include "tag/tagactionmanager.h" #include "foldershortcutactionmanager.h" #include "widgets/collectionpane.h" #if !defined(NDEBUG) #include using KSieveUi::SieveDebugDialog; #endif #include "collectionpage/collectionmaintenancepage.h" #include "collectionpage/collectionquotapage.h" #include "collectionpage/collectiontemplatespage.h" #include "collectionpage/collectionshortcutpage.h" #include "collectionpage/collectionviewpage.h" #include "collectionpage/collectionmailinglistpage.h" #include "archivemailagentinterface.h" #include "job/createnewcontactjob.h" #include "sendlateragentinterface.h" #include "folderarchive/folderarchiveutil.h" #include "folderarchive/folderarchivemanager.h" #include "pimcommon/acl/collectionaclpage.h" #include "mailcommon/collectionpage/collectiongeneralpage.h" #include "mailcommon/collectionpage/collectionexpirypage.h" #include "mailcommon/collectionpage/expirecollectionattribute.h" #include "mailcommon/filter/filtermanager.h" #include "mailcommon/filter/mailfilter.h" #include "mailcommon/widgets/favoritecollectionwidget.h" #include "mailcommon/folder/foldertreewidget.h" #include "mailcommon/folder/foldertreeview.h" #include "mailcommon/mailcommonsettings_base.h" #include "kmmainwidget.h" // Other PIM includes #include "kdepim-version.h" #include "messageviewer/utils/autoqpointer.h" #include "messageviewer/settings/globalsettings.h" #include "messageviewer/viewer/viewer.h" #include "messageviewer/viewer/attachmentstrategy.h" #include "messageviewer/header/headerstrategy.h" #include "messageviewer/header/headerstyle.h" #ifndef QT_NO_CURSOR #include "messageviewer/utils/kcursorsaver.h" #endif #include "messagecomposer/sender/messagesender.h" #include "messagecomposer/helper/messagehelper.h" #include "templateparser/templateparser.h" #include "messagecore/settings/globalsettings.h" #include "messagecore/misc/mailinglist.h" #include "messagecore/helpers/messagehelpers.h" #include "dialog/kmknotify.h" #include "ksieveui/vacation/vacationmanager.h" // LIBKDEPIM includes #include "progresswidget/progressmanager.h" #include "misc/broadcaststatus.h" // KDEPIMLIBS includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDELIBS includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // System includes #include #include // ugh #include using namespace KMime; using namespace Akonadi; using namespace MailCommon; using KPIM::ProgressManager; using KPIM::BroadcastStatus; using KMail::SearchWindow; using KMail::AntiSpamWizard; using KMime::Types::AddrSpecList; using MessageViewer::AttachmentStrategy; Q_DECLARE_METATYPE(KPIM::ProgressItem*) Q_DECLARE_METATYPE(Akonadi::Job*) Q_DECLARE_METATYPE(QPointer) K_GLOBAL_STATIC( KMMainWidget::PtrList, theMainWidgetList ) //----------------------------------------------------------------------------- KMMainWidget::KMMainWidget( QWidget *parent, KXMLGUIClient *aGUIClient, KActionCollection *actionCollection, KSharedConfig::Ptr config ) : QWidget( parent ), mMoveMsgToFolderAction(0), mCollectionProperties( 0 ), mFavoriteCollectionsView( 0 ), mMsgView( 0 ), mSplitter1( 0 ), mSplitter2( 0 ), mFolderViewSplitter( 0 ), mArchiveFolderAction( 0 ), mShowBusySplashTimer( 0 ), mMsgActions( 0 ), mCurrentFolder( 0 ), mVacationIndicatorActive( false ), mGoToFirstUnreadMessageInSelectedFolder( false ) { // must be the first line of the constructor: mStartupDone = false; mWasEverShown = false; mReaderWindowActive = true; mReaderWindowBelow = true; mFolderHtmlPref = false; mFolderHtmlLoadExtPref = false; mDestructed = false; mActionCollection = actionCollection; mTopLayout = new QVBoxLayout( this ); mTopLayout->setMargin( 0 ); mConfig = config; mGUIClient = aGUIClient; mFolderTreeWidget = 0; mPreferHtmlAction = 0; mPreferHtmlLoadExtAction = 0; Akonadi::Control::widgetNeedsAkonadi( this ); mFavoritesModel = 0; mVacationManager = new KSieveUi::VacationManager(this); // FIXME This should become a line separator as soon as the API // is extended in kdelibs. mToolbarActionSeparator = new QAction( this ); mToolbarActionSeparator->setSeparator( true ); theMainWidgetList->append( this ); readPreConfig(); createWidgets(); setupActions(); readConfig(); if ( !kmkernel->isOffline() ) { //kmail is set to online mode, make sure the agents are also online kmkernel->setAccountStatus(true); } QTimer::singleShot( 0, this, SLOT(slotShowStartupFolder())); connect( kmkernel, SIGNAL(startCheckMail()), this, SLOT(slotStartCheckMail()) ); connect( kmkernel, SIGNAL(endCheckMail()), this, SLOT(slotEndCheckMail()) ); connect( kmkernel, SIGNAL(configChanged()), this, SLOT(slotConfigChanged()) ); connect( kmkernel, SIGNAL(onlineStatusChanged(GlobalSettings::EnumNetworkState::type)), this, SLOT(slotUpdateOnlineStatus(GlobalSettings::EnumNetworkState::type)) ); connect( mTagActionManager, SIGNAL(tagActionTriggered(Akonadi::Tag)), this, SLOT(slotUpdateMessageTagList(Akonadi::Tag)) ); connect( mTagActionManager, SIGNAL(tagMoreActionClicked()), this, SLOT(slotSelectMoreMessageTagList()) ); kmkernel->toggleSystemTray(); { // make sure the pages are registered only once, since there can be multiple instances of KMMainWidget static bool pagesRegistered = false; if ( !pagesRegistered ) { Akonadi::CollectionPropertiesDialog::registerPage( new PimCommon::CollectionAclPageFactory ); Akonadi::CollectionPropertiesDialog::registerPage( new MailCommon::CollectionGeneralPageFactory ); Akonadi::CollectionPropertiesDialog::registerPage( new CollectionMaintenancePageFactory ); Akonadi::CollectionPropertiesDialog::registerPage( new CollectionQuotaPageFactory ); Akonadi::CollectionPropertiesDialog::registerPage( new CollectionTemplatesPageFactory ); Akonadi::CollectionPropertiesDialog::registerPage( new MailCommon::CollectionExpiryPageFactory ); Akonadi::CollectionPropertiesDialog::registerPage( new CollectionViewPageFactory ); Akonadi::CollectionPropertiesDialog::registerPage( new CollectionMailingListPageFactory ); Akonadi::CollectionPropertiesDialog::registerPage( new CollectionShortcutPageFactory ); pagesRegistered = true; } } KMainWindow *mainWin = dynamic_cast(window()); KStatusBar *sb = mainWin ? mainWin->statusBar() : 0; mVacationScriptIndicator = new KMail::VacationScriptIndicatorWidget( sb ); mVacationScriptIndicator->hide(); connect( mVacationScriptIndicator, SIGNAL(clicked(QString)), SLOT(slotEditVacation(QString)) ); if ( KSieveUi::Util::checkOutOfOfficeOnStartup() ) QTimer::singleShot( 0, this, SLOT(slotCheckVacation()) ); connect( mFolderTreeWidget->folderTreeView()->model(), SIGNAL(modelReset()), this, SLOT(restoreCollectionFolderViewConfig()) ); restoreCollectionFolderViewConfig(); if ( kmkernel->firstStart() ) { if (MailCommon::Util::foundMailer()) { if (KMessageBox::questionYesNo(this,i18n("Another mailer was found on system. Do you want to import data from it?")) == KMessageBox::Yes) { const QString path = KStandardDirs::findExe( QLatin1String("importwizard" ) ); if ( !QProcess::startDetached( path ) ) { KMessageBox::error( this, i18n( "Could not start the import wizard. " "Please check your installation." ), i18n( "Unable to start import wizard" ) ); } } else { KMail::Util::launchAccountWizard( this ); } } else { KMail::Util::launchAccountWizard( this ); } } // must be the last line of the constructor: mStartupDone = true; mCheckMailTimer.setInterval( 3 * 1000 ); mCheckMailTimer.setSingleShot( true ); connect( &mCheckMailTimer, SIGNAL(timeout()), SLOT(slotUpdateActionsAfterMailChecking()) ); } void KMMainWidget::restoreCollectionFolderViewConfig() { ETMViewStateSaver *saver = new ETMViewStateSaver; saver->setView( mFolderTreeWidget->folderTreeView() ); const KConfigGroup cfg( KMKernel::self()->config(), "CollectionFolderView" ); mFolderTreeWidget->restoreHeaderState( cfg.readEntry( "HeaderState", QByteArray() ) ); saver->restoreState( cfg ); //Restore startup folder Akonadi::Collection::Id id = -1; if (mCurrentFolder && mCurrentFolder->collection().isValid() ) { id = mCurrentFolder->collection().id(); } if (id == -1) { if (GlobalSettings::self()->startSpecificFolderAtStartup()) { Akonadi::Collection::Id startupFolder = GlobalSettings::self()->startupFolder(); if ( startupFolder > 0 ) saver->restoreCurrentItem( QString::fromLatin1("c%1").arg(startupFolder) ); } } else { saver->restoreCurrentItem( QString::fromLatin1("c%1").arg(id) ); } } //----------------------------------------------------------------------------- //The kernel may have already been deleted when this method is called, //perform all cleanup that requires the kernel in destruct() KMMainWidget::~KMMainWidget() { theMainWidgetList->removeAll( this ); qDeleteAll( mFilterCommands ); destruct(); } //----------------------------------------------------------------------------- //This method performs all cleanup that requires the kernel to exist. void KMMainWidget::destruct() { if ( mDestructed ) return; if ( mSearchWin ) mSearchWin->close(); writeConfig(false); /* don't force kmkernel sync when close BUG: 289287 */ writeFolderConfig(); deleteWidgets(); mCurrentFolder.clear(); delete mMoveOrCopyToDialog; delete mSelectFromAllFoldersDialog; disconnect( kmkernel->folderCollectionMonitor(), SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection)), this, 0); disconnect( kmkernel->folderCollectionMonitor(), SIGNAL(itemRemoved(Akonadi::Item)), this, 0); disconnect( kmkernel->folderCollectionMonitor(), SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection)), this, 0); disconnect( kmkernel->folderCollectionMonitor(), SIGNAL(collectionChanged(Akonadi::Collection,QSet)), this, 0); disconnect( kmkernel->folderCollectionMonitor(), SIGNAL(collectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics)), this, 0); mDestructed = true; } void KMMainWidget::slotStartCheckMail() { if ( mCheckMailTimer.isActive() ) mCheckMailTimer.stop(); } void KMMainWidget::slotEndCheckMail() { if ( !mCheckMailTimer.isActive() ) mCheckMailTimer.start(); } void KMMainWidget::slotUpdateActionsAfterMailChecking() { const bool sendOnAll = GlobalSettings::self()->sendOnCheck() == GlobalSettings::EnumSendOnCheck::SendOnAllChecks; const bool sendOnManual = GlobalSettings::self()->sendOnCheck() == GlobalSettings::EnumSendOnCheck::SendOnManualChecks; if ( !kmkernel->isOffline() && ( sendOnAll || (sendOnManual /*&& sendOnCheck*/ ) ) ) { slotSendQueued(); } // update folder menus in case some mail got filtered to trash/current folder // and we can enable "empty trash/move all to trash" action etc. updateFolderMenu(); } void KMMainWidget::slotCollectionFetched( int collectionId ) { // Called when a collection is fetched for the first time by the ETM. // This is the right time to update the caption (which still says "Loading...") // and to update the actions that depend on the number of mails in the folder. if ( mCurrentFolder && collectionId == mCurrentFolder->collection().id() ) { mCurrentFolder->setCollection( MailCommon::Util::updatedCollection( mCurrentFolder->collection() ) ); updateMessageActions(); updateFolderMenu(); } // We call this for any collection, it could be one of our parents... if ( mCurrentFolder ) { emit captionChangeRequest( MailCommon::Util::fullCollectionPath( mCurrentFolder->collection() ) ); } } void KMMainWidget::slotFolderChanged( const Akonadi::Collection& collection ) { folderSelected( collection ); if (collection.cachePolicy().syncOnDemand()) AgentManager::self()->synchronizeCollection( collection, false ); mMsgActions->setCurrentMessage( Akonadi::Item() ); emit captionChangeRequest( MailCommon::Util::fullCollectionPath( collection ) ); } void KMMainWidget::folderSelected( const Akonadi::Collection & col ) { // This is connected to the MainFolderView signal triggering when a folder is selected if ( mGoToFirstUnreadMessageInSelectedFolder ) { // the default action has been overridden from outside mPreSelectionMode = MessageList::Core::PreSelectFirstUnreadCentered; } else { // use the default action switch ( GlobalSettings::self()->actionEnterFolder() ) { case GlobalSettings::EnumActionEnterFolder::SelectFirstUnread: mPreSelectionMode = MessageList::Core::PreSelectFirstUnreadCentered; break; case GlobalSettings::EnumActionEnterFolder::SelectLastSelected: mPreSelectionMode = MessageList::Core::PreSelectLastSelected; break; case GlobalSettings::EnumActionEnterFolder::SelectNewest: mPreSelectionMode = MessageList::Core::PreSelectNewestCentered; break; case GlobalSettings::EnumActionEnterFolder::SelectOldest: mPreSelectionMode = MessageList::Core::PreSelectOldestCentered; break; default: mPreSelectionMode = MessageList::Core::PreSelectNone; break; } } mGoToFirstUnreadMessageInSelectedFolder = false; #ifndef QT_NO_CURSOR MessageViewer::KCursorSaver busy( MessageViewer::KBusyPtr::busy() ); #endif if (mMsgView) mMsgView->clear(true); const bool newFolder = mCurrentFolder && ( mCurrentFolder->collection() != col ); // Delete any pending timer, if needed it will be recreated below delete mShowBusySplashTimer; mShowBusySplashTimer = 0; if ( newFolder ) { // We're changing folder: write configuration for the old one writeFolderConfig(); } mCurrentFolder = FolderCollection::forCollection( col ); readFolderConfig(); if (mMsgView) { mMsgView->setHtmlOverride(mFolderHtmlPref); mMsgView->setHtmlLoadExtOverride(mFolderHtmlLoadExtPref); } if ( !mCurrentFolder->isValid() && ( mMessagePane->count() < 2 ) ) slotIntro(); updateMessageActions(); updateFolderMenu(); // The message pane uses the selection model of the folder view to load the correct aggregation model and theme // settings. At this point the selection model hasn't been updated yet to the user's new choice, so it would load // the old folder settings instead. QTimer::singleShot( 0, this, SLOT(slotShowSelectedFolderInPane()) ); } void KMMainWidget::slotShowSelectedFolderInPane() { if ( mCurrentFolder && mCurrentFolder->collection().isValid() ) { mMessagePane->setCurrentFolder( mCurrentFolder->collection(), false , mPreSelectionMode ); } } void KMMainWidget::clearViewer() { if (mMsgView) { mMsgView->clear( true ); mMsgView->displayAboutPage(); } } //----------------------------------------------------------------------------- void KMMainWidget::readPreConfig() { mLongFolderList = GlobalSettings::self()->folderList() == GlobalSettings::EnumFolderList::longlist; mReaderWindowActive = GlobalSettings::self()->readerWindowMode() != GlobalSettings::EnumReaderWindowMode::hide; mReaderWindowBelow = GlobalSettings::self()->readerWindowMode() == GlobalSettings::EnumReaderWindowMode::below; mHtmlPref = MessageViewer::GlobalSettings::self()->htmlMail(); mHtmlLoadExtPref = MessageViewer::GlobalSettings::self()->htmlLoadExternal(); mEnableFavoriteFolderView = ( MailCommon::MailCommonSettings::self()->favoriteCollectionViewMode() != MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::HiddenMode ); mEnableFolderQuickSearch = GlobalSettings::self()->enableFolderQuickSearch(); updateHtmlMenuEntry(); } //----------------------------------------------------------------------------- void KMMainWidget::readFolderConfig() { if ( !mCurrentFolder || !mCurrentFolder->isValid() ) return; KSharedConfig::Ptr config = KMKernel::self()->config(); KConfigGroup group( config, MailCommon::FolderCollection::configGroupName( mCurrentFolder->collection() ) ); mFolderHtmlPref = group.readEntry( "htmlMailOverride", false ); mFolderHtmlLoadExtPref = group.readEntry( "htmlLoadExternalOverride", false ); } //----------------------------------------------------------------------------- void KMMainWidget::writeFolderConfig() { if ( mCurrentFolder && mCurrentFolder->isValid() ) { KSharedConfig::Ptr config = KMKernel::self()->config(); KConfigGroup group( config, MailCommon::FolderCollection::configGroupName( mCurrentFolder->collection() ) ); group.writeEntry( "htmlMailOverride", mFolderHtmlPref ); group.writeEntry( "htmlLoadExternalOverride", mFolderHtmlLoadExtPref ); } } //----------------------------------------------------------------------------- void KMMainWidget::layoutSplitters() { // This function can only be called when the old splitters are already deleted assert( !mSplitter1 ); assert( !mSplitter2 ); // For some reason, this is necessary here so that the copy action still // works after changing the folder layout. if ( mMsgView ) disconnect( mMsgView->copyAction(), SIGNAL(triggered(bool)), mMsgView, SLOT(slotCopySelectedText()) ); // If long folder list is enabled, the splitters are: // Splitter 1: FolderView vs (HeaderAndSearch vs MessageViewer) // Splitter 2: HeaderAndSearch vs MessageViewer // // If long folder list is disabled, the splitters are: // Splitter 1: (FolderView vs HeaderAndSearch) vs MessageViewer // Splitter 2: FolderView vs HeaderAndSearch // The folder view is both the folder tree and the favorite folder view, if // enabled const bool opaqueResize = KGlobalSettings::opaqueResize(); const bool readerWindowAtSide = !mReaderWindowBelow && mReaderWindowActive; const bool readerWindowBelow = mReaderWindowBelow && mReaderWindowActive; mSplitter1 = new QSplitter( this ); mSplitter2 = new QSplitter( mSplitter1 ); QWidget * folderTreeWidget = mSearchAndTree; if ( mFavoriteCollectionsView ) { mFolderViewSplitter = new QSplitter( Qt::Vertical ); mFolderViewSplitter->setOpaqueResize( opaqueResize ); //mFolderViewSplitter->setChildrenCollapsible( false ); mFolderViewSplitter->addWidget( mFavoriteCollectionsView ); mFavoriteCollectionsView->setParent( mFolderViewSplitter ); mFolderViewSplitter->addWidget( mSearchAndTree ); folderTreeWidget = mFolderViewSplitter; } if ( mLongFolderList ) { // add folder tree mSplitter1->setOrientation( Qt::Horizontal ); mSplitter1->addWidget( folderTreeWidget ); // and the rest to the right mSplitter1->addWidget( mSplitter2 ); // add the message list to the right or below if ( readerWindowAtSide ) { mSplitter2->setOrientation( Qt::Horizontal ); } else { mSplitter2->setOrientation( Qt::Vertical ); } mSplitter2->addWidget( mMessagePane ); // add the preview window, if there is one if ( mMsgView ) { mSplitter2->addWidget( mMsgView ); } } else { // short folder list if ( mReaderWindowBelow ) { mSplitter1->setOrientation( Qt::Vertical ); mSplitter2->setOrientation( Qt::Horizontal ); } else { // at side or none mSplitter1->setOrientation( Qt::Horizontal ); mSplitter2->setOrientation( Qt::Vertical ); } mSplitter1->addWidget( mSplitter2 ); // add folder tree mSplitter2->addWidget( folderTreeWidget ); // add message list to splitter 2 mSplitter2->addWidget( mMessagePane ); // add the preview window, if there is one if ( mMsgView ) mSplitter1->addWidget( mMsgView ); } // // Set splitter properties // mSplitter1->setObjectName( QLatin1String("splitter1") ); mSplitter1->setOpaqueResize( opaqueResize ); //mSplitter1->setChildrenCollapsible( false ); mSplitter2->setObjectName( QLatin1String("splitter2") ); mSplitter2->setOpaqueResize( opaqueResize ); //mSplitter2->setChildrenCollapsible( false ); // // Set the stretch factors // mSplitter1->setStretchFactor( 0, 0 ); mSplitter2->setStretchFactor( 0, 0 ); mSplitter1->setStretchFactor( 1, 1 ); mSplitter2->setStretchFactor( 1, 1 ); if ( mFavoriteCollectionsView ) { mFolderViewSplitter->setStretchFactor( 0, 0 ); mFolderViewSplitter->setStretchFactor( 1, 1 ); } // Because the reader windows's width increases a tiny bit after each // restart in short folder list mode with message window at side, disable // the stretching as a workaround here if ( readerWindowAtSide && !mLongFolderList ) { mSplitter1->setStretchFactor( 0, 1 ); mSplitter1->setStretchFactor( 1, 0 ); } // // Set the sizes of the splitters to the values stored in the config // QList splitter1Sizes; QList splitter2Sizes; const int folderViewWidth = GlobalSettings::self()->folderViewWidth(); int ftHeight = GlobalSettings::self()->folderTreeHeight(); int headerHeight = GlobalSettings::self()->searchAndHeaderHeight(); const int messageViewerWidth = GlobalSettings::self()->readerWindowWidth(); int headerWidth = GlobalSettings::self()->searchAndHeaderWidth(); int messageViewerHeight = GlobalSettings::self()->readerWindowHeight(); int ffvHeight = mFolderViewSplitter ? MailCommon::MailCommonSettings::self()->favoriteCollectionViewHeight() : 0; // If the message viewer was hidden before, make sure it is not zero height if ( messageViewerHeight < 10 && readerWindowBelow ) { headerHeight /= 2; messageViewerHeight = headerHeight; } if ( mLongFolderList ) { if ( !readerWindowAtSide ) { splitter1Sizes << folderViewWidth << headerWidth; splitter2Sizes << headerHeight << messageViewerHeight; } else { splitter1Sizes << folderViewWidth << ( headerWidth + messageViewerWidth ); splitter2Sizes << headerWidth << messageViewerWidth; } } else { if ( !readerWindowAtSide ) { splitter1Sizes << headerHeight << messageViewerHeight; splitter2Sizes << folderViewWidth << headerWidth; } else { splitter1Sizes << headerWidth << messageViewerWidth; splitter2Sizes << ftHeight + ffvHeight << messageViewerHeight; } } mSplitter1->setSizes( splitter1Sizes ); mSplitter2->setSizes( splitter2Sizes ); if ( mFolderViewSplitter ) { QList splitterSizes; splitterSizes << ffvHeight << ftHeight; mFolderViewSplitter->setSizes( splitterSizes ); } // // Now add the splitters to the main layout // mTopLayout->addWidget( mSplitter1 ); // Make sure the focus is on the view, and not on the quick search line edit, because otherwise // shortcuts like + or j go to the wrong place. // This would normally be done in the message list itself, but apparently something resets the focus // again, probably all the reparenting we do here. mMessagePane->focusView(); // By default hide th unread and size columns on first run. if ( kmkernel->firstStart() ) { mFolderTreeWidget->folderTreeView()->hideColumn( 1 ); mFolderTreeWidget->folderTreeView()->hideColumn( 3 ); mFolderTreeWidget->folderTreeView()->header()->resizeSection( 0, folderViewWidth * 0.8 ); } // Make the copy action work, see disconnect comment above if ( mMsgView ) connect( mMsgView->copyAction(), SIGNAL(triggered(bool)), mMsgView, SLOT(slotCopySelectedText()) ); } //----------------------------------------------------------------------------- void KMMainWidget::refreshFavoriteFoldersViewProperties() { if ( mFavoriteCollectionsView ) { if ( MailCommon::MailCommonSettings::self()->favoriteCollectionViewMode() == MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::IconMode ) mFavoriteCollectionsView->setViewMode( QListView::IconMode ); else if ( MailCommon::MailCommonSettings::self()->favoriteCollectionViewMode() == MailCommon::MailCommonSettings::EnumFavoriteCollectionViewMode::ListMode ) mFavoriteCollectionsView->setViewMode( QListView::ListMode ); else Q_ASSERT(false); // we should never get here in hidden mode mFavoriteCollectionsView->setDropActionMenuEnabled( kmkernel->showPopupAfterDnD() ); mFavoriteCollectionsView->setWordWrap( true ); mFavoriteCollectionsView->updateMode(); } } //----------------------------------------------------------------------------- void KMMainWidget::readConfig() { const bool oldLongFolderList = mLongFolderList; const bool oldReaderWindowActive = mReaderWindowActive; const bool oldReaderWindowBelow = mReaderWindowBelow; const bool oldFavoriteFolderView = mEnableFavoriteFolderView; const bool oldFolderQuickSearch = mEnableFolderQuickSearch; // on startup, the layout is always new and we need to relayout the widgets bool layoutChanged = !mStartupDone; if ( mStartupDone ) { readPreConfig(); layoutChanged = ( oldLongFolderList != mLongFolderList ) || ( oldReaderWindowActive != mReaderWindowActive ) || ( oldReaderWindowBelow != mReaderWindowBelow ) || ( oldFavoriteFolderView != mEnableFavoriteFolderView ); if ( layoutChanged ) { deleteWidgets(); createWidgets(); restoreCollectionFolderViewConfig(); emit recreateGui(); } else if ( oldFolderQuickSearch != mEnableFolderQuickSearch ) { if ( mEnableFolderQuickSearch ) mFolderTreeWidget->filterFolderLineEdit()->show(); else mFolderTreeWidget->filterFolderLineEdit()->hide(); } } { // Read the config of the folder views and the header if ( mMsgView ) { mMsgView->readConfig(); } mMessagePane->reloadGlobalConfiguration(); mFolderTreeWidget->readConfig(); if ( mFavoriteCollectionsView ) { mFavoriteCollectionsView->readConfig(); } refreshFavoriteFoldersViewProperties(); } { // area for config group "General" if ( !mStartupDone ) { // check mail on startup // do it after building the kmmainwin, so that the progressdialog is available QTimer::singleShot( 0, this, SLOT(slotCheckMailOnStartup()) ); } } if ( layoutChanged ) { layoutSplitters(); } updateMessageMenu(); updateFileMenu(); kmkernel->toggleSystemTray(); connect( Akonadi::AgentManager::self(), SIGNAL(instanceAdded(Akonadi::AgentInstance)), this, SLOT(updateFileMenu()) ); connect( Akonadi::AgentManager::self(), SIGNAL(instanceRemoved(Akonadi::AgentInstance)), this, SLOT(updateFileMenu()) ); } //----------------------------------------------------------------------------- void KMMainWidget::writeConfig(bool force) { // Don't save the sizes of all the widgets when we were never shown. // This can happen in Kontact, where the KMail plugin is automatically // loaded, but not necessarily shown. // This prevents invalid sizes from being saved if ( mWasEverShown ) { // The height of the header widget can be 0, this happens when the user // did not switch to the header widget onced and the "Welcome to KMail" // HTML widget was shown the whole time int headersHeight = mMessagePane->height(); if ( headersHeight == 0 ) headersHeight = height() / 2; GlobalSettings::self()->setSearchAndHeaderHeight( headersHeight ); GlobalSettings::self()->setSearchAndHeaderWidth( mMessagePane->width() ); if ( mFavoriteCollectionsView ) { MailCommon::MailCommonSettings::self()->setFavoriteCollectionViewHeight( mFavoriteCollectionsView->height() ); GlobalSettings::self()->setFolderTreeHeight( mFolderTreeWidget->height() ); if ( !mLongFolderList ) { GlobalSettings::self()->setFolderViewHeight( mFolderViewSplitter->height() ); } } else if ( !mLongFolderList && mFolderTreeWidget ) { GlobalSettings::self()->setFolderTreeHeight( mFolderTreeWidget->height() ); } if ( mFolderTreeWidget ) { GlobalSettings::self()->setFolderViewWidth( mFolderTreeWidget->width() ); KSharedConfig::Ptr config = KMKernel::self()->config(); KConfigGroup group(config, "CollectionFolderView"); ETMViewStateSaver saver; saver.setView( mFolderTreeWidget->folderTreeView() ); saver.saveState( group ); group.writeEntry( "HeaderState", mFolderTreeWidget->folderTreeView()->header()->saveState() ); //Work around from startup folder group.deleteEntry( "Selection" ); #if 0 if (!GlobalSettings::self()->startSpecificFolderAtStartup()) { group.deleteEntry( "Current" ); } #endif group.sync(); } if ( mMsgView ) { if ( !mReaderWindowBelow ) GlobalSettings::self()->setReaderWindowWidth( mMsgView->width() ); mMsgView->viewer()->writeConfig(force); GlobalSettings::self()->setReaderWindowHeight( mMsgView->height() ); } } } void KMMainWidget::writeReaderConfig() { if ( mWasEverShown ) { if ( mMsgView ) { mMsgView->viewer()->writeConfig(); } } } //----------------------------------------------------------------------------- void KMMainWidget::deleteWidgets() { // Simply delete the top splitter, which always is mSplitter1, regardless // of the layout. This deletes all children. // akonadi action manager is created in createWidgets(), parented to this // so not autocleaned up. delete mAkonadiStandardActionManager; mAkonadiStandardActionManager = 0; delete mSplitter1; mMsgView = 0; mSearchAndTree = 0; mFolderViewSplitter = 0; mFavoriteCollectionsView = 0; mSplitter1 = 0; mSplitter2 = 0; mFavoritesModel = 0; } //----------------------------------------------------------------------------- void KMMainWidget::createWidgets() { // Note that all widgets we create in this function have the parent 'this'. // They will be properly reparented in layoutSplitters() // // Create header view and search bar // FolderTreeWidget::TreeViewOptions opt = FolderTreeWidget::ShowUnreadCount; opt |= FolderTreeWidget::UseLineEditForFiltering; opt |= FolderTreeWidget::ShowCollectionStatisticAnimation; opt |= FolderTreeWidget::DontKeyFilter; mFolderTreeWidget = new FolderTreeWidget( this, mGUIClient, opt ); connect( mFolderTreeWidget->folderTreeView(), SIGNAL(currentChanged(Akonadi::Collection)), this, SLOT(slotFolderChanged(Akonadi::Collection)) ); connect( mFolderTreeWidget->folderTreeView()->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(updateFolderMenu()) ); connect( mFolderTreeWidget->folderTreeView(), SIGNAL(prefereCreateNewTab(bool)), this, SLOT(slotCreateNewTab(bool)) ); mFolderTreeWidget->setSelectionMode( QAbstractItemView::ExtendedSelection ); mMessagePane = new CollectionPane( !GlobalSettings::self()->startSpecificFolderAtStartup(), KMKernel::self()->entityTreeModel(), mFolderTreeWidget->folderTreeView()->selectionModel(), this ); connect( KMKernel::self()->entityTreeModel(), SIGNAL(collectionFetched(int)), this, SLOT(slotCollectionFetched(int))); mMessagePane->setXmlGuiClient( mGUIClient ); connect( mMessagePane, SIGNAL(messageSelected(Akonadi::Item)), this, SLOT(slotMessageSelected(Akonadi::Item)) ); connect( mMessagePane, SIGNAL(selectionChanged()), SLOT(startUpdateMessageActionsTimer()) ); connect( mMessagePane, SIGNAL(currentTabChanged()), this, SLOT(refreshMessageListSelection()) ); connect( mMessagePane, SIGNAL(messageActivated(Akonadi::Item)), this, SLOT(slotMessageActivated(Akonadi::Item)) ); connect( mMessagePane, SIGNAL(messageStatusChangeRequest(Akonadi::Item,Akonadi::MessageStatus,Akonadi::MessageStatus)), SLOT(slotMessageStatusChangeRequest(Akonadi::Item,Akonadi::MessageStatus,Akonadi::MessageStatus)) ); connect( mMessagePane, SIGNAL(statusMessage(QString)), BroadcastStatus::instance(), SLOT(setStatusMsg(QString)) ); // // Create the reader window // if ( mReaderWindowActive ) { mMsgView = new KMReaderWin( this, this, actionCollection(), 0 ); if ( mMsgActions ) { mMsgActions->setMessageView( mMsgView ); } connect( mMsgView->viewer(), SIGNAL(replaceMsgByUnencryptedVersion()), this, SLOT(slotReplaceMsgByUnencryptedVersion()) ); connect( mMsgView->viewer(), SIGNAL(popupMenu(Akonadi::Item,KUrl,KUrl,QPoint)), this, SLOT(slotMessagePopup(Akonadi::Item,KUrl,KUrl,QPoint)) ); connect( mMsgView->viewer(), SIGNAL(moveMessageToTrash()), this, SLOT(slotMoveMessageToTrash()) ); } else { if ( mMsgActions ) { mMsgActions->setMessageView( 0 ); } } // // Create the folder tree // the "folder tree" consists of a quicksearch input field and the tree itself // mSearchAndTree = new QWidget( this ); QVBoxLayout *vboxlayout = new QVBoxLayout; vboxlayout->setMargin(0); mSearchAndTree->setLayout( vboxlayout ); vboxlayout->addWidget( mFolderTreeWidget ); if ( !GlobalSettings::self()->enableFolderQuickSearch() ) { mFolderTreeWidget->filterFolderLineEdit()->hide(); } // // Create the favorite folder view // mAkonadiStandardActionManager = new Akonadi::StandardMailActionManager( mGUIClient->actionCollection(), this ); connect( mAkonadiStandardActionManager, SIGNAL(actionStateUpdated()), this, SLOT(slotAkonadiStandardActionUpdated()) ); mAkonadiStandardActionManager->setCollectionSelectionModel( mFolderTreeWidget->folderTreeView()->selectionModel() ); mAkonadiStandardActionManager->setItemSelectionModel( mMessagePane->currentItemSelectionModel() ); if ( mEnableFavoriteFolderView ) { mFavoriteCollectionsView = new FavoriteCollectionWidget( mGUIClient, this ); refreshFavoriteFoldersViewProperties(); connect( mFavoriteCollectionsView, SIGNAL(currentChanged(Akonadi::Collection)), this, SLOT(slotFolderChanged(Akonadi::Collection)) ); mFavoritesModel = new Akonadi::FavoriteCollectionsModel( mFolderTreeWidget->folderTreeView()->model(), KMKernel::self()->config()->group( "FavoriteCollections" ), this ); mFavoriteCollectionsView->setModel( mFavoritesModel ); Akonadi::CollectionStatisticsDelegate *delegate = new Akonadi::CollectionStatisticsDelegate( mFavoriteCollectionsView ); delegate->setProgressAnimationEnabled( true ); mFavoriteCollectionsView->setItemDelegate(delegate); delegate->setUnreadCountShown( true ); mAkonadiStandardActionManager->setFavoriteCollectionsModel( mFavoritesModel ); mAkonadiStandardActionManager->setFavoriteSelectionModel( mFavoriteCollectionsView->selectionModel() ); } //Don't use mMailActionManager->createAllActions() to save memory by not //creating actions that doesn't make sense. QList standardActions; standardActions << StandardActionManager::CreateCollection << StandardActionManager::CopyCollections << StandardActionManager::DeleteCollections << StandardActionManager::SynchronizeCollections << StandardActionManager::CollectionProperties << StandardActionManager::CopyItems << StandardActionManager::Paste << StandardActionManager::DeleteItems << StandardActionManager::ManageLocalSubscriptions << StandardActionManager::CopyCollectionToMenu << StandardActionManager::CopyItemToMenu << StandardActionManager::MoveItemToMenu << StandardActionManager::MoveCollectionToMenu << StandardActionManager::CutItems << StandardActionManager::CutCollections << StandardActionManager::CreateResource << StandardActionManager::DeleteResources << StandardActionManager::ResourceProperties << StandardActionManager::SynchronizeResources << StandardActionManager::ToggleWorkOffline << StandardActionManager::SynchronizeCollectionsRecursive; Q_FOREACH( StandardActionManager::Type standardAction, standardActions ) { mAkonadiStandardActionManager->createAction( standardAction ); } if (mEnableFavoriteFolderView) { QList favoriteActions; favoriteActions << StandardActionManager::AddToFavoriteCollections << StandardActionManager::RemoveFromFavoriteCollections << StandardActionManager::RenameFavoriteCollection << StandardActionManager::SynchronizeFavoriteCollections; Q_FOREACH( StandardActionManager::Type favoriteAction, favoriteActions) { mAkonadiStandardActionManager->createAction( favoriteAction ); } } QList mailActions; mailActions << StandardMailActionManager::MarkAllMailAsRead << StandardMailActionManager::MoveToTrash << StandardMailActionManager::MoveAllToTrash << StandardMailActionManager::RemoveDuplicates << StandardMailActionManager::EmptyAllTrash << StandardMailActionManager::MarkMailAsRead << StandardMailActionManager::MarkMailAsUnread << StandardMailActionManager::MarkMailAsImportant << StandardMailActionManager::MarkMailAsActionItem; Q_FOREACH( StandardMailActionManager::Type mailAction, mailActions ) { mAkonadiStandardActionManager->createAction( mailAction ); } mAkonadiStandardActionManager->interceptAction( Akonadi::StandardActionManager::CollectionProperties ); connect( mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::CollectionProperties ), SIGNAL(triggered(bool)), this, SLOT(slotCollectionProperties()) ); // // Create all kinds of actions // mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::RemoveDuplicates )->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_Asterisk ) ); mAkonadiStandardActionManager->interceptAction( Akonadi::StandardMailActionManager::RemoveDuplicates ); connect( mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::RemoveDuplicates ), SIGNAL(triggered(bool)), this, SLOT(slotRemoveDuplicates()) ); { mCollectionProperties = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::CollectionProperties ); } connect( kmkernel->folderCollectionMonitor(), SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection)), SLOT(slotItemAdded(Akonadi::Item,Akonadi::Collection)) ); connect( kmkernel->folderCollectionMonitor(), SIGNAL(itemRemoved(Akonadi::Item)), SLOT(slotItemRemoved(Akonadi::Item)) ); connect( kmkernel->folderCollectionMonitor(), SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection)), SLOT(slotItemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection)) ); connect( kmkernel->folderCollectionMonitor(), SIGNAL(collectionChanged(Akonadi::Collection,QSet)), SLOT(slotCollectionChanged(Akonadi::Collection,QSet)) ); connect( kmkernel->folderCollectionMonitor(), SIGNAL(collectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics)), SLOT(slotCollectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics)) ); } void KMMainWidget::updateMoveAction( const Akonadi::CollectionStatistics& statistic ) { const bool hasUnreadMails = (statistic.unreadCount() > 0); const bool hasMails = (statistic.count()>0); updateMoveAction(hasUnreadMails,hasMails); } void KMMainWidget::updateMoveAction( bool hasUnreadMails, bool hasMails ) { const bool enable_goto_unread = hasUnreadMails || (GlobalSettings::self()->loopOnGotoUnread() == GlobalSettings::EnumLoopOnGotoUnread::LoopInAllFolders) || (GlobalSettings::self()->loopOnGotoUnread() == GlobalSettings::EnumLoopOnGotoUnread::LoopInAllMarkedFolders); actionCollection()->action( QLatin1String("go_next_message") )->setEnabled( hasMails ); actionCollection()->action( QLatin1String("go_next_unread_message") )->setEnabled( enable_goto_unread ); actionCollection()->action( QLatin1String("go_prev_message") )->setEnabled( hasMails ); actionCollection()->action( QLatin1String("go_prev_unread_message") )->setEnabled( enable_goto_unread ); if ( mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::MarkAllMailAsRead ) ) { mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::MarkAllMailAsRead )->setEnabled(hasUnreadMails); } } void KMMainWidget::updateAllToTrashAction(int statistics) { bool multiFolder = false; if ( mFolderTreeWidget ) { multiFolder = mFolderTreeWidget->selectedCollections().count() > 1; } if ( mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::MoveAllToTrash ) ) { const bool folderWithContent = mCurrentFolder && !mCurrentFolder->isStructural(); mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::MoveAllToTrash )->setEnabled( folderWithContent && ( statistics > 0 ) && mCurrentFolder->canDeleteMessages() && !multiFolder ); } } void KMMainWidget::slotCollectionStatisticsChanged( const Akonadi::Collection::Id id, const Akonadi::CollectionStatistics& statistic ) { if ( id == CommonKernel->outboxCollectionFolder().id() ) { const qint64 nbMsgOutboxCollection = statistic.count(); mSendQueued->setEnabled( nbMsgOutboxCollection > 0 ); mSendActionMenu->setEnabled( nbMsgOutboxCollection > 0 ); } else if ( mCurrentFolder && ( id == mCurrentFolder->collection().id() ) ) { updateMoveAction( statistic ); updateAllToTrashAction(statistic.count()); mCurrentFolder->setCollection(MailCommon::Util::updatedCollection( mCurrentFolder->collection() )); } } void KMMainWidget::slotCreateNewTab( bool preferNewTab ) { mMessagePane->setPreferEmptyTab( preferNewTab ); } void KMMainWidget::slotCollectionChanged( const Akonadi::Collection&collection, const QSet&set ) { if ( mCurrentFolder && ( collection == mCurrentFolder->collection() ) && ( set.contains( "MESSAGEFOLDER" ) || set.contains( "expirationcollectionattribute" ) ) ) { if ( set.contains( "MESSAGEFOLDER" ) ) mMessagePane->resetModelStorage(); else { mCurrentFolder->setCollection( collection ); } } else if ( set.contains( "ENTITYDISPLAY" ) || set.contains( "NAME" ) ) { QIcon icon = KIcon( QLatin1String( "folder" ) ); QString text; const QModelIndex idx = Akonadi::EntityTreeModel::modelIndexForCollection( KMKernel::self()->collectionModel(), collection ); if ( idx.isValid() ) { text = idx.data().toString(); icon = idx.data( Qt::DecorationRole ).value(); mMessagePane->updateTabIconText( collection, text,icon ); } } } void KMMainWidget::slotItemAdded( const Akonadi::Item &msg, const Akonadi::Collection &col ) { if ( col.isValid() ) { if ( col == CommonKernel->outboxCollectionFolder() ) { startUpdateMessageActionsTimer(); } } } void KMMainWidget::slotItemRemoved( const Akonadi::Item & item) { if ( item.isValid() && item.parentCollection().isValid() && ( item.parentCollection() == CommonKernel->outboxCollectionFolder() ) ) { startUpdateMessageActionsTimer(); } } void KMMainWidget::slotItemMoved( const Akonadi::Item &item, const Akonadi::Collection &from, const Akonadi::Collection &to ) { if ( item.isValid() && ( ( from.id() == CommonKernel->outboxCollectionFolder().id() ) || to.id() == CommonKernel->outboxCollectionFolder().id() ) ) { startUpdateMessageActionsTimer(); } } //------------------------------------------------------------------------- void KMMainWidget::slotFocusQuickSearch() { mMessagePane->focusQuickSearch(); } //------------------------------------------------------------------------- bool KMMainWidget::slotSearch() { if (!mSearchWin) { mSearchWin = new SearchWindow(this, mCurrentFolder ? mCurrentFolder->collection() : Akonadi::Collection()); mSearchWin->setModal( false ); mSearchWin->setObjectName( QLatin1String("Search") ); } else { mSearchWin->activateFolder(mCurrentFolder ? mCurrentFolder->collection() : Akonadi::Collection()); } mSearchWin->show(); KWindowSystem::activateWindow( mSearchWin->winId() ); return true; } //----------------------------------------------------------------------------- void KMMainWidget::slotHelp() { KToolInvocation::invokeHelp(); } //----------------------------------------------------------------------------- void KMMainWidget::slotFilter() { FilterIf->openFilterDialog( true ); } void KMMainWidget::slotManageSieveScripts() { if ( !kmkernel->askToGoOnline() ) { return; } if (mManageSieveDialog) return; mManageSieveDialog = new KSieveUi::ManageSieveScriptsDialog( this ); connect(mManageSieveDialog, SIGNAL(finished(int)), SLOT(slotCheckVacation())); mManageSieveDialog->show(); } //----------------------------------------------------------------------------- void KMMainWidget::slotAddrBook() { KRun::runCommand(QLatin1String("kaddressbook"), window()); } //----------------------------------------------------------------------------- void KMMainWidget::slotImport() { KRun::runCommand(QLatin1String("kmailcvt"), window()); } //----------------------------------------------------------------------------- void KMMainWidget::slotCheckMail() { kmkernel->checkMail(); } //----------------------------------------------------------------------------- void KMMainWidget::slotCheckMailOnStartup() { kmkernel->checkMailOnStartup(); } //----------------------------------------------------------------------------- void KMMainWidget::slotCheckOneAccount( QAction* item ) { if ( !item ) { return; } Akonadi::AgentInstance agent = Akonadi::AgentManager::self()->instance( item->data().toString() ); if ( agent.isValid() ) { if ( !agent.isOnline() ) { agent.setIsOnline( true ); } agent.synchronize(); } else { kDebug() << "account with identifier" << item->data().toString() << "not found"; } } //----------------------------------------------------------------------------- void KMMainWidget::slotCompose() { KMail::Composer * win; KMime::Message::Ptr msg( new KMime::Message() ); bool forceCursorPosition = false; if ( mCurrentFolder ) { MessageHelper::initHeader( msg, KMKernel::self()->identityManager(), mCurrentFolder->identity() ); //Laurent: bug 289905 /* if ( mCurrentFolder->collection().isValid() && mCurrentFolder->putRepliesInSameFolder() ) { KMime::Headers::Generic *header = new KMime::Headers::Generic( "X-KMail-Fcc", msg.get(), QString::number( mCurrentFolder->collection().id() ), "utf-8" ); msg->setHeader( header ); } */ TemplateParser::TemplateParser parser( msg, TemplateParser::TemplateParser::NewMessage ); parser.setIdentityManager( KMKernel::self()->identityManager() ); parser.process( msg, mCurrentFolder->collection() ); win = KMail::makeComposer( msg, false, false, KMail::Composer::New, mCurrentFolder->identity() ); win->setCollectionForNewMessage( mCurrentFolder->collection() ); forceCursorPosition = parser.cursorPositionWasSet(); } else { MessageHelper::initHeader( msg, KMKernel::self()->identityManager() ); TemplateParser::TemplateParser parser( msg, TemplateParser::TemplateParser::NewMessage ); parser.setIdentityManager( KMKernel::self()->identityManager() ); parser.process( KMime::Message::Ptr(), Akonadi::Collection() ); win = KMail::makeComposer( msg, false, false, KMail::Composer::New ); forceCursorPosition = parser.cursorPositionWasSet(); } if (forceCursorPosition) { win->setFocusToEditor(); } win->show(); } //----------------------------------------------------------------------------- // TODO: do we want the list sorted alphabetically? void KMMainWidget::slotShowNewFromTemplate() { if ( mCurrentFolder ) { const KPIMIdentities::Identity & ident = kmkernel->identityManager()->identityForUoidOrDefault( mCurrentFolder->identity() ); mTemplateFolder = CommonKernel->collectionFromId( ident.templates().toLongLong() ); } if ( !mTemplateFolder.isValid() ) { mTemplateFolder = CommonKernel->templatesCollectionFolder(); } if ( !mTemplateFolder.isValid() ) return; mTemplateMenu->menu()->clear(); Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob( mTemplateFolder ); job->fetchScope().setAncestorRetrieval( ItemFetchScope::Parent ); job->fetchScope().fetchFullPayload(); connect( job, SIGNAL(result(KJob*)), SLOT(slotDelayedShowNewFromTemplate(KJob*)) ); } void KMMainWidget::slotDelayedShowNewFromTemplate( KJob *job ) { Akonadi::ItemFetchJob *fetchJob = qobject_cast( job ); const Akonadi::Item::List items = fetchJob->items(); const int numberOfItems = items.count(); for ( int idx = 0; idx < numberOfItems; ++idx ) { KMime::Message::Ptr msg = MessageCore::Util::message( items.at( idx ) ); if ( msg ) { QString subj = msg->subject()->asUnicodeString(); if ( subj.isEmpty() ) subj = i18n("No Subject"); QAction *templateAction = mTemplateMenu->menu()->addAction(KStringHandler::rsqueeze( subj.replace( QLatin1Char('&'), QLatin1String("&&") ) ) ); QVariant var; var.setValue( items.at( idx ) ); templateAction->setData( var ); } } // If there are no templates available, add a menu entry which informs // the user about this. if ( mTemplateMenu->menu()->actions().isEmpty() ) { QAction *noAction = mTemplateMenu->menu()->addAction( i18n( "(no templates)" ) ); noAction->setEnabled( false ); } } //----------------------------------------------------------------------------- void KMMainWidget::slotNewFromTemplate( QAction *action ) { if ( !mTemplateFolder.isValid() ) return; const Akonadi::Item item = action->data().value(); newFromTemplate( item ); } //----------------------------------------------------------------------------- void KMMainWidget::newFromTemplate( const Akonadi::Item &msg ) { if ( !msg.isValid() ) return; KMCommand *command = new KMUseTemplateCommand( this, msg ); command->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotPostToML() { if ( mCurrentFolder && mCurrentFolder->isMailingListEnabled() ) { if (KMail::Util::mailingListPost( mCurrentFolder )) { return; } } slotCompose(); } //----------------------------------------------------------------------------- void KMMainWidget::slotFolderMailingListProperties() { showCollectionProperties( QLatin1String( "KMail::CollectionMailingListPage" ) ); } //----------------------------------------------------------------------------- void KMMainWidget::slotShowFolderShortcutDialog() { showCollectionProperties( QLatin1String( "KMail::CollectionShortcutPage" ) ); } //----------------------------------------------------------------------------- void KMMainWidget::slotExpireFolder() { if ( !mCurrentFolder ) return; bool mustDeleteExpirationAttribute = false; MailCommon::ExpireCollectionAttribute *attr = MailCommon::ExpireCollectionAttribute::expirationCollectionAttribute( mCurrentFolder->collection(), mustDeleteExpirationAttribute ); ; bool canBeExpired = true; if ( !attr->isAutoExpire() ) { canBeExpired = false; } else if ( attr->unreadExpireUnits() == MailCommon::ExpireCollectionAttribute::ExpireNever && attr->readExpireUnits() == MailCommon::ExpireCollectionAttribute::ExpireNever ) { canBeExpired = false; } if ( !canBeExpired ) { const QString message = i18n( "This folder does not have any expiry options set" ); KMessageBox::information( this, message ); if ( mustDeleteExpirationAttribute ) delete attr; return; } if ( GlobalSettings::self()->warnBeforeExpire() ) { const QString message = i18n( "Are you sure you want to expire the folder %1?", Qt::escape( mCurrentFolder->name() ) ); if ( KMessageBox::warningContinueCancel( this, message, i18n( "Expire Folder" ), KGuiItem( i18n( "&Expire" ) ) ) != KMessageBox::Continue ) { if ( mustDeleteExpirationAttribute ) delete attr; return; } } MailCommon::Util::expireOldMessages( mCurrentFolder->collection(), true /*immediate*/ ); if ( mustDeleteExpirationAttribute ) delete attr; } //----------------------------------------------------------------------------- void KMMainWidget::slotEmptyFolder() { if (!mCurrentFolder) return; const bool isTrash = CommonKernel->folderIsTrash( mCurrentFolder->collection() ); if ( GlobalSettings::self()->confirmBeforeEmpty() ) { const QString title = (isTrash) ? i18n("Empty Trash") : i18n("Move to Trash"); const QString text = (isTrash) ? i18n("Are you sure you want to empty the trash folder?") : i18n("Are you sure you want to move all messages from " "folder %1 to the trash?", Qt::escape( mCurrentFolder->name() ) ); if (KMessageBox::warningContinueCancel(this, text, title, KGuiItem( title, QLatin1String("user-trash"))) != KMessageBox::Continue) return; } #ifndef QT_NO_CURSOR MessageViewer::KCursorSaver busy( MessageViewer::KBusyPtr::busy() ); #endif slotMarkAll(); if (isTrash) { /* Don't ask for confirmation again when deleting, the user has already confirmed. */ slotDeleteMsg( false ); } else slotTrashSelectedMessages(); if (mMsgView) mMsgView->clearCache(); if ( !isTrash ) BroadcastStatus::instance()->setStatusMsg(i18n("Moved all messages to the trash")); updateMessageActions(); // Disable empty trash/move all to trash action - we've just deleted/moved // all folder contents. mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::MoveAllToTrash )->setEnabled( false ); } //----------------------------------------------------------------------------- void KMMainWidget::slotArchiveFolder() { if ( mCurrentFolder && mCurrentFolder->collection().isValid() ) { KMail::ArchiveFolderDialog archiveDialog; archiveDialog.setFolder( mCurrentFolder->collection() ); archiveDialog.exec(); } } //----------------------------------------------------------------------------- void KMMainWidget::slotRemoveFolder() { if ( !mCurrentFolder ) return; if ( !mCurrentFolder->collection().isValid() ) return; if ( mCurrentFolder->isSystemFolder() ) return; if ( mCurrentFolder->isReadOnly() ) return; Akonadi::CollectionFetchJob *job = new Akonadi::CollectionFetchJob( mCurrentFolder->collection(), CollectionFetchJob::FirstLevel, this ); job->fetchScope().setContentMimeTypes( QStringList() << KMime::Message::mimeType() ); job->setProperty( "collectionId", mCurrentFolder->collection().id() ); connect( job, SIGNAL(result(KJob*)), SLOT(slotDelayedRemoveFolder(KJob*)) ); } void KMMainWidget::slotDelayedRemoveFolder( KJob *job ) { const Akonadi::CollectionFetchJob *fetchJob = qobject_cast( job ); Akonadi::Collection::List listOfCollection = fetchJob->collections(); const bool hasNotSubDirectory = listOfCollection.isEmpty(); const Akonadi::Collection::Id id = fetchJob->property( "collectionId" ).toLongLong(); Akonadi::Collection col = MailCommon::Util::updatedCollection(CommonKernel->collectionFromId( id )); QDir dir; QString str; QString title; QString buttonLabel; if ( col.resource() == QLatin1String( "akonadi_search_resource" ) ) { title = i18n("Delete Search"); str = i18n("Are you sure you want to delete the search %1?
" "Any messages it shows will still be available in their original folder.
", Qt::escape( col.name() ) ); buttonLabel = i18nc("@action:button Delete search", "&Delete"); } else { title = i18n("Delete Folder"); if ( col.statistics().count() == 0 ) { if ( hasNotSubDirectory ) { str = i18n("Are you sure you want to delete the empty folder " "%1?", Qt::escape( col.name() ) ); } else { str = i18n("Are you sure you want to delete the empty folder " "%1 and all its subfolders? Those subfolders might " "not be empty and their contents will be discarded as well. " "

Beware that discarded messages are not saved " "into your Trash folder and are permanently deleted.

", Qt::escape( col.name() ) ); } } else { if ( hasNotSubDirectory ) { str = i18n("Are you sure you want to delete the folder " "%1, discarding its contents? " "

Beware that discarded messages are not saved " "into your Trash folder and are permanently deleted.

", Qt::escape( col.name() ) ); }else { str = i18n("Are you sure you want to delete the folder %1 " "and all its subfolders, discarding their contents? " "

Beware that discarded messages are not saved " "into your Trash folder and are permanently deleted.

", Qt::escape( col.name() ) ); } } buttonLabel = i18nc("@action:button Delete folder", "&Delete"); } if ( KMessageBox::warningContinueCancel( this, str, title, KGuiItem( buttonLabel, QLatin1String("edit-delete" )), KStandardGuiItem::cancel(), QString(), KMessageBox::Notify | KMessageBox::Dangerous ) == KMessageBox::Continue ) { kmkernel->checkFolderFromResources( listOfCollection<collection().id()) mCurrentFolder.clear(); Akonadi::CollectionDeleteJob *job = new Akonadi::CollectionDeleteJob( col ); connect( job, SIGNAL(result(KJob*)), this, SLOT(slotDeletionCollectionResult(KJob*)) ); } } void KMMainWidget::slotDeletionCollectionResult(KJob* job) { if ( job ) { if (Util::showJobErrorMessage( job )) { return; } } } //----------------------------------------------------------------------------- void KMMainWidget::slotExpireAll() { if ( GlobalSettings::self()->warnBeforeExpire() ) { const int ret = KMessageBox::warningContinueCancel(KMainWindow::memberList().first(), i18n("Are you sure you want to expire all old messages?"), i18n("Expire Old Messages?"), KGuiItem(i18n("Expire"))); if (ret != KMessageBox::Continue) { return; } } kmkernel->expireAllFoldersNow(); } //----------------------------------------------------------------------------- void KMMainWidget::slotOverrideHtml() { if ( mHtmlPref == mFolderHtmlPref ) { int result = KMessageBox::warningContinueCancel( this, // the warning text is taken from configuredialog.cpp: i18n( "Use of HTML in mail will make you more vulnerable to " "\"spam\" and may increase the likelihood that your system will be " "compromised by other present and anticipated security exploits." ), i18n( "Security Warning" ), KGuiItem(i18n( "Use HTML" )), KStandardGuiItem::cancel(), QLatin1String("OverrideHtmlWarning"), 0); if ( result == KMessageBox::Cancel ) { mPreferHtmlAction->setChecked( false ); return; } } mFolderHtmlPref = !mFolderHtmlPref; //Update mPrefererHtmlLoadExtAction mPreferHtmlLoadExtAction->setEnabled( mCurrentFolder && (mHtmlPref ? !mFolderHtmlPref : mFolderHtmlPref) ? true : false ); if (mMsgView) { mMsgView->setHtmlOverride(mFolderHtmlPref); mMsgView->update( true ); } } //----------------------------------------------------------------------------- void KMMainWidget::slotOverrideHtmlLoadExt() { if ( mHtmlLoadExtPref == mFolderHtmlLoadExtPref ) { int result = KMessageBox::warningContinueCancel( this, // the warning text is taken from configuredialog.cpp: i18n( "Loading external references in html mail will make you more vulnerable to " "\"spam\" and may increase the likelihood that your system will be " "compromised by other present and anticipated security exploits." ), i18n( "Security Warning" ), KGuiItem(i18n( "Load External References" )), KStandardGuiItem::cancel(), QLatin1String("OverrideHtmlLoadExtWarning"), 0); if ( result == KMessageBox::Cancel ) { mPreferHtmlLoadExtAction->setChecked( false ); return; } } mFolderHtmlLoadExtPref = !mFolderHtmlLoadExtPref; if (mMsgView) { mMsgView->setHtmlLoadExtOverride(mFolderHtmlLoadExtPref); mMsgView->update( true ); } } //----------------------------------------------------------------------------- void KMMainWidget::slotMessageQueuedOrDrafted() { if (!CommonKernel->folderIsDraftOrOutbox(mCurrentFolder->collection())) return; if (mMsgView) mMsgView->update(true); } //----------------------------------------------------------------------------- void KMMainWidget::slotForwardInlineMsg() { if ( !mCurrentFolder ) { return; } const QList selectedMessages = mMessagePane->selectionAsMessageItemList(); if ( selectedMessages.isEmpty() ) return; KMForwardCommand * command = new KMForwardCommand( this, selectedMessages, mCurrentFolder->identity() ); command->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotForwardAttachedMsg() { if ( !mCurrentFolder ) { return; } const QList selectedMessages = mMessagePane->selectionAsMessageItemList(); if ( selectedMessages.isEmpty() ) return; KMForwardAttachedCommand * command = new KMForwardAttachedCommand( this, selectedMessages, mCurrentFolder->identity() ); command->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotUseTemplate() { newFromTemplate( mMessagePane->currentItem() ); } //----------------------------------------------------------------------------- void KMMainWidget::slotResendMsg() { const Akonadi::Item msg = mMessagePane->currentItem(); if ( !msg.isValid() ) return; KMCommand *command = new KMResendMessageCommand( this, msg ); command->start(); } //----------------------------------------------------------------------------- // Message moving and permanent deletion // void KMMainWidget::moveMessageSelected( MessageList::Core::MessageItemSetReference ref, const Akonadi::Collection &dest, bool confirmOnDeletion ) { QList selectMsg = mMessagePane->itemListFromPersistentSet( ref ); // If this is a deletion, ask for confirmation if ( !dest.isValid() && confirmOnDeletion ) { int ret = KMessageBox::warningContinueCancel( this, i18np( "Do you really want to delete the selected message?
" "Once deleted, it cannot be restored.
", "Do you really want to delete the %1 selected messages?
" "Once deleted, they cannot be restored.
", selectMsg.count() ), selectMsg.count() > 1 ? i18n( "Delete Messages" ) : i18n( "Delete Message" ), KStandardGuiItem::del(), KStandardGuiItem::cancel(), QLatin1String("NoConfirmDelete") ); if ( ret == KMessageBox::Cancel ) { mMessagePane->deletePersistentSet( ref ); return; // user canceled the action } } mMessagePane->markMessageItemsAsAboutToBeRemoved( ref, true ); // And stuff them into a KMMoveCommand :) KMMoveCommand *command = new KMMoveCommand( dest, selectMsg,ref ); QObject::connect( command, SIGNAL(moveDone(KMMoveCommand*)), this, SLOT(slotMoveMessagesCompleted(KMMoveCommand*)) ); command->start(); if ( dest.isValid() ) BroadcastStatus::instance()->setStatusMsg( i18n( "Moving messages..." ) ); else BroadcastStatus::instance()->setStatusMsg( i18n( "Deleting messages..." ) ); } void KMMainWidget::slotMoveMessagesCompleted( KMMoveCommand *command ) { Q_ASSERT( command ); mMessagePane->markMessageItemsAsAboutToBeRemoved( command->refSet(), false ); mMessagePane->deletePersistentSet( command->refSet() ); // Bleah :D const bool moveWasReallyADelete = !command->destFolder().isValid(); if ( command->result() == KMCommand::OK ) { if ( moveWasReallyADelete ) BroadcastStatus::instance()->setStatusMsg( i18n( "Messages deleted successfully." ) ); else BroadcastStatus::instance()->setStatusMsg( i18n( "Messages moved successfully." ) ); } else { if ( moveWasReallyADelete ) { if ( command->result() == KMCommand::Failed ) BroadcastStatus::instance()->setStatusMsg( i18n( "Deleting messages failed." ) ); else BroadcastStatus::instance()->setStatusMsg( i18n( "Deleting messages canceled." ) ); } else { if ( command->result() == KMCommand::Failed ) BroadcastStatus::instance()->setStatusMsg( i18n( "Moving messages failed." ) ); else BroadcastStatus::instance()->setStatusMsg( i18n( "Moving messages canceled." ) ); } } // The command will autodelete itself and will also kill the set. } void KMMainWidget::slotDeleteMsg( bool confirmDelete ) { // Create a persistent message set from the current selection MessageList::Core::MessageItemSetReference ref = mMessagePane->selectionAsPersistentSet(); if ( ref != -1 ) moveMessageSelected( ref, Akonadi::Collection(), confirmDelete ); } void KMMainWidget::slotDeleteThread( bool confirmDelete ) { // Create a persistent set from the current thread. MessageList::Core::MessageItemSetReference ref = mMessagePane->currentThreadAsPersistentSet(); if ( ref != -1 ) moveMessageSelected( ref, Akonadi::Collection(), confirmDelete ); } FolderSelectionDialog* KMMainWidget::moveOrCopyToDialog() { if ( !mMoveOrCopyToDialog ) { FolderSelectionDialog::SelectionFolderOption options = FolderSelectionDialog::HideVirtualFolder; mMoveOrCopyToDialog = new FolderSelectionDialog( this, options ); mMoveOrCopyToDialog->setModal( true ); } return mMoveOrCopyToDialog; } FolderSelectionDialog* KMMainWidget::selectFromAllFoldersDialog() { if ( !mSelectFromAllFoldersDialog ) { FolderSelectionDialog::SelectionFolderOptions options = FolderSelectionDialog::None; options |= FolderSelectionDialog::NotAllowToCreateNewFolder; mSelectFromAllFoldersDialog = new FolderSelectionDialog( this, options ); mSelectFromAllFoldersDialog->setModal( true ); } return mSelectFromAllFoldersDialog; } void KMMainWidget::slotMoveSelectedMessageToFolder() { QPointer dialog( moveOrCopyToDialog() ); dialog->setCaption( i18n( "Move Messages to Folder" ) ); if ( dialog->exec() && dialog ) { const Akonadi::Collection dest = dialog->selectedCollection(); if ( dest.isValid() ) { moveSelectedMessagesToFolder( dest ); } } } void KMMainWidget::moveSelectedMessagesToFolder( const Akonadi::Collection & dest ) { MessageList::Core::MessageItemSetReference ref = mMessagePane->selectionAsPersistentSet(); if ( ref != -1 ) { //Need to verify if dest == src ??? akonadi do it for us. moveMessageSelected( ref, dest, false ); } } void KMMainWidget::copyMessageSelected( const QList &selectMsg, const Akonadi::Collection &dest ) { if ( selectMsg.isEmpty() ) return; // And stuff them into a KMCopyCommand :) KMCommand *command = new KMCopyCommand( dest, selectMsg ); QObject::connect( command, SIGNAL(completed(KMCommand*)), this, SLOT(slotCopyMessagesCompleted(KMCommand*)) ); command->start(); BroadcastStatus::instance()->setStatusMsg( i18n( "Copying messages..." ) ); } void KMMainWidget::slotCopyMessagesCompleted( KMCommand *command ) { Q_ASSERT( command ); if ( command->result() == KMCommand::OK ) { BroadcastStatus::instance()->setStatusMsg( i18n( "Messages copied successfully." ) ); } else { if ( command->result() == KMCommand::Failed ) BroadcastStatus::instance()->setStatusMsg( i18n( "Copying messages failed." ) ); else BroadcastStatus::instance()->setStatusMsg( i18n( "Copying messages canceled." ) ); } // The command will autodelete itself and will also kill the set. } void KMMainWidget::slotCopySelectedMessagesToFolder() { QPointer dialog( moveOrCopyToDialog() ); dialog->setCaption( i18n( "Copy Messages to Folder" ) ); if ( dialog->exec() && dialog ) { const Akonadi::Collection dest = dialog->selectedCollection(); if ( dest.isValid() ) { copySelectedMessagesToFolder( dest ); } } } void KMMainWidget::copySelectedMessagesToFolder( const Akonadi::Collection& dest ) { const QList lstMsg = mMessagePane->selectionAsMessageItemList(); if ( !lstMsg.isEmpty() ) { copyMessageSelected( lstMsg, dest ); } } //----------------------------------------------------------------------------- // Message trashing // void KMMainWidget::trashMessageSelected( MessageList::Core::MessageItemSetReference ref ) { if ( !mCurrentFolder ) { return; } const QList select = mMessagePane->itemListFromPersistentSet( ref ); mMessagePane->markMessageItemsAsAboutToBeRemoved( ref, true ); // FIXME: Why we don't use KMMoveCommand( trashFolder(), selectedMessages ); ? // And stuff them into a KMTrashMsgCommand :) KMCommand *command = new KMTrashMsgCommand( mCurrentFolder->collection(), select,ref ); QObject::connect( command, SIGNAL(moveDone(KMMoveCommand*)), this, SLOT(slotTrashMessagesCompleted(KMMoveCommand*)) ); command->start(); BroadcastStatus::instance()->setStatusMsg( i18n( "Moving messages to trash..." ) ); } void KMMainWidget::slotTrashMessagesCompleted( KMMoveCommand *command ) { Q_ASSERT( command ); mMessagePane->markMessageItemsAsAboutToBeRemoved( command->refSet(), false ); mMessagePane->deletePersistentSet( command->refSet() ); if ( command->result() == KMCommand::OK ) { BroadcastStatus::instance()->setStatusMsg( i18n( "Messages moved to trash successfully." ) ); } else { if ( command->result() == KMCommand::Failed ) { BroadcastStatus::instance()->setStatusMsg( i18n( "Moving messages to trash failed." ) ); } else BroadcastStatus::instance()->setStatusMsg( i18n( "Moving messages to trash canceled." ) ); } // The command will autodelete itself and will also kill the set. } void KMMainWidget::slotTrashSelectedMessages() { MessageList::Core::MessageItemSetReference ref = mMessagePane->selectionAsPersistentSet(); if ( ref != -1 ) { trashMessageSelected( ref ); } } void KMMainWidget::slotTrashThread() { MessageList::Core::MessageItemSetReference ref = mMessagePane->currentThreadAsPersistentSet(); if ( ref != -1 ) trashMessageSelected( ref ); } //----------------------------------------------------------------------------- // Message tag setting for messages // // FIXME: The "selection" version of these functions is in MessageActions. // We should probably move everything there.... void KMMainWidget::toggleMessageSetTag( const QList &select, const Akonadi::Tag &tag ) { if ( select.isEmpty() ) return; KMCommand *command = new KMSetTagCommand( Akonadi::Tag::List() << tag, select, KMSetTagCommand::Toggle ); command->start(); } void KMMainWidget::slotSelectMoreMessageTagList() { const QList selectedMessages = mMessagePane->selectionAsMessageItemList(); if ( selectedMessages.isEmpty() ) return; TagSelectionDialog dlg(this); if (selectedMessages.count() == 1) { dlg.setSelection(selectedMessages.first().tags()); } if ( dlg.exec() ) { const Akonadi::Tag::List lst = dlg.selection(); KMCommand *command = new KMSetTagCommand( lst, selectedMessages, KMSetTagCommand::CleanExistingAndAddNew ); command->start(); } } void KMMainWidget::slotUpdateMessageTagList( const Akonadi::Tag &tag ) { // Create a persistent set from the current thread. const QList selectedMessages = mMessagePane->selectionAsMessageItemList(); if ( selectedMessages.isEmpty() ) return; toggleMessageSetTag( selectedMessages, tag ); } void KMMainWidget::refreshMessageListSelection() { mAkonadiStandardActionManager->setItemSelectionModel( mMessagePane->currentItemSelectionModel() ); slotMessageSelected(mMessagePane->currentItem()); } //----------------------------------------------------------------------------- // Status setting for threads // // FIXME: The "selection" version of these functions is in MessageActions. // We should probably move everything there.... void KMMainWidget::setMessageSetStatus( const QList &select, const Akonadi::MessageStatus &status, bool toggle ) { KMCommand *command = new KMSetStatusCommand( status, select, toggle ); command->start(); } void KMMainWidget::setCurrentThreadStatus( const Akonadi::MessageStatus &status, bool toggle ) { const QList select = mMessagePane->currentThreadAsMessageList(); if ( select.isEmpty() ) return; setMessageSetStatus( select, status, toggle ); } void KMMainWidget::slotSetThreadStatusUnread() { setCurrentThreadStatus( MessageStatus::statusRead(), true ); } void KMMainWidget::slotSetThreadStatusImportant() { setCurrentThreadStatus( MessageStatus::statusImportant(), true ); } void KMMainWidget::slotSetThreadStatusRead() { setCurrentThreadStatus( MessageStatus::statusRead(), false ); } void KMMainWidget::slotSetThreadStatusToAct() { setCurrentThreadStatus( MessageStatus::statusToAct(), true ); } void KMMainWidget::slotSetThreadStatusWatched() { setCurrentThreadStatus( MessageStatus::statusWatched(), true ); if ( mWatchThreadAction->isChecked() ) mIgnoreThreadAction->setChecked(false); } void KMMainWidget::slotSetThreadStatusIgnored() { setCurrentThreadStatus( MessageStatus::statusIgnored(), true ); if ( mIgnoreThreadAction->isChecked() ) mWatchThreadAction->setChecked(false); } //----------------------------------------------------------------------------- void KMMainWidget::slotRedirectMsg() { const QList selectedMessages = mMessagePane->selectionAsMessageItemList(); if ( selectedMessages.isEmpty() ) return; KMCommand *command = new KMRedirectCommand( this, selectedMessages ); command->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotCustomReplyToMsg( const QString &tmpl ) { const Akonadi::Item msg = mMessagePane->currentItem(); if ( !msg.isValid() ) return; const QString text = mMsgView ? mMsgView->copyText() : QString(); kDebug() << "Reply with template:" << tmpl; KMCommand *command = new KMReplyCommand( this, msg, MessageComposer::ReplySmart, text, false, tmpl ); command->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotCustomReplyAllToMsg( const QString &tmpl ) { const Akonadi::Item msg = mMessagePane->currentItem(); if ( !msg.isValid() ) return; const QString text = mMsgView? mMsgView->copyText() : QString(); kDebug() << "Reply to All with template:" << tmpl; KMCommand *command = new KMReplyCommand(this, msg, MessageComposer::ReplyAll, text, false, tmpl ); command->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotCustomForwardMsg( const QString &tmpl ) { if ( !mCurrentFolder ) { return; } const QList selectedMessages = mMessagePane->selectionAsMessageItemList(); if ( selectedMessages.isEmpty() ) return; kDebug() << "Forward with template:" << tmpl; KMForwardCommand * command = new KMForwardCommand( this, selectedMessages, mCurrentFolder->identity(), tmpl ); command->start(); } void KMMainWidget::openFilterDialog(const QByteArray &field, const QString &value) { FilterIf->openFilterDialog( false ); FilterIf->createFilter( field, value ); } //----------------------------------------------------------------------------- void KMMainWidget::slotSubjectFilter() { const KMime::Message::Ptr msg = mMessagePane->currentMessage(); if ( !msg ) return; openFilterDialog("Subject", msg->subject()->asUnicodeString()); } //----------------------------------------------------------------------------- void KMMainWidget::slotFromFilter() { KMime::Message::Ptr msg = mMessagePane->currentMessage(); if ( !msg ) return; AddrSpecList al = MessageHelper::extractAddrSpecs( msg, "From" ); if ( al.empty() ) openFilterDialog("From", msg->from()->asUnicodeString()); else openFilterDialog("From", al.front().asString()); } //----------------------------------------------------------------------------- void KMMainWidget::slotToFilter() { KMime::Message::Ptr msg = mMessagePane->currentMessage(); if ( !msg ) return; openFilterDialog("To", msg->to()->asUnicodeString()); } //----------------------------------------------------------------------------- void KMMainWidget::slotUndo() { kmkernel->undoStack()->undo(); updateMessageActions(); updateFolderMenu(); } //----------------------------------------------------------------------------- void KMMainWidget::slotJumpToFolder() { QPointer dialog( selectFromAllFoldersDialog() ); dialog->setCaption( i18n( "Jump to Folder") ); if ( dialog->exec() && dialog ) { Akonadi::Collection collection = dialog->selectedCollection(); if ( collection.isValid() ) { slotSelectCollectionFolder( collection ); } } } void KMMainWidget::slotSelectCollectionFolder( const Akonadi::Collection & col ) { if ( mFolderTreeWidget ) { mFolderTreeWidget->selectCollectionFolder( col ); slotFolderChanged( col ); } } void KMMainWidget::slotApplyFilters() { const QList selectedMessages = mMessagePane->selectionAsMessageItemList(); if ( selectedMessages.isEmpty() ) return; applyFilters( selectedMessages ); } void KMMainWidget::slotApplyFiltersOnFolder() { if ( mCurrentFolder && mCurrentFolder->collection().isValid() ) { Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob( mCurrentFolder->collection(), this ); connect( job, SIGNAL(result(KJob*)), this, SLOT(slotFetchItemsForFolderDone(KJob*)) ); } } void KMMainWidget::slotFetchItemsForFolderDone(KJob*job) { Akonadi::ItemFetchJob *fjob = dynamic_cast( job ); Q_ASSERT( fjob ); Akonadi::Item::List items = fjob->items(); applyFilters( items ); } void KMMainWidget::applyFilters( const QList& selectedMessages ) { #ifndef QT_NO_CURSOR MessageViewer::KCursorSaver busy( MessageViewer::KBusyPtr::busy() ); #endif MailCommon::FilterManager::instance()->filter( selectedMessages ); } //----------------------------------------------------------------------------- void KMMainWidget::slotCheckVacation() { updateVacationScriptStatus( false ); if ( !kmkernel->askToGoOnline() ) return; mVacationManager->checkVacation(); connect(mVacationManager, SIGNAL(updateVacationScriptStatus(bool,QString)), SLOT(updateVacationScriptStatus(bool,QString)) ); connect(mVacationManager, SIGNAL(editVacation()), SLOT(slotEditVacation()) ); } void KMMainWidget::slotEditVacation(const QString &serverName) { if ( !kmkernel->askToGoOnline() ) { return; } mVacationManager->slotEditVacation(serverName); } //----------------------------------------------------------------------------- void KMMainWidget::slotDebugSieve() { #if !defined(NDEBUG) if ( mSieveDebugDialog ) return; mSieveDebugDialog = new KSieveUi::SieveDebugDialog( this ); mSieveDebugDialog->exec(); delete mSieveDebugDialog; #endif } //----------------------------------------------------------------------------- void KMMainWidget::slotStartCertManager() { if ( !QProcess::startDetached(QLatin1String("kleopatra") ) ) KMessageBox::error( this, i18n( "Could not start certificate manager; " "please check your installation." ), i18n( "KMail Error" ) ); else kDebug() << "\nslotStartCertManager(): certificate manager started."; } //----------------------------------------------------------------------------- void KMMainWidget::slotStartWatchGnuPG() { if ( !QProcess::startDetached(QLatin1String("kwatchgnupg")) ) KMessageBox::error( this, i18n( "Could not start GnuPG LogViewer (kwatchgnupg); " "please check your installation." ), i18n( "KMail Error" ) ); } //----------------------------------------------------------------------------- void KMMainWidget::slotConfigChanged() { readConfig(); mMsgActions->setupForwardActions(); mMsgActions->setupForwardingActionsList( mGUIClient ); } //----------------------------------------------------------------------------- void KMMainWidget::slotSaveMsg() { const QList selectedMessages = mMessagePane->selectionAsMessageItemList(); if ( selectedMessages.isEmpty() ) return; KMSaveMsgCommand *saveCommand = new KMSaveMsgCommand( this, selectedMessages ); saveCommand->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotOpenMsg() { KMOpenMsgCommand *openCommand = new KMOpenMsgCommand( this, KUrl(), overrideEncoding(), this ); openCommand->start(); } //----------------------------------------------------------------------------- void KMMainWidget::slotSaveAttachments() { const QList selectedMessages = mMessagePane->selectionAsMessageItemList(); if ( selectedMessages.isEmpty() ) return; // Avoid re-downloading in the common case that only one message is selected, and the message // is also displayed in the viewer. For this, create a dummy item without a parent collection / item id, // so that KMCommand doesn't download it. KMSaveAttachmentsCommand *saveCommand = 0; if ( mMsgView && selectedMessages.size() == 1 && mMsgView->message().hasPayload() && selectedMessages.first().id() == mMsgView->message().id() ) { Akonadi::Item dummyItem; dummyItem.setPayload( mMsgView->message().payload() ); saveCommand = new KMSaveAttachmentsCommand( this, dummyItem ); } else { saveCommand = new KMSaveAttachmentsCommand( this, selectedMessages ); } saveCommand->start(); } void KMMainWidget::slotOnlineStatus() { // KMKernel will emit a signal when we toggle the network state that is caught by // KMMainWidget::slotUpdateOnlineStatus to update our GUI if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Online ) { // if online; then toggle and set it offline. kmkernel->stopNetworkJobs(); } else { kmkernel->resumeNetworkJobs(); slotCheckVacation(); } } void KMMainWidget::slotUpdateOnlineStatus( GlobalSettings::EnumNetworkState::type ) { if ( !mAkonadiStandardActionManager ) { return; } KAction * action = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::ToggleWorkOffline ); if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Online ) { action->setText( i18n("Work Offline") ); action->setIcon( KIcon(QLatin1String("user-offline")) ); } else { action->setText( i18n("Work Online") ); action->setIcon( KIcon(QLatin1String("user-online")) ); } } //----------------------------------------------------------------------------- void KMMainWidget::slotSendQueued() { if ( kmkernel->msgSender() ) { kmkernel->msgSender()->sendQueued(); } } //----------------------------------------------------------------------------- void KMMainWidget::slotSendQueuedVia( QAction *item ) { const QStringList availTransports = MailTransport::TransportManager::self()->transportNames(); if ( !availTransports.isEmpty() && availTransports.contains( item->text() ) ) { if ( kmkernel->msgSender() ) { kmkernel->msgSender()->sendQueued( item->text() ); } } } //----------------------------------------------------------------------------- void KMMainWidget::slotShowBusySplash() { if ( mReaderWindowActive ) { mMsgView->displayBusyPage(); } } void KMMainWidget::showOfflinePage() { if ( !mReaderWindowActive ) return; mMsgView->displayOfflinePage(); } void KMMainWidget::showResourceOfflinePage() { if ( !mReaderWindowActive ) return; mMsgView->displayResourceOfflinePage(); } //----------------------------------------------------------------------------- void KMMainWidget::slotReplaceMsgByUnencryptedVersion() { kDebug(); Akonadi::Item oldMsg = mMessagePane->currentItem(); if ( oldMsg.isValid() ) { #if 0 kDebug() << "Old message found"; if ( oldMsg->hasUnencryptedMsg() ) { kDebug() << "Extra unencrypted message found"; KMime::Message* newMsg = oldMsg->unencryptedMsg(); // adjust the message id { QString msgId( oldMsg->msgId() ); QString prefix("DecryptedMsg."); int oldIdx = msgId.indexOf(prefix, 0, Qt::CaseInsensitive); if ( -1 == oldIdx ) { int leftAngle = msgId.lastIndexOf( '<' ); msgId = msgId.insert( (-1 == leftAngle) ? 0 : ++leftAngle, prefix ); } else { // toggle between "DecryptedMsg." and "DeCryptedMsg." // to avoid same message id QCharRef c = msgId[ oldIdx+2 ]; if ( 'C' == c ) c = 'c'; else c = 'C'; } newMsg->setMsgId( msgId ); mMsgView->setIdOfLastViewedMessage( msgId ); } // insert the unencrypted message kDebug() << "Adding unencrypted message to folder"; mFolder->addMsg( newMsg ); /* Figure out its index in the folder for selecting. This must be count()-1, * since we append. Be safe and do find, though, just in case. */ int newMsgIdx = mFolder->find( newMsg ); Q_ASSERT( newMsgIdx != -1 ); /* we need this unget, to have the message displayed correctly initially */ mFolder->unGetMsg( newMsgIdx ); int idx = mFolder->find( oldMsg ); Q_ASSERT( idx != -1 ); /* only select here, so the old one is not un-Gotten before, which would * render the pointer we hold invalid so that find would fail */ #if 0 // FIXME (Pragma) mHeaders->setCurrentItemByIndex( newMsgIdx ); #endif // remove the old one if ( idx != -1 ) { kDebug() << "Deleting encrypted message"; mFolder->take( idx ); } kDebug() << "Updating message actions"; updateMessageActions(); kDebug() << "Done."; } else kDebug() << "NO EXTRA UNENCRYPTED MESSAGE FOUND"; #else kDebug() << "AKONADI PORT: Disabled code in " << Q_FUNC_INFO; #endif } else kDebug() << "PANIC: NO OLD MESSAGE FOUND"; } void KMMainWidget::slotFocusOnNextMessage() { mMessagePane->focusNextMessageItem(MessageList::Core::MessageTypeAny, true,false ); } void KMMainWidget::slotFocusOnPrevMessage() { mMessagePane->focusPreviousMessageItem( MessageList::Core::MessageTypeAny, true, false ); } void KMMainWidget::slotSelectFirstMessage() { mMessagePane->selectFirstMessageItem( MessageList::Core::MessageTypeAny, true ); } void KMMainWidget::slotSelectLastMessage() { mMessagePane->selectLastMessageItem( MessageList::Core::MessageTypeAny, true ); } void KMMainWidget::slotSelectFocusedMessage() { mMessagePane->selectFocusedMessageItem(true ); } void KMMainWidget::slotSelectNextMessage() { mMessagePane->selectNextMessageItem( MessageList::Core::MessageTypeAny, MessageList::Core::ClearExistingSelection, true, false ); } void KMMainWidget::slotExtendSelectionToNextMessage() { mMessagePane->selectNextMessageItem( MessageList::Core::MessageTypeAny, MessageList::Core::GrowOrShrinkExistingSelection, true, // center item false // don't loop in folder ); } void KMMainWidget::slotSelectNextUnreadMessage() { // The looping logic is: "Don't loop" just never loops, "Loop in current folder" // loops just in current folder, "Loop in all folders" loops in the current folder // first and then after confirmation jumps to the next folder. // A bad point here is that if you answer "No, and don't ask me again" to the confirmation // dialog then you have "Loop in current folder" and "Loop in all folders" that do // the same thing and no way to get the old behaviour. However, after a consultation on #kontact, // for bug-to-bug backward compatibility, the masters decided to keep it b0rken :D // If nobody complains, it stays like it is: if you complain enough maybe the masters will // decide to reconsider :) if ( !mMessagePane->selectNextMessageItem( MessageList::Core::MessageTypeUnreadOnly, MessageList::Core::ClearExistingSelection, true, // center item /*GlobalSettings::self()->loopOnGotoUnread() == GlobalSettings::EnumLoopOnGotoUnread::LoopInCurrentFolder*/ GlobalSettings::self()->loopOnGotoUnread() != GlobalSettings::EnumLoopOnGotoUnread::DontLoop ) ) { // no next unread message was found in the current folder if ( ( GlobalSettings::self()->loopOnGotoUnread() == GlobalSettings::EnumLoopOnGotoUnread::LoopInAllFolders ) || ( GlobalSettings::self()->loopOnGotoUnread() == GlobalSettings::EnumLoopOnGotoUnread::LoopInAllMarkedFolders ) ) { mGoToFirstUnreadMessageInSelectedFolder = true; mFolderTreeWidget->folderTreeView()->selectNextUnreadFolder( true ); mGoToFirstUnreadMessageInSelectedFolder = false; } } } void KMMainWidget::slotSelectPreviousMessage() { mMessagePane->selectPreviousMessageItem( MessageList::Core::MessageTypeAny, MessageList::Core::ClearExistingSelection, true, false ); } void KMMainWidget::slotExtendSelectionToPreviousMessage() { mMessagePane->selectPreviousMessageItem( MessageList::Core::MessageTypeAny, MessageList::Core::GrowOrShrinkExistingSelection, true, // center item false // don't loop in folder ); } void KMMainWidget::slotSelectPreviousUnreadMessage() { if ( !mMessagePane->selectPreviousMessageItem( MessageList::Core::MessageTypeUnreadOnly, MessageList::Core::ClearExistingSelection, true, // center item GlobalSettings::self()->loopOnGotoUnread() == GlobalSettings::EnumLoopOnGotoUnread::LoopInCurrentFolder ) ) { // no next unread message was found in the current folder if ( ( GlobalSettings::self()->loopOnGotoUnread() == GlobalSettings::EnumLoopOnGotoUnread::LoopInAllFolders ) || ( GlobalSettings::self()->loopOnGotoUnread() == GlobalSettings::EnumLoopOnGotoUnread::LoopInAllMarkedFolders ) ) { mGoToFirstUnreadMessageInSelectedFolder = true; mFolderTreeWidget->folderTreeView()->selectPrevUnreadFolder(); mGoToFirstUnreadMessageInSelectedFolder = false; } } } void KMMainWidget::slotDisplayCurrentMessage() { if ( mMessagePane->currentItem().isValid() && !mMessagePane->searchEditHasFocus() ) slotMessageActivated( mMessagePane->currentItem() ); } // Called by double-clicked or 'Enter' in the messagelist -> pop up reader window void KMMainWidget::slotMessageActivated( const Akonadi::Item &msg ) { if ( !mCurrentFolder || !msg.isValid() ) return; if ( CommonKernel->folderIsDraftOrOutbox( mCurrentFolder->collection() ) ) { mMsgActions->setCurrentMessage( msg ); mMsgActions->editCurrentMessage(); return; } if ( CommonKernel->folderIsTemplates( mCurrentFolder->collection() ) ) { slotUseTemplate(); return; } // Try to fetch the mail, even in offline mode, it might be cached ItemFetchJob *itemFetchJob = MessageViewer::Viewer::createFetchJob( msg ); connect( itemFetchJob, SIGNAL(itemsReceived(Akonadi::Item::List)), SLOT(slotItemsFetchedForActivation(Akonadi::Item::List)) ); connect( itemFetchJob, SIGNAL(result(KJob*)), SLOT(itemsFetchForActivationDone(KJob*)) ); } void KMMainWidget::slotItemsFetchedForActivation( const Akonadi::Item::List &list ) { Q_ASSERT( list.size() == 1 ); const Item msg = list.first(); KMReaderMainWin *win = new KMReaderMainWin( mFolderHtmlPref, mFolderHtmlLoadExtPref ); const bool useFixedFont = mMsgView ? mMsgView->isFixedFont() : MessageViewer::GlobalSettings::self()->useFixedFont(); win->setUseFixedFont( useFixedFont ); const Akonadi::Collection parentCollection = MailCommon::Util::parentCollectionFromItem(msg); win->showMessage( overrideEncoding(), msg, parentCollection ); win->show(); } void KMMainWidget::itemsFetchForActivationDone( KJob * job ) { if ( job->error() ) { kDebug() << job->error() << job->errorString(); BroadcastStatus::instance()->setStatusMsg( job->errorString() ); } } void KMMainWidget::slotMessageStatusChangeRequest( const Akonadi::Item &item, const Akonadi::MessageStatus & set, const Akonadi::MessageStatus &clear ) { if ( !item.isValid() ) return; if ( clear.toQInt32() != Akonadi::MessageStatus().toQInt32() ) { KMCommand *command = new KMSetStatusCommand( clear, Akonadi::Item::List() << item, true ); command->start(); } if ( set.toQInt32() != Akonadi::MessageStatus().toQInt32() ) { KMCommand *command = new KMSetStatusCommand( set, Akonadi::Item::List() << item, false ); command->start(); } } //----------------------------------------------------------------------------- void KMMainWidget::slotMarkAll() { mMessagePane->selectAll(); updateMessageActions(); } void KMMainWidget::slotMessagePopup(const Akonadi::Item&msg ,const KUrl&aUrl,const KUrl &imageUrl,const QPoint& aPoint) { updateMessageMenu(); const QString email = KPIMUtils::firstEmailAddress( aUrl.path() ).toLower(); if ( aUrl.protocol() == QLatin1String("mailto") && !email.isEmpty()) { Akonadi::ContactSearchJob *job = new Akonadi::ContactSearchJob( this ); job->setLimit( 1 ); job->setQuery( Akonadi::ContactSearchJob::Email, email, Akonadi::ContactSearchJob::ExactMatch ); job->setProperty( "msg", QVariant::fromValue( msg ) ); job->setProperty( "point", aPoint ); job->setProperty( "imageUrl", imageUrl ); job->setProperty( "url", aUrl ); connect( job, SIGNAL(result(KJob*)), SLOT(slotContactSearchJobForMessagePopupDone(KJob*)) ); } else { showMessagePopup(msg, aUrl, imageUrl, aPoint, false, false); } } void KMMainWidget::slotContactSearchJobForMessagePopupDone( KJob *job ) { const Akonadi::ContactSearchJob *searchJob = qobject_cast( job ); const bool contactAlreadyExists = !searchJob->contacts().isEmpty(); const QList listContact = searchJob->items(); const bool uniqueContactFound = (listContact.count() == 1); if (uniqueContactFound) { mMsgView->setContactItem(listContact.first(), searchJob->contacts().at(0)); } else { mMsgView->clearContactItem(); } const Akonadi::Item msg = job->property( "msg" ).value(); const QPoint aPoint = job->property( "point" ).toPoint(); const KUrl imageUrl = job->property("imageUrl").value(); const KUrl url = job->property( "url" ).value(); showMessagePopup(msg, url, imageUrl, aPoint, contactAlreadyExists, uniqueContactFound); } void KMMainWidget::showMessagePopup(const Akonadi::Item&msg ,const KUrl&url,const KUrl &imageUrl,const QPoint& aPoint, bool contactAlreadyExists, bool uniqueContactFound) { KMenu *menu = new KMenu; bool urlMenuAdded = false; if ( !url.isEmpty() ) { if ( url.protocol() == QLatin1String( "mailto" ) ) { // popup on a mailto URL menu->addAction( mMsgView->mailToComposeAction() ); menu->addAction( mMsgView->mailToReplyAction() ); menu->addAction( mMsgView->mailToForwardAction() ); menu->addSeparator(); if ( contactAlreadyExists ) { if (uniqueContactFound) { menu->addAction( mMsgView->editContactAction() ); } else { menu->addAction( mMsgView->openAddrBookAction() ); } } else { menu->addAction( mMsgView->addAddrBookAction() ); menu->addAction( mMsgView->addToExistingContactAction() ); } menu->addSeparator(); menu->addMenu(mMsgView->viewHtmlOption()); menu->addSeparator(); menu->addAction( mMsgView->copyURLAction() ); urlMenuAdded = true; } else if ( url.protocol() != QLatin1String( "attachment" ) ) { // popup on a not-mailto URL menu->addAction( mMsgView->urlOpenAction() ); menu->addAction( mMsgView->addBookmarksAction() ); menu->addAction( mMsgView->urlSaveAsAction() ); menu->addAction( mMsgView->copyURLAction() ); if (mMsgView->isAShortUrl(url)) { menu->addSeparator(); menu->addAction( mMsgView->expandShortUrlAction() ); } if (!imageUrl.isEmpty()) { menu->addSeparator(); menu->addAction( mMsgView->copyImageLocation()); menu->addAction( mMsgView->downloadImageToDiskAction()); menu->addAction( mMsgView->shareImage()); if (mMsgView->adblockEnabled()) { menu->addSeparator(); menu->addAction( mMsgView->blockImage()); } } urlMenuAdded = true; } kDebug() << "URL is:" << url; } const QString selectedText = mMsgView ? mMsgView->copyText() : QString(); if ( mMsgView && !selectedText.isEmpty() ) { if ( urlMenuAdded ) { menu->addSeparator(); } menu->addAction( mMsgActions->replyMenu() ); menu->addSeparator(); menu->addAction( mMsgView->copyAction() ); menu->addAction( mMsgView->selectAllAction() ); menu->addSeparator(); mMsgActions->addWebShortcutsMenu(menu,selectedText); menu->addSeparator(); menu->addAction(mMsgView->translateAction()); menu->addSeparator(); menu->addAction( mMsgView->speakTextAction()); } else if ( !urlMenuAdded ) { // popup somewhere else (i.e., not a URL) on the message if (!mMessagePane->currentMessage()) { // no messages delete menu; return; } Akonadi::Collection parentCol = msg.parentCollection(); if ( parentCol.isValid() && CommonKernel->folderIsTemplates( parentCol) ) { menu->addAction( mUseAction ); } else { menu->addAction( mMsgActions->replyMenu() ); menu->addAction( mMsgActions->forwardMenu() ); } if ( parentCol.isValid() && CommonKernel->folderIsSentMailFolder( parentCol ) ) { menu->addAction( sendAgainAction() ); } else { menu->addAction( editAction() ); } menu->addAction( mailingListActionMenu() ); menu->addSeparator(); menu->addAction( mCopyActionMenu ); menu->addAction( mMoveActionMenu ); menu->addSeparator(); menu->addAction( mMsgActions->messageStatusMenu() ); menu->addSeparator(); if ( mMsgView ) { if (!imageUrl.isEmpty()) { menu->addSeparator(); menu->addAction( mMsgView->copyImageLocation()); menu->addAction( mMsgView->downloadImageToDiskAction()); menu->addAction( mMsgView->shareImage()); menu->addSeparator(); if (mMsgView->adblockEnabled()) { menu->addAction( mMsgView->blockImage() ); menu->addSeparator(); } } menu->addAction( mMsgView->viewSourceAction() ); menu->addAction( mMsgView->toggleFixFontAction() ); menu->addAction( mMsgView->toggleMimePartTreeAction() ); } menu->addSeparator(); menu->addAction( mMsgActions->printPreviewAction() ); menu->addAction( mMsgActions->printAction() ); menu->addAction( mSaveAsAction ); menu->addAction( mSaveAttachmentsAction ); menu->addSeparator(); if ( parentCol.isValid() && CommonKernel->folderIsTrash(parentCol) ) { menu->addAction( mDeleteAction ); } else { menu->addAction( akonadiStandardAction( Akonadi::StandardMailActionManager::MoveToTrash ) ); } menu->addSeparator(); - menu->addAction( mMsgView->createTodoAction() ); + // menu->addAction( mMsgView->createTodoAction() ); menu->addAction( mMsgView->createEventAction() ); - menu->addAction( mMsgView->createNoteAction() ); + // menu->addAction( mMsgView->createNoteAction() ); menu->addSeparator(); if (mMsgView) { menu->addAction( mMsgView->saveMessageDisplayFormatAction() ); menu->addAction( mMsgView->resetMessageDisplayFormatAction() ); menu->addSeparator(); } if (mMsgView && mMsgView->adblockEnabled()) { menu->addSeparator(); menu->addAction( mMsgView->openBlockableItems()); } } KAcceleratorManager::manage(menu); menu->exec( aPoint, 0 ); delete menu; } //----------------------------------------------------------------------------- void KMMainWidget::getAccountMenu() { mActMenu->clear(); const Akonadi::AgentInstance::List lst = MailCommon::Util::agentInstances(); foreach ( const Akonadi::AgentInstance& type, lst ) { // Explicitly make a copy, as we're not changing values of the list but only // the local copy which is passed to action. QAction* action = mActMenu->addAction( QString( type.name() ).replace(QLatin1Char('&'), QLatin1String("&&")) ); action->setData( type.identifier() ); } } //----------------------------------------------------------------------------- void KMMainWidget::getTransportMenu() { mSendMenu->clear(); QStringList availTransports = MailTransport::TransportManager::self()->transportNames(); QStringList::Iterator it; QStringList::Iterator end( availTransports.end() ); for (it = availTransports.begin(); it != end ; ++it) mSendMenu->addAction((*it).replace(QLatin1Char('&'), QLatin1String("&&"))); } //----------------------------------------------------------------------------- void KMMainWidget::setupActions() { mMsgActions = new KMail::MessageActions( actionCollection(), this ); mMsgActions->setMessageView( mMsgView ); //----- File Menu mSaveAsAction = new KAction(KIcon(QLatin1String("document-save")), i18n("Save &As..."), this); actionCollection()->addAction(QLatin1String("file_save_as"), mSaveAsAction ); connect(mSaveAsAction, SIGNAL(triggered(bool)), SLOT(slotSaveMsg())); mSaveAsAction->setShortcut(KStandardShortcut::save()); mOpenAction = KStandardAction::open( this, SLOT(slotOpenMsg()), actionCollection() ); mOpenRecentAction = KStandardAction::openRecent( this, SLOT(slotOpenRecentMsg(KUrl)), actionCollection() ); KConfigGroup grp = mConfig->group(QLatin1String("Recent Files")); mOpenRecentAction->loadEntries(grp); { KAction *action = new KAction(i18n("&Expire All Folders"), this); actionCollection()->addAction(QLatin1String("expire_all_folders"), action ); connect(action, SIGNAL(triggered(bool)), SLOT(slotExpireAll())); } { KAction *action = new KAction(KIcon(QLatin1String("mail-receive")), i18n("Check &Mail"), this); actionCollection()->addAction(QLatin1String("check_mail"), action ); connect(action, SIGNAL(triggered(bool)), SLOT(slotCheckMail())); action->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_L)); } KActionMenu *actActionMenu = new KActionMenu(KIcon(QLatin1String("mail-receive")), i18n("Check Mail In"), this); actActionMenu->setIconText( i18n("Check Mail") ); actActionMenu->setToolTip( i18n("Check Mail") ); actionCollection()->addAction(QLatin1String("check_mail_in"), actActionMenu ); actActionMenu->setDelayed(true); //needed for checking "all accounts" connect(actActionMenu, SIGNAL(triggered(bool)), this, SLOT(slotCheckMail())); mActMenu = actActionMenu->menu(); connect(mActMenu, SIGNAL(triggered(QAction*)), SLOT(slotCheckOneAccount(QAction*))); connect(mActMenu, SIGNAL(aboutToShow()), SLOT(getAccountMenu())); mSendQueued = new KAction(KIcon(QLatin1String("mail-send")), i18n("&Send Queued Messages"), this); actionCollection()->addAction(QLatin1String("send_queued"), mSendQueued ); connect(mSendQueued, SIGNAL(triggered(bool)), SLOT(slotSendQueued())); { KAction * action = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::ToggleWorkOffline ); mAkonadiStandardActionManager->interceptAction( Akonadi::StandardActionManager::ToggleWorkOffline ); action->setCheckable(false); connect( action, SIGNAL(triggered(bool)), this, SLOT(slotOnlineStatus()) ); action->setText( i18n("Online status (unknown)") ); } mSendActionMenu = new KActionMenu(KIcon(QLatin1String("mail-send-via")), i18n("Send Queued Messages Via"), this); actionCollection()->addAction(QLatin1String("send_queued_via"), mSendActionMenu ); mSendActionMenu->setDelayed(true); mSendMenu = mSendActionMenu->menu(); connect(mSendMenu,SIGNAL(triggered(QAction*)), SLOT(slotSendQueuedVia(QAction*))); connect(mSendMenu,SIGNAL(aboutToShow()),SLOT(getTransportMenu())); //----- Tools menu if (parent()->inherits("KMMainWin")) { KAction *action = new KAction(KIcon(QLatin1String("x-office-address-book")), i18n("&Address Book"), this); actionCollection()->addAction(QLatin1String("addressbook"), action ); connect(action, SIGNAL(triggered(bool)), SLOT(slotAddrBook())); if (KStandardDirs::findExe(QLatin1String("kaddressbook")).isEmpty()) action->setEnabled(false); } { KAction *action = new KAction(KIcon(QLatin1String("pgp-keys")), i18n("Certificate Manager"), this); actionCollection()->addAction(QLatin1String("tools_start_certman"), action ); connect(action, SIGNAL(triggered(bool)), SLOT(slotStartCertManager())); // disable action if no certman binary is around if (KStandardDirs::findExe(QLatin1String("kleopatra")).isEmpty()) action->setEnabled(false); } { KAction *action = new KAction(KIcon(QLatin1String("pgp-keys")), i18n("GnuPG Log Viewer"), this); actionCollection()->addAction(QLatin1String("tools_start_kwatchgnupg"), action ); connect(action, SIGNAL(triggered(bool)), SLOT(slotStartWatchGnuPG())); #ifdef Q_OS_WIN32 // not ported yet, underlying infrastructure missing on Windows const bool usableKWatchGnupg = false; #else // disable action if no kwatchgnupg binary is around bool usableKWatchGnupg = !KStandardDirs::findExe(QLatin1String("kwatchgnupg")).isEmpty(); #endif action->setEnabled(usableKWatchGnupg); } { KAction *action = new KAction(KIcon(QLatin1String("document-import")), i18n("&Import Messages..."), this); actionCollection()->addAction(QLatin1String("import"), action ); connect(action, SIGNAL(triggered(bool)), SLOT(slotImport())); if (KStandardDirs::findExe(QLatin1String("kmailcvt")).isEmpty()) action->setEnabled(false); } #if !defined(NDEBUG) { KAction *action = new KAction(i18n("&Debug Sieve..."), this); actionCollection()->addAction(QLatin1String("tools_debug_sieve"), action ); connect(action, SIGNAL(triggered(bool)), SLOT(slotDebugSieve())); } #endif { KAction *action = new KAction(i18n("Filter &Log Viewer..."), this); actionCollection()->addAction(QLatin1String("filter_log_viewer"), action ); connect(action, SIGNAL(triggered(bool)), SLOT(slotFilterLogViewer())); } { KAction *action = new KAction(i18n("&Anti-Spam Wizard..."), this); actionCollection()->addAction(QLatin1String("antiSpamWizard"), action ); connect(action, SIGNAL(triggered(bool)), SLOT(slotAntiSpamWizard())); } { KAction *action = new KAction(i18n("&Anti-Virus Wizard..."), this); actionCollection()->addAction(QLatin1String("antiVirusWizard"), action ); connect(action, SIGNAL(triggered(bool)), SLOT(slotAntiVirusWizard())); } { KAction *action = new KAction( i18n("&Account Wizard..."), this ); actionCollection()->addAction( QLatin1String("accountWizard"), action ); connect( action, SIGNAL(triggered(bool)), SLOT(slotAccountWizard()) ); } { KAction *action = new KAction( i18n("&Import Wizard..."), this ); actionCollection()->addAction( QLatin1String("importWizard"), action ); connect( action, SIGNAL(triggered(bool)), SLOT(slotImportWizard()) ); } if ( KSieveUi::Util::allowOutOfOfficeSettings() ) { KAction *action = new KAction( i18n("Edit \"Out of Office\" Replies..."), this ); actionCollection()->addAction( QLatin1String("tools_edit_vacation"), action ); connect( action, SIGNAL(triggered(bool)), SLOT(slotEditVacation()) ); } { KAction *action = new KAction(i18n("&Configure Automatic Archiving..."), this); actionCollection()->addAction(QLatin1String("tools_automatic_archiving"), action ); connect(action, SIGNAL(triggered(bool)), SLOT(slotConfigureAutomaticArchiving())); } { KAction *action = new KAction(i18n("Message Delayed..."), this); actionCollection()->addAction(QLatin1String("message_delayed"), action ); connect(action, SIGNAL(triggered(bool)), SLOT(slotConfigureSendLater())); } // Disable the standard action delete key sortcut. KAction* const standardDelAction = akonadiStandardAction( Akonadi::StandardActionManager::DeleteItems ); standardDelAction->setShortcut( QKeySequence() ); //----- Edit Menu /* The delete action is nowhere in the gui, by default, so we need to make * sure it is plugged into the KAccel now, since that won't happen on * XMLGui construction or manual ->plug(). This is only a problem when run * as a part, though. */ mDeleteAction = new KAction(KIcon(QLatin1String("edit-delete")), i18nc("@action Hard delete, bypassing trash", "&Delete"), this); actionCollection()->addAction(QLatin1String("delete"), mDeleteAction ); connect(mDeleteAction, SIGNAL(triggered(bool)), SLOT(slotDeleteMsg())); mDeleteAction->setShortcut(QKeySequence(Qt::SHIFT+Qt::Key_Delete)); mTrashThreadAction = new KAction(i18n("M&ove Thread to Trash"), this); actionCollection()->addAction(QLatin1String("move_thread_to_trash"), mTrashThreadAction ); mTrashThreadAction->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_Delete)); mTrashThreadAction->setIcon(KIcon(QLatin1String("user-trash"))); mTrashThreadAction->setHelpText(i18n("Move thread to trashcan") ); connect(mTrashThreadAction, SIGNAL(triggered(bool)), SLOT(slotTrashThread())); mDeleteThreadAction = new KAction(KIcon(QLatin1String("edit-delete")), i18n("Delete T&hread"), this); actionCollection()->addAction(QLatin1String("delete_thread"), mDeleteThreadAction ); connect(mDeleteThreadAction, SIGNAL(triggered(bool)), SLOT(slotDeleteThread())); mDeleteThreadAction->setShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_Delete)); { KAction *action = new KAction(KIcon(QLatin1String("edit-find-mail")), i18n("&Find Messages..."), this); actionCollection()->addAction(QLatin1String("search_messages"), action ); connect(action, SIGNAL(triggered(bool)), SLOT(slotRequestFullSearchFromQuickSearch())); action->setShortcut(QKeySequence(Qt::Key_S)); } { KAction *action = new KAction(i18n("Select &All Messages"), this); actionCollection()->addAction(QLatin1String("mark_all_messages"), action ); connect(action, SIGNAL(triggered(bool)), SLOT(slotMarkAll())); action->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_A ) ); } //----- Folder Menu mFolderMailingListPropertiesAction = new KAction(i18n("&Mailing List Management..."), this); actionCollection()->addAction(QLatin1String("folder_mailinglist_properties"), mFolderMailingListPropertiesAction ); connect(mFolderMailingListPropertiesAction, SIGNAL(triggered(bool)), SLOT(slotFolderMailingListProperties())); // mFolderMailingListPropertiesAction->setIcon(KIcon("document-properties-mailing-list")); mShowFolderShortcutDialogAction = new KAction(KIcon(QLatin1String("configure-shortcuts")), i18n("&Assign Shortcut..."), this); actionCollection()->addAction(QLatin1String("folder_shortcut_command"), mShowFolderShortcutDialogAction ); connect( mShowFolderShortcutDialogAction, SIGNAL(triggered(bool)), SLOT(slotShowFolderShortcutDialog()) ); // FIXME: this action is not currently enabled in the rc file, but even if // it were there is inconsistency between the action name and action. // "Expiration Settings" implies that this will lead to a settings dialogue // and it should be followed by a "...", but slotExpireFolder() performs // an immediate expiry. // // TODO: expire action should be disabled if there is no content or if // the folder can't delete messages. // // Leaving the action here for the moment, it and the "Expire" option in the // folder popup menu should be combined or at least made consistent. Same for // slotExpireFolder() and FolderViewItem::slotShowExpiryProperties(). mExpireFolderAction = new KAction(i18n("&Expiration Settings"), this); actionCollection()->addAction(QLatin1String("expire"), mExpireFolderAction ); connect(mExpireFolderAction, SIGNAL(triggered(bool)), SLOT(slotExpireFolder())); mAkonadiStandardActionManager->interceptAction( Akonadi::StandardMailActionManager::MoveToTrash ); connect( mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::MoveToTrash ), SIGNAL(triggered(bool)), this, SLOT(slotTrashSelectedMessages()) ); mAkonadiStandardActionManager->interceptAction( Akonadi::StandardMailActionManager::MoveAllToTrash ); connect( mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::MoveAllToTrash ), SIGNAL(triggered(bool)), this, SLOT(slotEmptyFolder()) ); mAkonadiStandardActionManager->interceptAction( Akonadi::StandardActionManager::DeleteCollections ); connect( mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::DeleteCollections ), SIGNAL(triggered(bool)), this, SLOT(slotRemoveFolder()) ); // ### PORT ME: Add this to the context menu. Not possible right now because // the context menu uses XMLGUI, and that would add the entry to // all collection context menus mArchiveFolderAction = new KAction( i18n( "&Archive Folder..." ), this ); actionCollection()->addAction( QLatin1String("archive_folder"), mArchiveFolderAction ); connect( mArchiveFolderAction, SIGNAL(triggered(bool)), SLOT(slotArchiveFolder()) ); mPreferHtmlAction = new KToggleAction(i18n("Prefer &HTML to Plain Text"), this); actionCollection()->addAction(QLatin1String("prefer_html"), mPreferHtmlAction ); connect(mPreferHtmlAction, SIGNAL(triggered(bool)), SLOT(slotOverrideHtml())); mPreferHtmlLoadExtAction = new KToggleAction(i18n("Load E&xternal References"), this); actionCollection()->addAction(QLatin1String("prefer_html_external_refs"), mPreferHtmlLoadExtAction ); connect(mPreferHtmlLoadExtAction, SIGNAL(triggered(bool)), SLOT(slotOverrideHtmlLoadExt())); { KAction *action = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::CopyCollections); action->setShortcut(QKeySequence(Qt::SHIFT+Qt::CTRL+Qt::Key_C)); } { KAction *action = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::Paste); action->setShortcut(QKeySequence(Qt::SHIFT+Qt::CTRL+Qt::Key_V)); } { KAction *action = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::CopyItems); action->setShortcut(QKeySequence(Qt::ALT+Qt::CTRL+Qt::Key_C)); } { KAction *action = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::CutItems ); action->setShortcut(QKeySequence(Qt::ALT+Qt::CTRL+Qt::Key_X)); } { KAction *action = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::CopyItemToMenu ); action->setText(i18n("Copy Message To...") ); action = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::MoveItemToMenu ); action->setText(i18n("Move Message To...") ); } //----- Message Menu { KAction *action = new KAction(KIcon(QLatin1String("mail-message-new")), i18n("&New Message..."), this); actionCollection()->addAction(QLatin1String("new_message"), action ); action->setIconText( i18nc("@action:intoolbar New Empty Message", "New" ) ); connect(action, SIGNAL(triggered(bool)), SLOT(slotCompose())); // do not set a New shortcut if kmail is a component if ( !kmkernel->xmlGuiInstance().isValid() ) { action->setShortcut(KStandardShortcut::openNew()); } } mTemplateMenu = new KActionMenu( KIcon( QLatin1String("document-new") ), i18n("Message From &Template"), actionCollection() ); mTemplateMenu->setDelayed( true ); actionCollection()->addAction(QLatin1String("new_from_template"), mTemplateMenu ); connect( mTemplateMenu->menu(), SIGNAL(aboutToShow()), this, SLOT(slotShowNewFromTemplate()) ); connect( mTemplateMenu->menu(), SIGNAL(triggered(QAction*)), this, SLOT(slotNewFromTemplate(QAction*)) ); mMessageNewList = new KAction( KIcon( QLatin1String("mail-message-new-list") ), i18n( "New Message t&o Mailing-List..." ), this ); actionCollection()->addAction(QLatin1String("post_message"), mMessageNewList); connect( mMessageNewList, SIGNAL(triggered(bool)), SLOT(slotPostToML()) ); mMessageNewList->setShortcut( QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_N ) ); mSendAgainAction = new KAction(i18n("Send A&gain..."), this); actionCollection()->addAction(QLatin1String("send_again"), mSendAgainAction ); connect(mSendAgainAction, SIGNAL(triggered(bool)), SLOT(slotResendMsg())); //----- Create filter actions mFilterMenu = new KActionMenu(KIcon(QLatin1String("view-filter")), i18n("&Create Filter"), this); actionCollection()->addAction(QLatin1String("create_filter"), mFilterMenu ); connect( mFilterMenu, SIGNAL(triggered(bool)), this, SLOT(slotFilter()) ); { KAction *action = new KAction(i18n("Filter on &Subject..."), this); actionCollection()->addAction(QLatin1String("subject_filter"), action ); connect(action, SIGNAL(triggered(bool)), SLOT(slotSubjectFilter())); mFilterMenu->addAction( action ); } { KAction *action = new KAction(i18n("Filter on &From..."), this); actionCollection()->addAction(QLatin1String("from_filter"), action ); connect(action, SIGNAL(triggered(bool)), SLOT(slotFromFilter())); mFilterMenu->addAction( action ); } { KAction *action = new KAction(i18n("Filter on &To..."), this); actionCollection()->addAction(QLatin1String("to_filter"), action ); connect(action, SIGNAL(triggered(bool)), SLOT(slotToFilter())); mFilterMenu->addAction( action ); } mFilterMenu->addAction( mMsgActions->listFilterAction() ); mUseAction = new KAction( KIcon(QLatin1String("document-new")), i18n("New Message From &Template"), this ); actionCollection()->addAction(QLatin1String("use_template"), mUseAction); connect(mUseAction, SIGNAL(triggered(bool)), SLOT(slotUseTemplate())); mUseAction->setShortcut(QKeySequence(Qt::SHIFT + Qt::Key_N)); //----- "Mark Thread" submenu mThreadStatusMenu = new KActionMenu(i18n("Mark &Thread"), this); actionCollection()->addAction(QLatin1String("thread_status"), mThreadStatusMenu ); mMarkThreadAsReadAction = new KAction(KIcon(QLatin1String("mail-mark-read")), i18n("Mark Thread as &Read"), this); actionCollection()->addAction(QLatin1String("thread_read"), mMarkThreadAsReadAction ); connect(mMarkThreadAsReadAction, SIGNAL(triggered(bool)), SLOT(slotSetThreadStatusRead())); mMarkThreadAsReadAction->setHelpText(i18n("Mark all messages in the selected thread as read")); mThreadStatusMenu->addAction( mMarkThreadAsReadAction ); mMarkThreadAsUnreadAction = new KAction(KIcon(QLatin1String("mail-mark-unread")), i18n("Mark Thread as &Unread"), this); actionCollection()->addAction(QLatin1String("thread_unread"), mMarkThreadAsUnreadAction ); connect(mMarkThreadAsUnreadAction, SIGNAL(triggered(bool)), SLOT(slotSetThreadStatusUnread())); mMarkThreadAsUnreadAction->setHelpText(i18n("Mark all messages in the selected thread as unread")); mThreadStatusMenu->addAction( mMarkThreadAsUnreadAction ); mThreadStatusMenu->addSeparator(); //----- "Mark Thread" toggle actions mToggleThreadImportantAction = new KToggleAction(KIcon(QLatin1String("mail-mark-important")), i18n("Mark Thread as &Important"), this); actionCollection()->addAction(QLatin1String("thread_flag"), mToggleThreadImportantAction ); connect(mToggleThreadImportantAction, SIGNAL(triggered(bool)), SLOT(slotSetThreadStatusImportant())); mToggleThreadImportantAction->setCheckedState( KGuiItem(i18n("Remove &Important Thread Mark")) ); mThreadStatusMenu->addAction( mToggleThreadImportantAction ); mToggleThreadToActAction = new KToggleAction(KIcon(QLatin1String("mail-mark-task")), i18n("Mark Thread as &Action Item"), this); actionCollection()->addAction(QLatin1String("thread_toact"), mToggleThreadToActAction ); connect(mToggleThreadToActAction, SIGNAL(triggered(bool)), SLOT(slotSetThreadStatusToAct())); mToggleThreadToActAction->setCheckedState( KGuiItem(i18n("Remove &Action Item Thread Mark")) ); mThreadStatusMenu->addAction( mToggleThreadToActAction ); //------- "Watch and ignore thread" actions mWatchThreadAction = new KToggleAction(KIcon(QLatin1String("mail-thread-watch")), i18n("&Watch Thread"), this); actionCollection()->addAction(QLatin1String("thread_watched"), mWatchThreadAction ); connect(mWatchThreadAction, SIGNAL(triggered(bool)), SLOT(slotSetThreadStatusWatched())); mIgnoreThreadAction = new KToggleAction(KIcon(QLatin1String("mail-thread-ignored")), i18n("&Ignore Thread"), this); actionCollection()->addAction(QLatin1String("thread_ignored"), mIgnoreThreadAction ); connect(mIgnoreThreadAction, SIGNAL(triggered(bool)), SLOT(slotSetThreadStatusIgnored())); mThreadStatusMenu->addSeparator(); mThreadStatusMenu->addAction( mWatchThreadAction ); mThreadStatusMenu->addAction( mIgnoreThreadAction ); mSaveAttachmentsAction = new KAction(KIcon(QLatin1String("mail-attachment")), i18n("Save A&ttachments..."), this); actionCollection()->addAction(QLatin1String("file_save_attachments"), mSaveAttachmentsAction ); connect(mSaveAttachmentsAction, SIGNAL(triggered(bool)), SLOT(slotSaveAttachments())); mMoveActionMenu = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::MoveItemToMenu); mCopyActionMenu = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::CopyItemToMenu); mApplyAllFiltersAction = new KAction( KIcon( QLatin1String("view-filter") ), i18n( "Appl&y All Filters" ), this ); actionCollection()->addAction( QLatin1String("apply_filters"), mApplyAllFiltersAction ); connect( mApplyAllFiltersAction, SIGNAL(triggered(bool)), SLOT(slotApplyFilters()) ); mApplyAllFiltersAction->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_J ) ); mApplyFilterActionsMenu = new KActionMenu( i18n( "A&pply Filter" ), this ); actionCollection()->addAction( QLatin1String("apply_filter_actions"), mApplyFilterActionsMenu ); { KAction *action = new KAction(i18nc("View->","&Expand Thread / Group"), this); actionCollection()->addAction(QLatin1String("expand_thread"), action ); action->setShortcut(QKeySequence(Qt::Key_Period)); action->setHelpText(i18n("Expand the current thread or group")); connect(action, SIGNAL(triggered(bool)), SLOT(slotExpandThread())); } { KAction *action = new KAction(i18nc("View->","&Collapse Thread / Group"), this); actionCollection()->addAction(QLatin1String("collapse_thread"), action ); action->setShortcut(QKeySequence(Qt::Key_Comma)); action->setHelpText( i18n("Collapse the current thread or group")); connect(action, SIGNAL(triggered(bool)), SLOT(slotCollapseThread())); } { KAction *action = new KAction(i18nc("View->","Ex&pand All Threads"), this); actionCollection()->addAction(QLatin1String("expand_all_threads"), action ); action->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_Period)); action->setHelpText( i18n("Expand all threads in the current folder")); connect(action, SIGNAL(triggered(bool)), SLOT(slotExpandAllThreads())); } { KAction *action = new KAction(i18nc("View->","C&ollapse All Threads"), this); actionCollection()->addAction(QLatin1String("collapse_all_threads"), action ); action->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_Comma)); action->setHelpText( i18n("Collapse all threads in the current folder")); connect(action, SIGNAL(triggered(bool)), SLOT(slotCollapseAllThreads())); } KAction *dukeOfMonmoth = new KAction(i18n("&Display Message"), this); actionCollection()->addAction(QLatin1String("display_message"), dukeOfMonmoth ); connect(dukeOfMonmoth, SIGNAL(triggered(bool)), SLOT(slotDisplayCurrentMessage())); KShortcut shortcut = KShortcut(QKeySequence( Qt::Key_Enter )); shortcut.setAlternate( QKeySequence( Qt::Key_Return ) ); dukeOfMonmoth->setShortcuts( shortcut ); //----- Go Menu { KAction *action = new KAction(i18n("&Next Message"), this); actionCollection()->addAction(QLatin1String("go_next_message"), action ); action->setShortcuts(KShortcut( QLatin1String("N; Right") )); action->setHelpText(i18n("Go to the next message")); connect(action, SIGNAL(triggered(bool)), SLOT(slotSelectNextMessage())); } { KAction *action = new KAction(i18n("Next &Unread Message"), this); actionCollection()->addAction(QLatin1String("go_next_unread_message"), action ); action->setShortcut(QKeySequence(Qt::Key_Plus)); if ( QApplication::isRightToLeft() ) { action->setIcon( KIcon( QLatin1String("go-previous") ) ); } else { action->setIcon( KIcon( QLatin1String("go-next") ) ); } action->setIconText( i18nc( "@action:inmenu Goto next unread message", "Next" ) ); action->setHelpText(i18n("Go to the next unread message")); connect(action, SIGNAL(triggered(bool)), SLOT(slotSelectNextUnreadMessage())); } { KAction *action = new KAction(i18n("&Previous Message"), this); actionCollection()->addAction(QLatin1String("go_prev_message"), action ); action->setHelpText(i18n("Go to the previous message")); action->setShortcuts(KShortcut( QLatin1String("P; Left") )); connect(action, SIGNAL(triggered(bool)), SLOT(slotSelectPreviousMessage())); } { KAction *action = new KAction(i18n("Previous Unread &Message"), this); actionCollection()->addAction(QLatin1String("go_prev_unread_message"), action ); action->setShortcut(QKeySequence(Qt::Key_Minus)); if ( QApplication::isRightToLeft() ) { action->setIcon( KIcon( QLatin1String("go-next") ) ); } else { action->setIcon( KIcon( QLatin1String("go-previous") ) ); } action->setIconText( i18nc( "@action:inmenu Goto previous unread message.","Previous" ) ); action->setHelpText(i18n("Go to the previous unread message")); connect(action, SIGNAL(triggered(bool)), SLOT(slotSelectPreviousUnreadMessage())); } { KAction *action = new KAction(i18n("Next Unread &Folder"), this); actionCollection()->addAction(QLatin1String("go_next_unread_folder"), action ); connect(action, SIGNAL(triggered(bool)), SLOT(slotNextUnreadFolder())); action->setShortcut(QKeySequence(Qt::ALT+Qt::Key_Plus)); action->setHelpText(i18n("Go to the next folder with unread messages")); } { KAction *action = new KAction(i18n("Previous Unread F&older"), this); actionCollection()->addAction(QLatin1String("go_prev_unread_folder"), action ); action->setShortcut(QKeySequence(Qt::ALT+Qt::Key_Minus)); action->setHelpText(i18n("Go to the previous folder with unread messages")); connect(action, SIGNAL(triggered(bool)), SLOT(slotPrevUnreadFolder())); } { KAction *action = new KAction(i18nc("Go->","Next Unread &Text"), this); actionCollection()->addAction(QLatin1String("go_next_unread_text"), action ); action->setShortcut(QKeySequence(Qt::Key_Space)); action->setHelpText(i18n("Go to the next unread text")); action->setWhatsThis( i18n("Scroll down current message. " "If at end of current message, " "go to next unread message.")); connect(action, SIGNAL(triggered(bool)), SLOT(slotReadOn())); } //----- Settings Menu { KAction *action = new KAction(i18n("Configure &Filters..."), this); action->setMenuRole( QAction::NoRole ); // do not move to application menu on OS X actionCollection()->addAction(QLatin1String("filter"), action ); connect(action, SIGNAL(triggered(bool)), SLOT(slotFilter())); } { KAction *action = new KAction(i18n("Manage &Sieve Scripts..."), this); actionCollection()->addAction(QLatin1String("sieveFilters"), action ); connect(action, SIGNAL(triggered(bool)), SLOT(slotManageSieveScripts())); } { KAction *action = new KAction(KIcon(QLatin1String("kmail")), i18n("KMail &Introduction"), this); actionCollection()->addAction(QLatin1String("help_kmail_welcomepage"), action ); action->setHelpText( i18n("Display KMail's Welcome Page") ); connect(action, SIGNAL(triggered(bool)), SLOT(slotIntro())); } // ----- Standard Actions // KStandardAction::configureNotifications(this, SLOT(slotEditNotifications()), actionCollection()); { KAction *action = new KAction( KIcon(QLatin1String("preferences-desktop-notification")), i18n("Configure &Notifications..."), this ); action->setMenuRole( QAction::NoRole ); // do not move to application menu on OS X actionCollection()->addAction( QLatin1String("kmail_configure_notifications"), action ); connect(action, SIGNAL(triggered(bool)), SLOT(slotEditNotifications())); } { KAction *action = new KAction(KIcon(QLatin1String("configure")), i18n("&Configure KMail..."), this); actionCollection()->addAction(QLatin1String("kmail_configure_kmail"), action ); connect(action, SIGNAL(triggered(bool)), kmkernel, SLOT(slotShowConfigurationDialog())); } { mExpireConfigAction = new KAction( i18n( "Expire..." ), this ); actionCollection()->addAction( QLatin1String("expire_settings"),mExpireConfigAction ); connect( mExpireConfigAction, SIGNAL(triggered(bool)), this, SLOT(slotShowExpiryProperties()) ); } { KAction *action = new KAction( KIcon( QLatin1String("bookmark-new" )), i18n( "Add Favorite Folder..." ), this ); actionCollection()->addAction( QLatin1String("add_favorite_folder"), action ); connect( action, SIGNAL(triggered(bool)), this, SLOT(slotAddFavoriteFolder()) ); } { mServerSideSubscription = new KAction( KIcon( QLatin1String("folder-bookmarks") ), i18n( "Serverside Subscription..." ), this); actionCollection()->addAction( QLatin1String("serverside_subscription"), mServerSideSubscription); connect( mServerSideSubscription, SIGNAL(triggered(bool)), this, SLOT(slotServerSideSubscription()) ); } { mApplyFiltersOnFolder = new KAction( KIcon( QLatin1String("view-filter") ), i18n( "Appl&y All Filters On Folder" ), this ); actionCollection()->addAction( QLatin1String("apply_filters_on_folder"), mApplyFiltersOnFolder ); connect( mApplyFiltersOnFolder, SIGNAL(triggered(bool)), SLOT(slotApplyFiltersOnFolder()) ); } { KAction *action = new KAction(KIcon(QLatin1String("kmail")), i18n("&Export KMail Data..."), this); actionCollection()->addAction(QLatin1String("kmail_export_data"), action ); connect(action, SIGNAL(triggered(bool)), this, SLOT(slotExportData())); } { KAction *action = new KAction(KIcon( QLatin1String( "contact-new" ) ),i18n("New AddressBook Contact..."),this); actionCollection()->addAction(QLatin1String("kmail_new_addressbook_contact"), action ); connect(action, SIGNAL(triggered(bool)), this, SLOT(slotCreateAddressBookContact())); } actionCollection()->addAction(KStandardAction::Undo, QLatin1String("kmail_undo"), this, SLOT(slotUndo())); KStandardAction::tipOfDay( this, SLOT(slotShowTip()), actionCollection() ); menutimer = new QTimer( this ); menutimer->setObjectName( QLatin1String("menutimer") ); menutimer->setSingleShot( true ); connect( menutimer, SIGNAL(timeout()), SLOT(updateMessageActionsDelayed()) ); connect( kmkernel->undoStack(), SIGNAL(undoStackChanged()), this, SLOT(slotUpdateUndo())); updateMessageActions(); updateFolderMenu(); mTagActionManager = new KMail::TagActionManager( this, actionCollection(), mMsgActions, mGUIClient ); mFolderShortcutActionManager = new KMail::FolderShortcutActionManager( this, actionCollection() ); { KAction *action = new KAction( i18n("Copy Message to Folder"), this ); actionCollection()->addAction(QLatin1String( "copy_message_to_folder"), action ); connect( action, SIGNAL(triggered(bool)), SLOT(slotCopySelectedMessagesToFolder()) ); action->setShortcut( QKeySequence( Qt::Key_C ) ); } { KAction *action = new KAction( i18n("Jump to Folder..."), this ); actionCollection()->addAction( QLatin1String("jump_to_folder"), action ); connect( action, SIGNAL(triggered(bool)), SLOT(slotJumpToFolder()) ); action->setShortcut( QKeySequence( Qt::Key_J ) ); } { KAction *action = new KAction(i18n("Abort Current Operation"), this); actionCollection()->addAction(QLatin1String("cancel"), action ); connect( action, SIGNAL(triggered(bool)), ProgressManager::instance(), SLOT(slotAbortAll()) ); action->setShortcut( QKeySequence( Qt::Key_Escape ) ); } { KAction *action = new KAction(i18n("Focus on Next Folder"), this); actionCollection()->addAction(QLatin1String("inc_current_folder"), action ); connect( action, SIGNAL(triggered(bool)), mFolderTreeWidget->folderTreeView(), SLOT(slotFocusNextFolder()) ); action->setShortcut( QKeySequence( Qt::CTRL+Qt::Key_Right ) ); } { KAction *action = new KAction(i18n("Focus on Previous Folder"), this); actionCollection()->addAction(QLatin1String("dec_current_folder"), action ); connect( action, SIGNAL(triggered(bool)), mFolderTreeWidget->folderTreeView(), SLOT(slotFocusPrevFolder()) ); action->setShortcut( QKeySequence( Qt::CTRL+Qt::Key_Left ) ); } { KAction *action = new KAction(i18n("Select Folder with Focus"), this); actionCollection()->addAction(QLatin1String("select_current_folder"), action ); connect( action, SIGNAL(triggered(bool)), mFolderTreeWidget->folderTreeView(), SLOT(slotSelectFocusFolder()) ); action->setShortcut( QKeySequence( Qt::CTRL+Qt::Key_Space ) ); } { KAction *action = new KAction(i18n("Focus on First Folder"), this); actionCollection()->addAction(QLatin1String("focus_first_folder"), action ); connect( action, SIGNAL(triggered(bool)), mFolderTreeWidget->folderTreeView(), SLOT(slotFocusFirstFolder()) ); action->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_Home ) ); } { KAction *action = new KAction(i18n("Focus on Last Folder"), this); actionCollection()->addAction(QLatin1String("focus_last_folder"), action ); connect( action, SIGNAL(triggered(bool)), mFolderTreeWidget->folderTreeView(), SLOT(slotFocusLastFolder()) ); action->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_End ) ); } { KAction *action = new KAction(i18n("Focus on Next Message"), this); actionCollection()->addAction(QLatin1String("inc_current_message"), action ); connect( action, SIGNAL(triggered(bool)), this, SLOT(slotFocusOnNextMessage()) ); action->setShortcut( QKeySequence( Qt::ALT+Qt::Key_Right ) ); } { KAction *action = new KAction(i18n("Focus on Previous Message"), this); actionCollection()->addAction(QLatin1String("dec_current_message"), action ); connect( action, SIGNAL(triggered(bool)), this, SLOT(slotFocusOnPrevMessage()) ); action->setShortcut( QKeySequence( Qt::ALT+Qt::Key_Left ) ); } { KAction *action = new KAction(i18n("Select First Message"), this); actionCollection()->addAction(QLatin1String("select_first_message"), action ); connect ( action, SIGNAL(triggered(bool)), this, SLOT(slotSelectFirstMessage()) ); action->setShortcut( QKeySequence( Qt::ALT + Qt::Key_Home ) ); } { KAction *action = new KAction(i18n("Select Last Message"), this); actionCollection()->addAction(QLatin1String("select_last_message"), action ); connect ( action, SIGNAL(triggered(bool)), this, SLOT(slotSelectLastMessage()) ); action->setShortcut( QKeySequence( Qt::ALT + Qt::Key_End ) ); } { KAction *action = new KAction(i18n("Select Message with Focus"), this); actionCollection()->addAction( QLatin1String("select_current_message"), action ); connect( action, SIGNAL(triggered(bool)), this, SLOT(slotSelectFocusedMessage()) ); action->setShortcut( QKeySequence( Qt::ALT+Qt::Key_Space ) ); } { mQuickSearchAction = new KAction( i18n("Set Focus to Quick Search"), this ); //If change shortcut change Panel::setQuickSearchClickMessage(...) message mQuickSearchAction->setShortcut( QKeySequence( Qt::ALT + Qt::Key_Q ) ); actionCollection()->addAction( QLatin1String("focus_to_quickseach"), mQuickSearchAction ); connect( mQuickSearchAction, SIGNAL(triggered(bool)), SLOT(slotFocusQuickSearch()) ); updateQuickSearchLineText(); } { KAction *action = new KAction( i18n( "Extend Selection to Previous Message" ), this ); action->setShortcut( QKeySequence( Qt::SHIFT + Qt::Key_Left ) ); actionCollection()->addAction( QLatin1String("previous_message"), action ); connect( action, SIGNAL(triggered(bool)), this, SLOT(slotExtendSelectionToPreviousMessage()) ); } { KAction *action = new KAction( i18n( "Extend Selection to Next Message" ), this ); action->setShortcut( QKeySequence( Qt::SHIFT + Qt::Key_Right ) ); actionCollection()->addAction( QLatin1String("next_message"), action ); connect( action, SIGNAL(triggered(bool)), this, SLOT(slotExtendSelectionToNextMessage()) ); } { mMoveMsgToFolderAction = new KAction( i18n("Move Message to Folder"), this ); mMoveMsgToFolderAction->setShortcut( QKeySequence( Qt::Key_M ) ); actionCollection()->addAction( QLatin1String("move_message_to_folder"), mMoveMsgToFolderAction ); connect( mMoveMsgToFolderAction, SIGNAL(triggered(bool)), SLOT(slotMoveSelectedMessageToFolder()) ); } mArchiveAction = new KAction( i18nc("@action", "Archive"), this); actionCollection()->addAction( QLatin1String("archive_mails"), mArchiveAction ); connect( mArchiveAction, SIGNAL(triggered(bool)), SLOT(slotArchiveMails()) ); } void KMMainWidget::slotAddFavoriteFolder() { if (!mFavoritesModel) return; QPointer dialog( selectFromAllFoldersDialog() ); dialog->setCaption( i18n("Add Favorite Folder") ); if ( dialog->exec() && dialog ) { const Akonadi::Collection collection = dialog->selectedCollection(); if ( collection.isValid() ) { mFavoritesModel->addCollection( collection ); } } } //----------------------------------------------------------------------------- void KMMainWidget::slotEditNotifications() { KMail::KMKnotify notifyDlg( this ); notifyDlg.exec(); } void KMMainWidget::slotShowExpiryProperties() { showCollectionProperties( QLatin1String( "MailCommon::CollectionExpiryPage" ) ); } //----------------------------------------------------------------------------- void KMMainWidget::slotReadOn() { if ( !mMsgView ) return; if ( !mMsgView->viewer()->atBottom() ) { mMsgView->viewer()->slotJumpDown(); return; } slotSelectNextUnreadMessage(); } void KMMainWidget::slotNextUnreadFolder() { if ( !mFolderTreeWidget ) return; mGoToFirstUnreadMessageInSelectedFolder = true; mFolderTreeWidget->folderTreeView()->selectNextUnreadFolder(); mGoToFirstUnreadMessageInSelectedFolder = false; } void KMMainWidget::slotPrevUnreadFolder() { if ( !mFolderTreeWidget ) return; mGoToFirstUnreadMessageInSelectedFolder = true; mFolderTreeWidget->folderTreeView()->selectPrevUnreadFolder(); mGoToFirstUnreadMessageInSelectedFolder = false; } void KMMainWidget::slotExpandThread() { mMessagePane->setCurrentThreadExpanded( true ); } void KMMainWidget::slotCollapseThread() { mMessagePane->setCurrentThreadExpanded( false ); } void KMMainWidget::slotExpandAllThreads() { // TODO: Make this asynchronous ? (if there is enough demand) #ifndef QT_NO_CURSOR MessageViewer::KCursorSaver busy( MessageViewer::KBusyPtr::busy() ); #endif mMessagePane->setAllThreadsExpanded( true ); } void KMMainWidget::slotCollapseAllThreads() { // TODO: Make this asynchronous ? (if there is enough demand) #ifndef QT_NO_CURSOR MessageViewer::KCursorSaver busy( MessageViewer::KBusyPtr::busy() ); #endif mMessagePane->setAllThreadsExpanded( false ); } //----------------------------------------------------------------------------- void KMMainWidget::updateMessageMenu() { updateMessageActions(); } void KMMainWidget::startUpdateMessageActionsTimer() { // FIXME: This delay effectively CAN make the actions to be in an incoherent state // Maybe we should mark actions as "dirty" here and check it in every action handler... updateMessageActions( true ); menutimer->stop(); menutimer->start( 500 ); } void KMMainWidget::updateMessageActions( bool fast ) { Akonadi::Item::List selectedItems; Akonadi::Item::List selectedVisibleItems; bool allSelectedBelongToSameThread = false; if (mCurrentFolder && mCurrentFolder->isValid() && mMessagePane->getSelectionStats( selectedItems, selectedVisibleItems, &allSelectedBelongToSameThread ) ) { mMsgActions->setCurrentMessage( mMessagePane->currentItem(), selectedVisibleItems ); } else { mMsgActions->setCurrentMessage( Akonadi::Item() ); } if ( !fast ) updateMessageActionsDelayed(); } void KMMainWidget::updateMessageActionsDelayed() { int count; Akonadi::Item::List selectedItems; Akonadi::Item::List selectedVisibleItems; bool allSelectedBelongToSameThread = false; Akonadi::Item currentMessage; if (mCurrentFolder && mCurrentFolder->isValid() && mMessagePane->getSelectionStats( selectedItems, selectedVisibleItems, &allSelectedBelongToSameThread ) ) { count = selectedItems.count(); currentMessage = mMessagePane->currentItem(); } else { count = 0; currentMessage = Akonadi::Item(); } mApplyFiltersOnFolder->setEnabled( mCurrentFolder && mCurrentFolder->isValid() ); // // Here we have: // // - A list of selected messages stored in selectedSernums. // The selected messages might contain some invisible ones as a selected // collapsed node "includes" all the children in the selection. // - A list of selected AND visible messages stored in selectedVisibleSernums. // This list does not contain children of selected and collapsed nodes. // // Now, actions can operate on: // - Any set of messages // These are called "mass actions" and are enabled whenever we have a message selected. // In fact we should differentiate between actions that operate on visible selection // and those that operate on the selection as a whole (without considering visibility)... // - A single thread // These are called "thread actions" and are enabled whenever all the selected messages belong // to the same thread. If the selection doesn't cover the whole thread then the action // will act on the whole thread anyway (thus will silently extend the selection) // - A single message // And we have two sub-cases: // - The selection must contain exactly one message // These actions can't ignore the hidden messages and thus must be disabled if // the selection contains any. // - The selection must contain exactly one visible message // These actions will ignore the hidden message and thus can be enabled if // the selection contains any. // bool readOnly = mCurrentFolder && mCurrentFolder->isValid() && ( mCurrentFolder->rights() & Akonadi::Collection::ReadOnly ); // can we apply strictly single message actions ? (this is false if the whole selection contains more than one message) bool single_actions = count == 1; // can we apply loosely single message actions ? (this is false if the VISIBLE selection contains more than one message) bool singleVisibleMessageSelected = selectedVisibleItems.count() == 1; // can we apply "mass" actions to the selection ? (this is actually always true if the selection is non-empty) bool mass_actions = count >= 1; // does the selection identify a single thread ? bool thread_actions = mass_actions && allSelectedBelongToSameThread && mMessagePane->isThreaded(); // can we apply flags to the selected messages ? bool flags_available = GlobalSettings::self()->allowLocalFlags() || !(mCurrentFolder && mCurrentFolder->isValid() ? readOnly : true); mThreadStatusMenu->setEnabled( thread_actions ); // these need to be handled individually, the user might have them // in the toolbar mWatchThreadAction->setEnabled( thread_actions && flags_available ); mIgnoreThreadAction->setEnabled( thread_actions && flags_available ); mMarkThreadAsReadAction->setEnabled( thread_actions ); mMarkThreadAsUnreadAction->setEnabled( thread_actions ); mToggleThreadToActAction->setEnabled( thread_actions && flags_available ); mToggleThreadImportantAction->setEnabled( thread_actions && flags_available ); bool canDeleteMessages = mCurrentFolder && mCurrentFolder->isValid() && ( mCurrentFolder->rights() & Akonadi::Collection::CanDeleteItem ); mTrashThreadAction->setEnabled( thread_actions && canDeleteMessages ); mDeleteThreadAction->setEnabled( thread_actions && canDeleteMessages ); if ( currentMessage.isValid() ) { MessageStatus status; status.setStatusFromFlags( currentMessage.flags() ); mTagActionManager->updateActionStates ( count, mMessagePane->currentItem() ); if (thread_actions) { mToggleThreadToActAction->setChecked( status.isToAct() ); mToggleThreadImportantAction->setChecked( status.isImportant() ); mWatchThreadAction->setChecked( status.isWatched() ); mIgnoreThreadAction->setChecked( status.isIgnored() ); } } mMoveActionMenu->setEnabled( mass_actions && canDeleteMessages ); if (mMoveMsgToFolderAction) mMoveMsgToFolderAction->setEnabled( mass_actions && canDeleteMessages ); //mCopyActionMenu->setEnabled( mass_actions ); mDeleteAction->setEnabled( mass_actions && canDeleteMessages ); mExpireConfigAction->setEnabled( canDeleteMessages ); if ( mMsgView ) { mMsgView->findInMessageAction()->setEnabled( mass_actions && !CommonKernel->folderIsTemplates( mCurrentFolder->collection() ) ); } mMsgActions->forwardInlineAction()->setEnabled( mass_actions && !CommonKernel->folderIsTemplates( mCurrentFolder->collection() ) ); mMsgActions->forwardAttachedAction()->setEnabled( mass_actions && !CommonKernel->folderIsTemplates( mCurrentFolder->collection() ) ); mMsgActions->forwardMenu()->setEnabled( mass_actions && !CommonKernel->folderIsTemplates( mCurrentFolder->collection() ) ); mMsgActions->editAction()->setEnabled( single_actions ); mUseAction->setEnabled( single_actions && CommonKernel->folderIsTemplates( mCurrentFolder->collection() ) ); filterMenu()->setEnabled( single_actions ); mMsgActions->redirectAction()->setEnabled( /*single_actions &&*/mass_actions && !CommonKernel->folderIsTemplates( mCurrentFolder->collection() ) ); if ( mMsgActions->customTemplatesMenu() ) { mMsgActions->customTemplatesMenu()->forwardActionMenu()->setEnabled( mass_actions ); mMsgActions->customTemplatesMenu()->replyActionMenu()->setEnabled( single_actions ); mMsgActions->customTemplatesMenu()->replyAllActionMenu()->setEnabled( single_actions ); } // "Print" will act on the current message: it will ignore any hidden selection mMsgActions->printAction()->setEnabled( singleVisibleMessageSelected ); // "Print preview" will act on the current message: it will ignore any hidden selection KAction *printPreviewAction = mMsgActions->printPreviewAction(); if (printPreviewAction) printPreviewAction->setEnabled( singleVisibleMessageSelected ); // "View Source" will act on the current message: it will ignore any hidden selection if (mMsgView) { mMsgView->viewSourceAction()->setEnabled( singleVisibleMessageSelected ); } MessageStatus status; status.setStatusFromFlags( currentMessage.flags() ); QList< QAction *> actionList; bool statusSendAgain = single_actions && ( ( currentMessage.isValid() && status.isSent() ) || ( currentMessage.isValid() && CommonKernel->folderIsSentMailFolder( mCurrentFolder->collection() ) ) ); if ( statusSendAgain ) { actionList << mSendAgainAction; } else if ( single_actions ) { actionList << messageActions()->editAction(); } actionList << mSaveAttachmentsAction; if (mCurrentFolder && FolderArchive::FolderArchiveUtil::resourceSupportArchiving(mCurrentFolder->collection().resource())) actionList << mArchiveAction; mGUIClient->unplugActionList( QLatin1String( "messagelist_actionlist" ) ); mGUIClient->plugActionList( QLatin1String( "messagelist_actionlist" ), actionList ); mSendAgainAction->setEnabled( statusSendAgain ); mSaveAsAction->setEnabled( mass_actions ); if ((mCurrentFolder&& mCurrentFolder->isValid())) { updateMoveAction( mCurrentFolder->statistics() ); } else { updateMoveAction(false,false); } const qint64 nbMsgOutboxCollection = MailCommon::Util::updatedCollection( CommonKernel->outboxCollectionFolder() ).statistics().count(); mSendQueued->setEnabled( nbMsgOutboxCollection > 0 ); mSendActionMenu->setEnabled( nbMsgOutboxCollection > 0 ); const bool newPostToMailingList = mCurrentFolder && mCurrentFolder->isMailingListEnabled(); mMessageNewList->setEnabled(newPostToMailingList); slotUpdateOnlineStatus( static_cast( GlobalSettings::self()->networkState() ) ); if (action( QLatin1String("kmail_undo") )) action( QLatin1String("kmail_undo") )->setEnabled( kmkernel->undoStack()->size() > 0 ); // Enable / disable all filters. foreach ( QAction *filterAction, mFilterMenuActions ) { filterAction->setEnabled( count > 0 ); } mApplyAllFiltersAction->setEnabled( count); mApplyFilterActionsMenu->setEnabled( count ); } void KMMainWidget::slotAkonadiStandardActionUpdated() { bool multiFolder = false; if ( mFolderTreeWidget ) { multiFolder = mFolderTreeWidget->selectedCollections().count() > 1; } if ( mCollectionProperties ) { if ( mCurrentFolder && mCurrentFolder->collection().isValid() ) { const Akonadi::AgentInstance instance = Akonadi::AgentManager::self()->instance( mCurrentFolder->collection().resource() ); mCollectionProperties->setEnabled( !multiFolder && !mCurrentFolder->isStructural() && (instance.status()!=Akonadi::AgentInstance::Broken) ); } else { mCollectionProperties->setEnabled(false); } QList< QAction* > collectionProperties; if ( mCollectionProperties->isEnabled() ) collectionProperties << mCollectionProperties; mGUIClient->unplugActionList( QLatin1String("akonadi_collection_collectionproperties_actionlist") ); mGUIClient->plugActionList( QLatin1String("akonadi_collection_collectionproperties_actionlist"), collectionProperties ); } const bool folderWithContent = mCurrentFolder && !mCurrentFolder->isStructural(); if ( mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::DeleteCollections ) ) { mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::DeleteCollections )->setEnabled( mCurrentFolder && !multiFolder && ( mCurrentFolder->collection().rights() & Collection::CanDeleteCollection ) && !mCurrentFolder->isSystemFolder() && folderWithContent); } if ( mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::MoveAllToTrash ) ) { mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::MoveAllToTrash )->setEnabled( folderWithContent && ( mCurrentFolder->count() > 0 ) && mCurrentFolder->canDeleteMessages() && !multiFolder ); mAkonadiStandardActionManager->action( Akonadi::StandardMailActionManager::MoveAllToTrash )->setText( (mCurrentFolder && CommonKernel->folderIsTrash(mCurrentFolder->collection())) ? i18n("E&mpty Trash") : i18n("&Move All Messages to Trash") ); } QList< QAction* > addToFavorite; QAction *actionAddToFavoriteCollections = akonadiStandardAction( Akonadi::StandardActionManager::AddToFavoriteCollections ); if ( actionAddToFavoriteCollections ) { if ( mEnableFavoriteFolderView && actionAddToFavoriteCollections->isEnabled() ) addToFavorite << actionAddToFavoriteCollections; mGUIClient->unplugActionList( QLatin1String("akonadi_collection_add_to_favorites_actionlist") ); mGUIClient->plugActionList( QLatin1String("akonadi_collection_add_to_favorites_actionlist"), addToFavorite ); } QList< QAction* > syncActionList; QAction *actionSync = akonadiStandardAction( Akonadi::StandardActionManager::SynchronizeCollections ); if ( actionSync && actionSync->isEnabled() ) { syncActionList << actionSync; } actionSync = akonadiStandardAction( Akonadi::StandardActionManager::SynchronizeCollectionsRecursive ); if ( actionSync && actionSync->isEnabled() ) { syncActionList << actionSync; } mGUIClient->unplugActionList( QLatin1String("akonadi_collection_sync_actionlist") ); mGUIClient->plugActionList( QLatin1String("akonadi_collection_sync_actionlist"), syncActionList ); QList< QAction* > actionList; QAction *action = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::CreateCollection ); if ( action && action->isEnabled() ) { actionList << action; } action = mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::MoveCollectionToMenu ); if ( action && action->isEnabled() ) { actionList <action( Akonadi::StandardActionManager::CopyCollectionToMenu); if ( action && action->isEnabled() ) { actionList <unplugActionList( QLatin1String("akonadi_collection_move_copy_menu_actionlist") ); mGUIClient->plugActionList( QLatin1String("akonadi_collection_move_copy_menu_actionlist"), actionList ); } void KMMainWidget::updateHtmlMenuEntry() { if (mPreferHtmlAction && mPreferHtmlLoadExtAction) { bool multiFolder = false; if ( mFolderTreeWidget ) { multiFolder = mFolderTreeWidget->selectedCollections().count() > 1; } // the visual ones only make sense if we are showing a message list mPreferHtmlAction->setEnabled( mFolderTreeWidget && mFolderTreeWidget->folderTreeView()->currentFolder().isValid() && !multiFolder ); mPreferHtmlLoadExtAction->setEnabled( mFolderTreeWidget && mFolderTreeWidget->folderTreeView()->currentFolder().isValid() && !multiFolder && (mHtmlPref ? !mFolderHtmlPref : mFolderHtmlPref) ? true : false ); mPreferHtmlAction->setChecked( !multiFolder && ( mHtmlPref ? !mFolderHtmlPref : mFolderHtmlPref ) ); mPreferHtmlLoadExtAction->setChecked( !multiFolder && ( mHtmlLoadExtPref ? !mFolderHtmlLoadExtPref : mFolderHtmlLoadExtPref ) ); } } //----------------------------------------------------------------------------- void KMMainWidget::updateFolderMenu() { if (!CommonKernel->outboxCollectionFolder().isValid()) { QTimer::singleShot(1000,this,SLOT(updateFolderMenu())); return; } const bool folderWithContent = mCurrentFolder && !mCurrentFolder->isStructural(); bool multiFolder = false; if ( mFolderTreeWidget ) { multiFolder = mFolderTreeWidget->selectedCollections().count() > 1; } mFolderMailingListPropertiesAction->setEnabled( folderWithContent && !multiFolder && !mCurrentFolder->isSystemFolder() ); QList< QAction* > actionlist; if ( mCurrentFolder && mCurrentFolder->collection().id() == CommonKernel->outboxCollectionFolder().id() && (mCurrentFolder->collection()).statistics().count() > 0) { kDebug() << "Enabling send queued"; mSendQueued->setEnabled(true); actionlist << mSendQueued; } // if ( mCurrentFolder && mCurrentFolder->collection().id() != CommonKernel->trashCollectionFolder().id() ) { // actionlist << mTrashAction; // } mGUIClient->unplugActionList( QLatin1String( "outbox_folder_actionlist" ) ); mGUIClient->plugActionList( QLatin1String( "outbox_folder_actionlist" ), actionlist ); actionlist.clear(); const bool isASearchFolder = mCurrentFolder && mCurrentFolder->collection().resource() == QLatin1String( "akonadi_search_resource" ); if (isASearchFolder) mAkonadiStandardActionManager->action( Akonadi::StandardActionManager::DeleteCollections )->setText( i18n("&Delete Search") ); mArchiveFolderAction->setEnabled( mCurrentFolder && !multiFolder && folderWithContent ); bool isInTrashFolder = (mCurrentFolder && CommonKernel->folderIsTrash(mCurrentFolder->collection())); akonadiStandardAction( Akonadi::StandardMailActionManager::MoveToTrash )->setText( isInTrashFolder ? i18nc("@action Hard delete, bypassing trash", "&Delete"): i18n("&Move to Trash") ); mTrashThreadAction->setText(isInTrashFolder ?i18n("Delete T&hread"): i18n("M&ove Thread to Trash")); mExpireConfigAction->setEnabled( mCurrentFolder && !mCurrentFolder->isStructural() && !multiFolder && mCurrentFolder->canDeleteMessages() && folderWithContent && !MailCommon::Util::isVirtualCollection( mCurrentFolder->collection() ) ); updateHtmlMenuEntry(); mShowFolderShortcutDialogAction->setEnabled( !multiFolder && folderWithContent ); actionlist << akonadiStandardAction( Akonadi::StandardActionManager::ManageLocalSubscriptions ); bool imapFolderIsOnline = false; if (mCurrentFolder && kmkernel->isImapFolder( mCurrentFolder->collection(),imapFolderIsOnline )) { if (imapFolderIsOnline) { actionlist << mServerSideSubscription; } } mGUIClient->unplugActionList( QLatin1String( "collectionview_actionlist" ) ); mGUIClient->plugActionList( QLatin1String( "collectionview_actionlist" ), actionlist ); } //----------------------------------------------------------------------------- void KMMainWidget::slotIntro() { if ( !mMsgView ) return; mMsgView->clear( true ); mMsgView->displayAboutPage(); mCurrentFolder.clear(); } void KMMainWidget::slotShowStartupFolder() { connect( MailCommon::FilterManager::instance(), SIGNAL(filtersChanged()), this, SLOT(initializeFilterActions()) ); // Plug various action lists. This can't be done in the constructor, as that is called before // the main window or Kontact calls createGUI(). // This function however is called with a single shot timer. checkAkonadiServerManagerState(); mFolderShortcutActionManager->createActions(); mTagActionManager->createActions(); messageActions()->setupForwardingActionsList( mGUIClient ); QString newFeaturesMD5 = KMReaderWin::newFeaturesMD5(); if ( kmkernel->firstStart() || GlobalSettings::self()->previousNewFeaturesMD5() != newFeaturesMD5 ) { GlobalSettings::self()->setPreviousNewFeaturesMD5( newFeaturesMD5 ); slotIntro(); return; } } void KMMainWidget::checkAkonadiServerManagerState() { Akonadi::ServerManager::State state = Akonadi::ServerManager::self()->state(); if (state == Akonadi::ServerManager::Running) { initializeFilterActions(); } else { connect( Akonadi::ServerManager::self(), SIGNAL(stateChanged(Akonadi::ServerManager::State)), SLOT(slotServerStateChanged(Akonadi::ServerManager::State)) ); } } void KMMainWidget::slotServerStateChanged(Akonadi::ServerManager::State state) { if (state == Akonadi::ServerManager::Running) { initializeFilterActions(); disconnect( Akonadi::ServerManager::self(), SIGNAL(stateChanged(Akonadi::ServerManager::State))); } } void KMMainWidget::slotShowTip() { KTipDialog::showTip( this, QString(), true ); } QList KMMainWidget::actionCollections() const { return QList() << actionCollection(); } //----------------------------------------------------------------------------- void KMMainWidget::slotUpdateUndo() { if ( actionCollection()->action( QLatin1String("kmail_undo") ) ) { actionCollection()->action( QLatin1String("kmail_undo") )->setEnabled( kmkernel->undoStack()->size()>0 ); } } //----------------------------------------------------------------------------- void KMMainWidget::clearFilterActions() { if ( !mFilterTBarActions.isEmpty() ) if ( mGUIClient->factory() ) mGUIClient->unplugActionList( QLatin1String("toolbar_filter_actions") ); if ( !mFilterMenuActions.isEmpty() ) if ( mGUIClient->factory() ) mGUIClient->unplugActionList( QLatin1String("menu_filter_actions") ); foreach ( QAction *a, mFilterMenuActions ) actionCollection()->removeAction( a ); mApplyFilterActionsMenu->menu()->clear(); mFilterTBarActions.clear(); mFilterMenuActions.clear(); qDeleteAll( mFilterCommands ); mFilterCommands.clear(); } //----------------------------------------------------------------------------- void KMMainWidget::initializeFilterActions() { clearFilterActions(); mApplyFilterActionsMenu->menu()->addAction( mApplyAllFiltersAction ); bool addedSeparator = false; foreach ( MailFilter *filter, MailCommon::FilterManager::instance()->filters() ) { if ( !filter->isEmpty() && filter->configureShortcut() && filter->isEnabled() ) { QString filterName = QString::fromLatin1( "Filter %1").arg( filter->name() ); QString normalizedName = filterName.replace(QLatin1Char(' '), QLatin1Char('_')); if ( action( normalizedName ) ) { continue; } KMMetaFilterActionCommand *filterCommand = new KMMetaFilterActionCommand( filter->identifier(), this ); mFilterCommands.append( filterCommand ); QString displayText = i18n( "Filter %1", filter->name() ); QString icon = filter->icon(); if ( icon.isEmpty() ) { icon = QLatin1String("system-run"); } KAction *filterAction = new KAction( KIcon( icon ), displayText, actionCollection() ); filterAction->setIconText( filter->toolbarName() ); // The shortcut configuration is done in the filter dialog. // The shortcut set in the shortcut dialog would not be saved back to // the filter settings correctly. filterAction->setShortcutConfigurable( false ); actionCollection()->addAction( normalizedName, filterAction ); connect( filterAction, SIGNAL(triggered(bool)), filterCommand, SLOT(start()) ); filterAction->setShortcuts( filter->shortcut() ); if ( !addedSeparator ) { QAction *a = mApplyFilterActionsMenu->menu()->addSeparator(); mFilterMenuActions.append( a ); addedSeparator = true; } mApplyFilterActionsMenu->menu()->addAction( filterAction ); mFilterMenuActions.append( filterAction ); if ( filter->configureToolbar() ) { mFilterTBarActions.append( filterAction ); } } } if ( !mFilterMenuActions.isEmpty() && mGUIClient->factory() ) mGUIClient->plugActionList( QLatin1String("menu_filter_actions"), mFilterMenuActions ); if ( !mFilterTBarActions.isEmpty() && mGUIClient->factory() ) { mFilterTBarActions.prepend( mToolbarActionSeparator ); mGUIClient->plugActionList( QLatin1String("toolbar_filter_actions"), mFilterTBarActions ); } // Our filters have changed, now enable/disable them updateMessageActions(); } //----------------------------------------------------------------------------- void KMMainWidget::slotAntiSpamWizard() { AntiSpamWizard wiz( AntiSpamWizard::AntiSpam, this ); wiz.exec(); } //----------------------------------------------------------------------------- void KMMainWidget::slotAntiVirusWizard() { AntiSpamWizard wiz( AntiSpamWizard::AntiVirus, this); wiz.exec(); } //----------------------------------------------------------------------------- void KMMainWidget::slotAccountWizard() { KMail::Util::launchAccountWizard( this ); } void KMMainWidget::slotImportWizard() { const QString path = KStandardDirs::findExe( QLatin1String("importwizard" ) ); if ( !QProcess::startDetached( path ) ) KMessageBox::error( this, i18n( "Could not start the import wizard. " "Please check your installation." ), i18n( "Unable to start import wizard" ) ); } //----------------------------------------------------------------------------- void KMMainWidget::slotFilterLogViewer() { MailCommon::FilterManager::instance()->showFilterLogDialog( (qlonglong)winId() ); } //----------------------------------------------------------------------------- void KMMainWidget::updateFileMenu() { const bool isEmpty = MailCommon::Util::agentInstances().isEmpty(); actionCollection()->action(QLatin1String("check_mail"))->setEnabled( !isEmpty ); actionCollection()->action(QLatin1String("check_mail_in"))->setEnabled( !isEmpty ); } //----------------------------------------------------------------------------- const KMMainWidget::PtrList * KMMainWidget::mainWidgetList() { // better safe than sorry; check whether the global static has already been destroyed if ( theMainWidgetList.isDestroyed() ) { return 0; } return theMainWidgetList; } QSharedPointer KMMainWidget::currentFolder() const { return mCurrentFolder; } //----------------------------------------------------------------------------- QString KMMainWidget::overrideEncoding() const { if ( mMsgView ) return mMsgView->overrideEncoding(); else return MessageCore::GlobalSettings::self()->overrideCharacterEncoding(); } void KMMainWidget::showEvent( QShowEvent *event ) { QWidget::showEvent( event ); mWasEverShown = true; } void KMMainWidget::slotRequestFullSearchFromQuickSearch() { // First, open the search window. If we are currently on a search folder, // the search associated with that will be loaded. if ( !slotSearch() ) return; assert( mSearchWin ); // Now we look at the current state of the quick search, and if there's // something in there, we add the criteria to the existing search for // the search folder, if applicable, or make a new one from it. SearchPattern pattern; const QString searchString = mMessagePane->currentFilterSearchString(); if ( !searchString.isEmpty() ) pattern.append( SearchRule::createInstance( "", SearchRule::FuncContains, searchString ) ); #if 0 //PORT IT QList status = mMessagePane->currentFilterStatus(); if ( status.hasAttachment() ) { pattern.append( SearchRule::createInstance( "", SearchRule::FuncHasAttachment ) ); status.setHasAttachment( false ); } if ( !status.isOfUnknownStatus() ) { pattern.append( SearchRule::Ptr( new SearchRuleStatus( status ) ) ); } #endif if ( !pattern.isEmpty() ) mSearchWin->addRulesToSearchPattern( pattern ); } void KMMainWidget::updateVacationScriptStatus( bool active, const QString &serverName ) { mVacationScriptIndicator->setVacationScriptActive(active, serverName); mVacationIndicatorActive = mVacationScriptIndicator->hasVacationScriptActive(); } QWidget * KMMainWidget::vacationScriptIndicator() const { return mVacationScriptIndicator; } void KMMainWidget::updateVacationScriptStatus() { updateVacationScriptStatus( mVacationIndicatorActive ); } KMail::TagActionManager *KMMainWidget::tagActionManager() const { return mTagActionManager; } KMail::FolderShortcutActionManager *KMMainWidget::folderShortcutActionManager() const { return mFolderShortcutActionManager; } void KMMainWidget::slotMessageSelected(const Akonadi::Item &item) { delete mShowBusySplashTimer; mShowBusySplashTimer = 0; if ( mMsgView ) { // The current selection was cleared, so we'll remove the previously // selected message from the preview pane if ( !item.isValid() ) { mMsgView->clear(); } else { mShowBusySplashTimer = new QTimer( this ); mShowBusySplashTimer->setSingleShot( true ); connect( mShowBusySplashTimer, SIGNAL(timeout()), this, SLOT(slotShowBusySplash()) ); mShowBusySplashTimer->start( GlobalSettings::self()->folderLoadingTimeout() ); //TODO: check if we need a different timeout setting for this Akonadi::ItemFetchJob *itemFetchJob = MessageViewer::Viewer::createFetchJob( item ); const QString resource = mCurrentFolder->collection().resource(); itemFetchJob->setProperty( "_resource", QVariant::fromValue(resource) ); connect( itemFetchJob, SIGNAL(itemsReceived(Akonadi::Item::List)), SLOT(itemsReceived(Akonadi::Item::List)) ); connect( itemFetchJob, SIGNAL(result(KJob*)), SLOT(itemsFetchDone(KJob*)) ); } } } void KMMainWidget::itemsReceived(const Akonadi::Item::List &list ) { Q_ASSERT( list.size() == 1 ); delete mShowBusySplashTimer; mShowBusySplashTimer = 0; if ( !mMsgView ) return; Item item = list.first(); if ( mMessagePane ) { mMessagePane->show(); if ( mMessagePane->currentItem() != item ) { // The user has selected another email already, so don't render this one. // Mark it as read, though, if the user settings say so. if ( MessageViewer::GlobalSettings::self()->delayedMarkAsRead() && MessageViewer::GlobalSettings::self()->delayedMarkTime() == 0 ) { item.setFlag( Akonadi::MessageFlags::Seen ); Akonadi::ItemModifyJob *modifyJob = new Akonadi::ItemModifyJob( item, this ); modifyJob->disableRevisionCheck(); modifyJob->setIgnorePayload( true ); } return; } } mMsgView->setMessage( item ); // reset HTML override to the folder setting mMsgView->setHtmlOverride(mFolderHtmlPref); mMsgView->setHtmlLoadExtOverride(mFolderHtmlLoadExtPref); mMsgView->setDecryptMessageOverwrite( false ); mMsgActions->setCurrentMessage( item ); } void KMMainWidget::itemsFetchDone( KJob *job ) { delete mShowBusySplashTimer; mShowBusySplashTimer = 0; if ( job->error() ) { // Unfortunately job->error() is Job::Unknown in many cases. // (see JobPrivate::handleResponse in akonadi/job.cpp) // So we show the "offline" page after checking the resource status. kDebug() << job->error() << job->errorString(); const QString resource = job->property("_resource").toString(); const Akonadi::AgentInstance agentInstance = Akonadi::AgentManager::self()->instance( resource ); if ( !agentInstance.isOnline() ) { // The resource is offline if ( mMsgView ) { mMsgView->viewer()->enableMessageDisplay(); mMsgView->clear( true ); } mMessagePane->show(); if (kmkernel->isOffline()) showOfflinePage(); else showResourceOfflinePage(); } else { // Some other error BroadcastStatus::instance()->setStatusMsg( job->errorString() ); } } } KAction *KMMainWidget::akonadiStandardAction( Akonadi::StandardActionManager::Type type ) { return mAkonadiStandardActionManager->action( type ); } KAction *KMMainWidget::akonadiStandardAction( Akonadi::StandardMailActionManager::Type type ) { return mAkonadiStandardActionManager->action( type ); } void KMMainWidget::slotCollectionProperties() { showCollectionProperties( QString() ); } void KMMainWidget::showCollectionProperties( const QString &pageToShow ) { if ( !mCurrentFolder ) return; if ( Solid::Networking::status() == Solid::Networking::Unconnected ) { KMessageBox::information( this, i18n( "Network is unconnected. Folder information cannot be updated." ) ); showCollectionPropertiesContinued( pageToShow, QPointer() ); } else { const Akonadi::AgentInstance agentInstance = Akonadi::AgentManager::self()->instance( mCurrentFolder->collection().resource() ); bool isOnline = agentInstance.isOnline(); if (!isOnline) { showCollectionPropertiesContinued( pageToShow, QPointer() ); } else { QPointer progressItem( KPIM::ProgressManager::createProgressItem( i18n( "Retrieving folder properties" ) ) ); progressItem->setUsesBusyIndicator( true ); progressItem->setCryptoStatus(KPIM::ProgressItem::Unknown); Akonadi::CollectionAttributesSynchronizationJob *sync = new Akonadi::CollectionAttributesSynchronizationJob( mCurrentFolder->collection() ); sync->setProperty( "collectionId", mCurrentFolder->collection().id() ); sync->setProperty( "pageToShow", pageToShow ); // note for dialog later sync->setProperty( "progressItem", QVariant::fromValue( progressItem ) ); connect( sync, SIGNAL(result(KJob*)), this, SLOT(slotCollectionPropertiesContinued(KJob*)) ); connect( progressItem, SIGNAL(progressItemCanceled(KPIM::ProgressItem*)), sync, SLOT(kill()) ); connect( progressItem, SIGNAL(progressItemCanceled(KPIM::ProgressItem*)), KPIM::ProgressManager::instance(), SLOT(slotStandardCancelHandler(KPIM::ProgressItem*)) ); sync->start(); } } } void KMMainWidget::slotCollectionPropertiesContinued( KJob* job ) { QString pageToShow; QPointer progressItem; if ( job ) { Akonadi::CollectionAttributesSynchronizationJob *sync = dynamic_cast( job ); Q_ASSERT( sync ); if ( sync->property( "collectionId" ) != mCurrentFolder->collection().id() ) return; pageToShow = sync->property( "pageToShow" ).toString(); progressItem = sync->property( "progressItem" ).value< QPointer >(); if ( progressItem ) { disconnect( progressItem, SIGNAL(progressItemCanceled(KPIM::ProgressItem*)), sync, SLOT(kill()) ); } else { // progressItem does not exist anymore, operation has been canceled return; } } showCollectionPropertiesContinued( pageToShow, progressItem ); } void KMMainWidget::showCollectionPropertiesContinued( const QString &pageToShow, QPointer progressItem ) { if ( !progressItem ) { progressItem = KPIM::ProgressManager::createProgressItem( i18n( "Retrieving folder properties" ) ); progressItem->setUsesBusyIndicator( true ); progressItem->setCryptoStatus(KPIM::ProgressItem::Unknown); connect( progressItem, SIGNAL(progressItemCanceled(KPIM::ProgressItem*)), KPIM::ProgressManager::instance(), SLOT(slotStandardCancelHandler(KPIM::ProgressItem*)) ); } Akonadi::CollectionFetchJob *fetch = new Akonadi::CollectionFetchJob( mCurrentFolder->collection(), Akonadi::CollectionFetchJob::Base ); connect( progressItem, SIGNAL(progressItemCanceled(KPIM::ProgressItem*)), fetch, SLOT(kill()) ); fetch->fetchScope().setIncludeStatistics( true ); fetch->setProperty( "pageToShow", pageToShow ); fetch->setProperty( "progressItem", QVariant::fromValue( progressItem ) ); connect( fetch, SIGNAL(result(KJob*)), this, SLOT(slotCollectionPropertiesFinished(KJob*)) ); connect( progressItem, SIGNAL(progressItemCanceled(KPIM::ProgressItem*)), fetch, SLOT(kill()) ); } void KMMainWidget::slotCollectionPropertiesFinished( KJob *job ) { if ( !job ) return; QPointer progressItem = job->property( "progressItem" ).value< QPointer >(); // progressItem does not exist anymore, operation has been canceled if ( !progressItem ) { return; } progressItem->setComplete(); progressItem->setStatus( i18n( "Done" ) ); Akonadi::CollectionFetchJob *fetch = dynamic_cast( job ); Q_ASSERT( fetch ); if ( fetch->collections().isEmpty() ) { kWarning() << "no collection"; return; } const Akonadi::Collection collection = fetch->collections().first(); const QStringList pages = QStringList() << QLatin1String( "MailCommon::CollectionGeneralPage" ) << QLatin1String( "KMail::CollectionViewPage" ) << QLatin1String( "Akonadi::CachePolicyPage" ) << QLatin1String( "KMail::CollectionTemplatesPage" ) << QLatin1String( "MailCommon::CollectionExpiryPage" ) << QLatin1String( "PimCommon::CollectionAclPage" ) << QLatin1String( "KMail::CollectionMailingListPage" ) << QLatin1String( "KMail::CollectionQuotaPage" ) << QLatin1String( "KMail::CollectionShortcutPage" ) << QLatin1String( "KMail::CollectionMaintenancePage" ); Akonadi::CollectionPropertiesDialog *dlg = new Akonadi::CollectionPropertiesDialog( collection, pages, this ); dlg->setCaption( i18nc( "@title:window", "Properties of Folder %1", collection.name() ) ); const QString pageToShow = fetch->property( "pageToShow" ).toString(); if ( !pageToShow.isEmpty() ) { // show a specific page dlg->setCurrentPage( pageToShow ); } dlg->show(); } void KMMainWidget::slotRemoveDuplicates() { KPIM::ProgressItem *item = KPIM::ProgressManager::createProgressItem( i18n( "Removing duplicates" ) ); item->setUsesBusyIndicator( true ); item->setCryptoStatus(KPIM::ProgressItem::Unknown); QItemSelectionModel *selectionModel = mFolderTreeWidget->folderTreeView()->selectionModel(); QModelIndexList indexes = selectionModel->selectedIndexes(); Akonadi::Collection::List collections; Q_FOREACH (const QModelIndex &index, indexes) { Akonadi::Collection collection = index.data(Akonadi::EntityTreeModel::CollectionRole).value(); if ( collection.isValid() ) { collections << collection; } } Akonadi::RemoveDuplicatesJob *job = new RemoveDuplicatesJob( collections, this ); job->setProperty( "ProgressItem", QVariant::fromValue ( item ) ); item->setProperty( "RemoveDuplicatesJob", QVariant::fromValue( qobject_cast( job ) ) ); connect( job, SIGNAL(finished(KJob*)), this, SLOT(slotRemoveDuplicatesDone(KJob*)) ); connect( job, SIGNAL(description(KJob*,QString,QPair,QPair)), this, SLOT(slotRemoveDuplicatesUpdate(KJob*,QString)) ); connect( item, SIGNAL(progressItemCanceled(KPIM::ProgressItem*)), this, SLOT(slotRemoveDuplicatesCanceled(KPIM::ProgressItem*)) ); } void KMMainWidget::slotRemoveDuplicatesDone( KJob *job ) { if ( job->error() && job->error() != KJob::KilledJobError ) { KMessageBox::error( this, job->errorText(), i18n( "Error while removing duplicates" ) ); } KPIM::ProgressItem *item = job->property( "ProgressItem" ).value(); if ( item ) { item->setComplete(); item->setStatus( i18n( "Done" ) ); item = 0; } } void KMMainWidget::slotRemoveDuplicatesCanceled( KPIM::ProgressItem *item ) { Akonadi::Job *job = item->property( "RemoveDuplicatesJob" ).value(); if ( job ) { job->kill( KJob::Quietly ); } item->setComplete(); item = 0; } void KMMainWidget::slotRemoveDuplicatesUpdate( KJob* job, const QString& description ) { KPIM::ProgressItem *item = job->property( "ProgressItem" ).value(); if ( item ) { item->setStatus( description ); } } void KMMainWidget::slotServerSideSubscription() { if ( !mCurrentFolder ) return; bool isImapOnline = false; if ( kmkernel->isImapFolder( mCurrentFolder->collection(), isImapOnline ) ) { QDBusInterface iface( QLatin1String( "org.freedesktop.Akonadi.Resource.")+mCurrentFolder->collection().resource(), QLatin1String( "/" ), QLatin1String( "org.kde.Akonadi.ImapResourceBase" ), DBusConnectionPool::threadConnection(), this ); if ( !iface.isValid() ) { kDebug()<<"Cannot create imap dbus interface"; return; } QDBusPendingCall call = iface.asyncCall( QLatin1String( "configureSubscription" ), (qlonglong)winId() ); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(slotConfigureSubscriptionFinished(QDBusPendingCallWatcher*))); } } void KMMainWidget::slotConfigureSubscriptionFinished(QDBusPendingCallWatcher* watcher) { QDBusPendingReply reply = *watcher; if ( !reply.isValid() ) { return; } if (reply == -2 ){ KMessageBox::error(this,i18n("IMAP server not configured yet. Please configure the server in the IMAP account before setting up server-side subscription.")); } else if (reply == -1) { KMessageBox::error(this,i18n("Log in failed, please configure the IMAP account before setting up server-side subscription.")); } watcher->deleteLater(); } void KMMainWidget::savePaneSelection() { if (mMessagePane) { mMessagePane->saveCurrentSelection(); } } void KMMainWidget::slotConfigureAutomaticArchiving() { OrgFreedesktopAkonadiArchiveMailAgentInterface archiveMailInterface(QLatin1String("org.freedesktop.Akonadi.ArchiveMailAgent"), QLatin1String("/ArchiveMailAgent"),QDBusConnection::sessionBus(), this); if (archiveMailInterface.isValid()) { archiveMailInterface.showConfigureDialog( (qlonglong)winId() ); } else { KMessageBox::error(this,i18n("Archive Mail Agent was not registered.")); } } void KMMainWidget::slotConfigureSendLater() { OrgFreedesktopAkonadiSendLaterAgentInterface sendLaterInterface(QLatin1String("org.freedesktop.Akonadi.SendLaterAgent"), QLatin1String("/SendLaterAgent"),QDBusConnection::sessionBus(), this); if (sendLaterInterface.isValid()) { sendLaterInterface.showConfigureDialog( (qlonglong)winId() ); } else { KMessageBox::error(this,i18n("Send Later Agent was not registered.")); } } void KMMainWidget::updatePaneTagComboBox() { if (mMessagePane) { mMessagePane->updateTagComboBox(); } } void KMMainWidget::slotExportData() { const QString path = KStandardDirs::findExe( QLatin1String("pimsettingexporter" ) ); if ( !QProcess::startDetached( path ) ) KMessageBox::error( this, i18n( "Could not start \"PIM Setting Exporter\" program. " "Please check your installation." ), i18n( "Unable to start \"PIM Setting Exporter\" program" ) ); } void KMMainWidget::slotCreateAddressBookContact() { CreateNewContactJob *job = new CreateNewContactJob( this, this ); job->start(); } void KMMainWidget::slotOpenRecentMsg(const KUrl& url) { KMOpenMsgCommand *openCommand = new KMOpenMsgCommand( this, url, overrideEncoding(), this ); openCommand->start(); } void KMMainWidget::addRecentFile(const KUrl& mUrl) { mOpenRecentAction->addUrl(mUrl); KConfigGroup grp = mConfig->group(QLatin1String("Recent Files")); mOpenRecentAction->saveEntries(grp); grp.sync(); } void KMMainWidget::slotMoveMessageToTrash() { if (messageView() && messageView()->viewer()) { KMTrashMsgCommand *command = new KMTrashMsgCommand( mCurrentFolder->collection(), messageView()->viewer()->messageItem(), -1 ); command->start(); } } void KMMainWidget::slotArchiveMails() { const QList selectedMessages = mMessagePane->selectionAsMessageItemList(); KMKernel::self()->folderArchiveManager()->setArchiveItems(selectedMessages, mCurrentFolder->collection().resource()); } void KMMainWidget::updateQuickSearchLineText() { //If change change shortcut mMessagePane->setQuickSearchClickMessage(i18nc("Show shortcut for focus quick search. Don't change it", "Search...<%1>",mQuickSearchAction->shortcut().toString())); } diff --git a/kmail/kmreadermainwin.cpp b/kmail/kmreadermainwin.cpp index 684f35a488..ef9b98b9bc 100644 --- a/kmail/kmreadermainwin.cpp +++ b/kmail/kmreadermainwin.cpp @@ -1,634 +1,634 @@ /* This file is part of KMail, the KDE mail client. Copyright (c) 2002 Don Sanders Copyright (c) 2011 Montel Laurent KMail is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation. KMail is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ // // A toplevel KMainWindow derived class for displaying // single messages or single message parts. // // Could be extended to include support for normal main window // widgets like a toolbar. #include "kmreadermainwin.h" #include "kmreaderwin.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kmcommands.h" #include "kmenubar.h" #include "kmenu.h" #include "kmmainwidget.h" #include "messageviewer/viewer/csshelper.h" #include "customtemplatesmenu.h" #include "messageactions.h" #include "util.h" #include "kernel/mailkernel.h" #include "foldercollection.h" #include #include #include #include #include #include #include #include #include "messagecore/helpers/messagehelpers.h" #include using namespace MailCommon; KMReaderMainWin::KMReaderMainWin( bool htmlOverride, bool htmlLoadExtOverride, char *name ) : KMail::SecondaryWindow( name ? name : "readerwindow#" ) { mReaderWin = new KMReaderWin( this, this, actionCollection()); //mReaderWin->setShowCompleteMessage( true ); mReaderWin->setHtmlOverride( htmlOverride ); mReaderWin->setHtmlLoadExtOverride( htmlLoadExtOverride ); mReaderWin->setDecryptMessageOverwrite( true ); initKMReaderMainWin(); } //----------------------------------------------------------------------------- KMReaderMainWin::KMReaderMainWin( char *name ) : KMail::SecondaryWindow( name ? name : "readerwindow#" ) { mReaderWin = new KMReaderWin( this, this, actionCollection()); initKMReaderMainWin(); } //----------------------------------------------------------------------------- KMReaderMainWin::KMReaderMainWin(KMime::Content* aMsgPart, bool aHTML, const QString & encoding, char *name ) : KMail::SecondaryWindow( name ? name : "readerwindow#" ) { mReaderWin = new KMReaderWin( this, this, actionCollection() ); mReaderWin->setOverrideEncoding( encoding ); mReaderWin->setHtmlOverride( aHTML ); mReaderWin->setMsgPart( aMsgPart ); initKMReaderMainWin(); } //----------------------------------------------------------------------------- void KMReaderMainWin::initKMReaderMainWin() { setCentralWidget( mReaderWin ); setupAccel(); setupGUI( Keys | StatusBar | Create, QLatin1String("kmreadermainwin.rc") ); mMsgActions->setupForwardingActionsList( this ); applyMainWindowSettings( KMKernel::self()->config()->group( "Separate Reader Window" ) ); if( ! mReaderWin->message().isValid() ) { menuBar()->hide(); toolBar( QLatin1String("mainToolBar") )->hide(); } connect( kmkernel, SIGNAL(configChanged()), this, SLOT(slotConfigChanged()) ); connect( mReaderWin, SIGNAL(showStatusBarMessage(QString)), statusBar(), SLOT(showMessage(QString)) ); } //----------------------------------------------------------------------------- KMReaderMainWin::~KMReaderMainWin() { saveMainWindowSettings( KMKernel::self()->config()->group( "Separate Reader Window" ) ); } //----------------------------------------------------------------------------- void KMReaderMainWin::setUseFixedFont( bool useFixedFont ) { mReaderWin->setUseFixedFont( useFixedFont ); } void KMReaderMainWin::showMessage( const QString & encoding, const Akonadi::Item &msg, const Akonadi::Collection& parentCollection ) { mParentCollection = parentCollection; mReaderWin->setOverrideEncoding( encoding ); mReaderWin->setMessage( msg, MessageViewer::Viewer::Force ); KMime::Message::Ptr message = MessageCore::Util::message( msg ); QString caption; if ( message ) { caption = message->subject()->asUnicodeString(); } if(mParentCollection.isValid()) { caption += QLatin1String(" - "); caption += MailCommon::Util::fullCollectionPath( mParentCollection ); } if(!caption.isEmpty()) { setCaption(caption); } mMsg = msg; mMsgActions->setCurrentMessage( msg ); const bool canChange = mParentCollection.isValid() ? (bool)( mParentCollection.rights() & Akonadi::Collection::CanDeleteItem ) : false; mTrashAction->setEnabled( canChange ); menuBar()->show(); toolBar( QLatin1String("mainToolBar") )->show(); } void KMReaderMainWin::showMessage( const QString& encoding, KMime::Message::Ptr message ) { if ( !message ) return; Akonadi::Item item; item.setPayload( message ); item.setMimeType( KMime::Message::mimeType() ); mMsg = item; mMsgActions->setCurrentMessage( item ); mReaderWin->setOverrideEncoding( encoding ); mReaderWin->setMessage( message ); setCaption( message->subject()->asUnicodeString() ); mTrashAction->setEnabled( false ); menuBar()->show(); toolBar( QLatin1String("mainToolBar") )->show(); } void KMReaderMainWin::slotReplyOrForwardFinished() { if ( GlobalSettings::self()->closeAfterReplyOrForward() ) { close(); } } Akonadi::Collection KMReaderMainWin::parentCollection() const { if ( mParentCollection.isValid() ) return mParentCollection; else return mMsg.parentCollection(); } //----------------------------------------------------------------------------- void KMReaderMainWin::slotTrashMsg() { if ( !mMsg.isValid() ) return; KMTrashMsgCommand *command = new KMTrashMsgCommand( parentCollection(), mMsg, -1 ); command->start(); close(); } //----------------------------------------------------------------------------- void KMReaderMainWin::slotForwardInlineMsg() { if ( !mReaderWin->message().hasPayload() ) return; KMCommand *command = 0; const Akonadi::Collection parentCol = mReaderWin->message().parentCollection(); if ( parentCol.isValid() ) { QSharedPointer fd = FolderCollection::forCollection( parentCol, false ); if ( fd ) command = new KMForwardCommand( this, mReaderWin->message(), fd->identity() ); else command = new KMForwardCommand( this, mReaderWin->message() ); } else { command = new KMForwardCommand( this, mReaderWin->message() ); } connect( command, SIGNAL(completed(KMCommand*)), this, SLOT(slotReplyOrForwardFinished()) ); command->start(); } //----------------------------------------------------------------------------- void KMReaderMainWin::slotForwardAttachedMsg() { if ( !mReaderWin->message().hasPayload() ) return; KMCommand *command = 0; const Akonadi::Collection parentCol = mReaderWin->message().parentCollection(); if ( parentCol.isValid() ) { QSharedPointer fd = FolderCollection::forCollection( parentCol, false ); if ( fd ) command = new KMForwardAttachedCommand( this, mReaderWin->message(), fd->identity() ); else command = new KMForwardAttachedCommand( this, mReaderWin->message() ); } else command = new KMForwardAttachedCommand( this, mReaderWin->message() ); connect( command, SIGNAL(completed(KMCommand*)), this, SLOT(slotReplyOrForwardFinished()) ); command->start(); } //----------------------------------------------------------------------------- void KMReaderMainWin::slotRedirectMsg() { if ( !mReaderWin->message().hasPayload() ) return; KMCommand *command = new KMRedirectCommand( this, mReaderWin->message() ); connect( command, SIGNAL(completed(KMCommand*)), this, SLOT(slotReplyOrForwardFinished()) ); command->start(); } //----------------------------------------------------------------------------- void KMReaderMainWin::slotCustomReplyToMsg( const QString &tmpl ) { if ( !mReaderWin->message().hasPayload() ) return; KMCommand *command = new KMReplyCommand( this, mReaderWin->message(), MessageComposer::ReplySmart, mReaderWin->copyText(), false, tmpl ); connect( command, SIGNAL(completed(KMCommand*)), this, SLOT(slotReplyOrForwardFinished()) ); command->start(); } //----------------------------------------------------------------------------- void KMReaderMainWin::slotCustomReplyAllToMsg( const QString &tmpl ) { if ( !mReaderWin->message().hasPayload() ) return; KMCommand *command = new KMReplyCommand( this, mReaderWin->message(), MessageComposer::ReplyAll, mReaderWin->copyText(), false, tmpl ); connect( command, SIGNAL(completed(KMCommand*)), this, SLOT(slotReplyOrForwardFinished()) ); command->start(); } //----------------------------------------------------------------------------- void KMReaderMainWin::slotCustomForwardMsg( const QString &tmpl) { if ( !mReaderWin->message().hasPayload() ) return; KMCommand *command = new KMForwardCommand( this, mReaderWin->message(), 0, tmpl ); connect( command, SIGNAL(completed(KMCommand*)), this, SLOT(slotReplyOrForwardFinished()) ); command->start(); } //----------------------------------------------------------------------------- void KMReaderMainWin::slotConfigChanged() { //readConfig(); mMsgActions->setupForwardActions(); mMsgActions->setupForwardingActionsList( this ); } void KMReaderMainWin::setupAccel() { if ( kmkernel->xmlGuiInstance().isValid() ) setComponentData( kmkernel->xmlGuiInstance() ); mMsgActions = new KMail::MessageActions( actionCollection(), this ); mMsgActions->setMessageView( mReaderWin ); connect( mMsgActions, SIGNAL(replyActionFinished()), this, SLOT(slotReplyOrForwardFinished()) ); //----- File Menu mSaveAtmAction = new KAction(KIcon(QLatin1String("mail-attachment")), i18n("Save A&ttachments..."), actionCollection() ); connect( mSaveAtmAction, SIGNAL(triggered(bool)), mReaderWin->viewer(), SLOT(slotAttachmentSaveAll()) ); mTrashAction = new KAction( KIcon( QLatin1String("user-trash") ), i18n("&Move to Trash"), this ); mTrashAction->setIconText( i18nc( "@action:intoolbar Move to Trash", "Trash" ) ); mTrashAction->setHelpText( i18n( "Move message to trashcan" ) ); mTrashAction->setShortcut( QKeySequence( Qt::Key_Delete ) ); actionCollection()->addAction( QLatin1String("move_to_trash"), mTrashAction ); connect( mTrashAction, SIGNAL(triggered()), this, SLOT(slotTrashMsg()) ); KAction *closeAction = KStandardAction::close( this, SLOT(close()), actionCollection() ); KShortcut closeShortcut = KShortcut(closeAction->shortcuts()); closeShortcut.setAlternate( QKeySequence(Qt::Key_Escape)); closeAction->setShortcuts(closeShortcut); //----- Message Menu mFontAction = new KFontAction( i18n("Select Font"), this ); actionCollection()->addAction( QLatin1String("text_font"), mFontAction ); mFontAction->setFont( mReaderWin->cssHelper()->bodyFont().family() ); connect( mFontAction, SIGNAL(triggered(QString)), SLOT(slotFontAction(QString)) ); mFontSizeAction = new KFontSizeAction( i18n( "Select Size" ), this ); mFontSizeAction->setFontSize( mReaderWin->cssHelper()->bodyFont().pointSize() ); actionCollection()->addAction( QLatin1String("text_size"), mFontSizeAction ); connect( mFontSizeAction, SIGNAL(fontSizeChanged(int)), SLOT(slotSizeAction(int)) ); connect( mReaderWin->viewer(), SIGNAL(popupMenu(Akonadi::Item,KUrl,KUrl,QPoint)), this, SLOT(slotMessagePopup(Akonadi::Item,KUrl,KUrl,QPoint)) ); connect( mReaderWin->viewer(), SIGNAL(itemRemoved()), this, SLOT(close()) ); setStandardToolBarMenuEnabled(true); KStandardAction::configureToolbars(this, SLOT(slotEditToolbars()), actionCollection()); connect( mReaderWin->viewer(), SIGNAL(moveMessageToTrash()), this, SLOT(slotTrashMsg()) ); } //----------------------------------------------------------------------------- KAction *KMReaderMainWin::copyActionMenu(QMenu *menu) { KMMainWidget* mainwin = kmkernel->getKMMainWidget(); if ( mainwin ) { KActionMenu *action = new KActionMenu( menu ); action->setIcon( KIcon( QLatin1String("edit-copy")) ); action->setText( i18n("Copy Item To...") ); mainwin->standardMailActionManager()->standardActionManager()->createActionFolderMenu( action->menu(), Akonadi::StandardActionManager::CopyItemToMenu ); connect( action->menu(), SIGNAL(triggered(QAction*)), SLOT(slotCopyItem(QAction*)) ); return action; } return 0; } void KMReaderMainWin::slotCopyItem(QAction*action) { if ( action ) { const QModelIndex index = action->data().value(); const Akonadi::Collection collection = index.data( Akonadi::EntityTreeModel::CollectionRole ).value(); if ( mMsg.isValid() ) { Akonadi::ItemCopyJob *job = new Akonadi::ItemCopyJob( mMsg, collection,this ); connect( job, SIGNAL(result(KJob*)), this, SLOT(slotCopyResult(KJob*)) ); } else { Akonadi::ItemCreateJob *job = new Akonadi::ItemCreateJob( mMsg, collection, this ); connect( job, SIGNAL(result(KJob*)), this, SLOT(slotCopyResult(KJob*)) ); } } } void KMReaderMainWin::slotCopyResult( KJob * job ) { if ( job->error() ) { KMessageBox::sorry( this, i18n("Cannot copy item. %1", job->errorString() ) ); } } void KMReaderMainWin::slotMessagePopup(const Akonadi::Item&aMsg , const KUrl&aUrl, const KUrl&imageUrl, const QPoint& aPoint) { mMsg = aMsg; const QString email = KPIMUtils::firstEmailAddress( aUrl.path() ).toLower(); if ( aUrl.protocol() == QLatin1String("mailto") && !email.isEmpty()) { Akonadi::ContactSearchJob *job = new Akonadi::ContactSearchJob( this ); job->setLimit( 1 ); job->setQuery( Akonadi::ContactSearchJob::Email, email, Akonadi::ContactSearchJob::ExactMatch ); job->setProperty( "msg", QVariant::fromValue( mMsg ) ); job->setProperty( "point", aPoint ); job->setProperty( "imageUrl", imageUrl ); job->setProperty( "url", aUrl ); connect( job, SIGNAL(result(KJob*)), SLOT(slotContactSearchJobForMessagePopupDone(KJob*)) ); } else { showMessagePopup(mMsg, aUrl, imageUrl, aPoint, false, false); } } void KMReaderMainWin::slotContactSearchJobForMessagePopupDone( KJob *job ) { const Akonadi::ContactSearchJob *searchJob = qobject_cast( job ); const bool contactAlreadyExists = !searchJob->contacts().isEmpty(); const QList listContact = searchJob->items(); const bool uniqueContactFound = (listContact.count() == 1); if(uniqueContactFound) { mReaderWin->setContactItem(listContact.first(), searchJob->contacts().at(0)); } else { mReaderWin->clearContactItem(); } const Akonadi::Item msg = job->property( "msg" ).value(); const QPoint aPoint = job->property( "point" ).toPoint(); const KUrl imageUrl = job->property("imageUrl").value(); const KUrl url = job->property("url").value(); showMessagePopup(msg, url, imageUrl, aPoint, contactAlreadyExists, uniqueContactFound); } void KMReaderMainWin::showMessagePopup(const Akonadi::Item&msg ,const KUrl&url,const KUrl &imageUrl,const QPoint& aPoint, bool contactAlreadyExists, bool uniqueContactFound) { KMenu *menu = 0; bool urlMenuAdded = false; bool copyAdded = false; const bool messageHasPayload = msg.hasPayload(); if ( !url.isEmpty() ) { if ( url.protocol() == QLatin1String( "mailto" ) ) { // popup on a mailto URL menu = new KMenu; menu->addAction( mReaderWin->mailToComposeAction() ); if ( messageHasPayload ) { menu->addAction( mReaderWin->mailToReplyAction() ); menu->addAction( mReaderWin->mailToForwardAction() ); menu->addSeparator(); } if ( contactAlreadyExists ) { if(uniqueContactFound) { menu->addAction( mReaderWin->editContactAction() ); } else { menu->addAction( mReaderWin->openAddrBookAction() ); } } else { menu->addAction( mReaderWin->addAddrBookAction() ); menu->addAction( mReaderWin->addToExistingContactAction() ); } menu->addSeparator(); menu->addMenu(mReaderWin->viewHtmlOption()); menu->addSeparator(); menu->addAction( mReaderWin->copyURLAction() ); copyAdded = true; urlMenuAdded = true; } else if( url.protocol() != QLatin1String( "attachment" ) ){ // popup on a not-mailto URL if(!menu) menu = new KMenu; menu->addAction( mReaderWin->urlOpenAction() ); menu->addAction( mReaderWin->addBookmarksAction() ); menu->addAction( mReaderWin->urlSaveAsAction() ); menu->addAction( mReaderWin->copyURLAction() ); if (mReaderWin->isAShortUrl(url)) { menu->addSeparator(); menu->addAction( mReaderWin->expandShortUrlAction() ); } if(!imageUrl.isEmpty()) { menu->addSeparator(); menu->addAction( mReaderWin->copyImageLocation()); menu->addAction(mReaderWin->downloadImageToDiskAction()); menu->addAction(mReaderWin->shareImage()); if (mReaderWin->adblockEnabled()) { menu->addSeparator(); menu->addAction( mReaderWin->blockImage()); } } urlMenuAdded = true; } } const QString selectedText(mReaderWin->copyText()); if ( !selectedText.isEmpty() ) { if(!menu) menu = new KMenu; if ( urlMenuAdded ) { menu->addSeparator(); } if(messageHasPayload) { menu->addAction( mMsgActions->replyMenu() ); menu->addSeparator(); } if( !copyAdded ) menu->addAction( mReaderWin->copyAction() ); menu->addAction( mReaderWin->selectAllAction() ); menu->addSeparator(); mMsgActions->addWebShortcutsMenu(menu,selectedText); menu->addSeparator(); menu->addAction(mReaderWin->translateAction()); menu->addSeparator(); menu->addAction( mReaderWin->speakTextAction()); } else if ( !urlMenuAdded ) { if(!menu) menu = new KMenu; // popup somewhere else (i.e., not a URL) on the message if (messageHasPayload) { bool replyForwardMenu = false; Akonadi::Collection col = parentCollection(); if ( col.isValid() ) { if ( ! ( CommonKernel->folderIsSentMailFolder( col ) || CommonKernel->folderIsDrafts( col ) || CommonKernel->folderIsTemplates( col ) ) ) { replyForwardMenu = true; } } else if ( messageHasPayload ) { replyForwardMenu = true; } if ( replyForwardMenu ) { // add the reply and forward actions only if we are not in a sent-mail, // templates or drafts folder menu->addAction( mMsgActions->replyMenu() ); menu->addAction( mMsgActions->forwardMenu() ); menu->addSeparator(); } menu->addAction( copyActionMenu(menu) ); menu->addSeparator(); if(!imageUrl.isEmpty()) { menu->addSeparator(); menu->addAction( mReaderWin->copyImageLocation()); menu->addAction( mReaderWin->downloadImageToDiskAction()); menu->addAction( mReaderWin->shareImage()); menu->addSeparator(); if (mReaderWin->adblockEnabled()) { menu->addAction( mReaderWin->blockImage()); menu->addSeparator(); } } menu->addAction( mReaderWin->viewSourceAction() ); menu->addAction( mReaderWin->toggleFixFontAction() ); menu->addAction( mReaderWin->toggleMimePartTreeAction() ); menu->addSeparator(); menu->addAction( mMsgActions->printPreviewAction() ); menu->addAction( mMsgActions->printAction() ); menu->addAction( mReaderWin->saveAsAction() ); menu->addAction( mSaveAtmAction ); if ( msg.isValid() ) { menu->addSeparator(); - menu->addAction( mReaderWin->createTodoAction() ); + // menu->addAction( mReaderWin->createTodoAction() ); menu->addAction( mReaderWin->createEventAction() ); - menu->addAction( mReaderWin->createNoteAction() ); + // menu->addAction( mReaderWin->createNoteAction() ); menu->addSeparator(); menu->addAction( mReaderWin->saveMessageDisplayFormatAction() ); menu->addAction( mReaderWin->resetMessageDisplayFormatAction() ); } } else { menu->addAction( mReaderWin->toggleFixFontAction() ); menu->addAction( mReaderWin->toggleMimePartTreeAction() ); } if (mReaderWin->adblockEnabled()) { menu->addSeparator(); menu->addAction( mReaderWin->openBlockableItems()); } } if (menu) { KAcceleratorManager::manage(menu); menu->exec( aPoint, 0 ); delete menu; } } void KMReaderMainWin::slotFontAction( const QString& font) { QFont f( mReaderWin->cssHelper()->bodyFont() ); f.setFamily( font ); mReaderWin->cssHelper()->setBodyFont( f ); mReaderWin->cssHelper()->setPrintFont( f ); mReaderWin->update(); } void KMReaderMainWin::slotSizeAction( int size ) { QFont f( mReaderWin->cssHelper()->bodyFont() ); f.setPointSize( size ); mReaderWin->cssHelper()->setBodyFont( f ); mReaderWin->cssHelper()->setPrintFont( f ); mReaderWin->update(); } void KMReaderMainWin::slotEditToolbars() { saveMainWindowSettings( KConfigGroup(KMKernel::self()->config(), "ReaderWindow") ); KEditToolBar dlg( guiFactory(), this ); connect( &dlg, SIGNAL(newToolBarConfig()), SLOT(slotUpdateToolbars()) ); dlg.exec(); } void KMReaderMainWin::slotUpdateToolbars() { createGUI(QLatin1String("kmreadermainwin.rc")); applyMainWindowSettings( KConfigGroup(KMKernel::self()->config(), "ReaderWindow") ); } diff --git a/kmail/kmreaderwin.cpp b/kmail/kmreaderwin.cpp index 9c2043b77f..858aa70ddb 100644 --- a/kmail/kmreaderwin.cpp +++ b/kmail/kmreaderwin.cpp @@ -1,931 +1,931 @@ /* -*- mode: C++; c-file-style: "gnu" -*- This file is part of KMail, the KDE mail client. Copyright (c) 1997 Markus Wuebben Copyright (c) 2009 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // define this to copy all html that is written to the readerwindow to // filehtmlwriter.out in the current working directory #include "kmreaderwin.h" #include "settings/globalsettings.h" #include "kmmainwidget.h" #include "kmreadermainwin.h" #include "kernel/mailkernel.h" #include "dialog/addemailtoexistingcontactdialog.h" #include "job/addemailtoexistingcontactjob.h" #include "kdepim-version.h" #include #include #include #include #include #include "kmcommands.h" #include "mailcommon/mdn/sendmdnhandler.h" #include #include "messageviewer/header/headerstrategy.h" #include "messageviewer/header/headerstyle.h" #include "messageviewer/viewer/mailwebview.h" #include "messageviewer/utils/markmessagereadhandler.h" #include "messageviewer/settings/globalsettings.h" #include "messageviewer/viewer/csshelper.h" using MessageViewer::CSSHelper; #include "util.h" #include "utils/stringutil.h" #include #include "messageviewer/viewer/viewer.h" using namespace MessageViewer; #include #include "messageviewer/viewer/attachmentstrategy.h" #include "messagecomposer/sender/messagesender.h" #include "messagecomposer/helper/messagefactory.h" #include "messagecomposer/composer/composer.h" #include "messagecomposer/part/textpart.h" #include "messagecomposer/part/infopart.h" #include using MessageComposer::MessageFactory; #include "messagecore/helpers/messagehelpers.h" #include #include #include #include #include #include #include #include #include #include #include #include #include // X headers... #undef Never #undef Always #include #include #include #include #include #include #include using namespace KMail; using namespace MailCommon; //----------------------------------------------------------------------------- KMReaderWin::KMReaderWin(QWidget *aParent, QWidget *mainWindow, KActionCollection* actionCollection, Qt::WindowFlags aFlags ) : QWidget(aParent, aFlags ), mMainWindow( mainWindow ), mActionCollection( actionCollection ), mMailToComposeAction( 0 ), mMailToReplyAction( 0 ), mMailToForwardAction( 0 ), mAddAddrBookAction( 0 ), mOpenAddrBookAction( 0 ), mUrlSaveAsAction( 0 ), mAddBookmarksAction( 0 ), mAddEmailToExistingContactAction( 0 ) { createActions(); QVBoxLayout * vlay = new QVBoxLayout( this ); vlay->setMargin( 0 ); mViewer = new Viewer( this, mainWindow, mActionCollection ); mViewer->setExternalWindow( true ); mViewer->setAppName( QLatin1String("KMail") ); connect( mViewer, SIGNAL(urlClicked(Akonadi::Item,KUrl)), this, SLOT(slotUrlClicked(Akonadi::Item,KUrl)) ); connect( mViewer, SIGNAL(requestConfigSync()), kmkernel, SLOT(slotRequestConfigSync()), Qt::QueuedConnection ); // happens anyway on shutdown, so we can skip it there with using a queued connection connect( mViewer, SIGNAL(makeResourceOnline(MessageViewer::Viewer::ResourceOnlineMode)), kmkernel, SLOT(makeResourceOnline(MessageViewer::Viewer::ResourceOnlineMode))); connect( mViewer, SIGNAL(showReader(KMime::Content*,bool,QString)), this, SLOT(slotShowReader(KMime::Content*,bool,QString)) ); connect( mViewer, SIGNAL(showMessage(KMime::Message::Ptr,QString)), this, SLOT(slotShowMessage(KMime::Message::Ptr,QString)) ); connect( mViewer, SIGNAL(showStatusBarMessage(QString)), this, SIGNAL(showStatusBarMessage(QString)) ); connect( mViewer, SIGNAL(deleteMessage(Akonadi::Item)), this, SLOT(slotDeleteMessage(Akonadi::Item)) ); mViewer->addMessageLoadedHandler( new MessageViewer::MarkMessageReadHandler( this ) ); mViewer->addMessageLoadedHandler( new MailCommon::SendMdnHandler( kmkernel, this ) ); vlay->addWidget( mViewer ); readConfig(); } void KMReaderWin::createActions() { KActionCollection *ac = mActionCollection; if ( !ac ) { return; } // // Message Menu // // new message to mMailToComposeAction = new KAction( KIcon( QLatin1String("mail-message-new") ), i18n( "New Message To..." ), this ); ac->addAction(QLatin1String("mail_new"), mMailToComposeAction ); mMailToComposeAction->setShortcutConfigurable( false ); connect( mMailToComposeAction, SIGNAL(triggered(bool)), SLOT(slotMailtoCompose()) ); // reply to mMailToReplyAction = new KAction( KIcon( QLatin1String("mail-reply-sender") ), i18n( "Reply To..." ), this ); ac->addAction( QLatin1String("mailto_reply"), mMailToReplyAction ); mMailToReplyAction->setShortcutConfigurable( false ); connect( mMailToReplyAction, SIGNAL(triggered(bool)), SLOT(slotMailtoReply()) ); // forward to mMailToForwardAction = new KAction( KIcon( QLatin1String("mail-forward" )), i18n( "Forward To..." ), this ); mMailToForwardAction->setShortcutConfigurable( false ); ac->addAction( QLatin1String("mailto_forward"), mMailToForwardAction ); connect( mMailToForwardAction, SIGNAL(triggered(bool)), SLOT(slotMailtoForward()) ); // add to addressbook mAddAddrBookAction = new KAction( KIcon(QLatin1String( "contact-new") ), i18n( "Add to Address Book" ), this ); mAddAddrBookAction->setShortcutConfigurable( false ); ac->addAction( QLatin1String("add_addr_book"), mAddAddrBookAction ); connect( mAddAddrBookAction, SIGNAL(triggered(bool)), SLOT(slotMailtoAddAddrBook()) ); mAddEmailToExistingContactAction = new KAction( KIcon(QLatin1String( "contact-new") ), i18n( "Add to Existing Contact" ), this ); mAddEmailToExistingContactAction->setShortcutConfigurable( false ); ac->addAction( QLatin1String("add_to_existing_contact"), mAddAddrBookAction ); connect( mAddEmailToExistingContactAction, SIGNAL(triggered(bool)), SLOT(slotMailToAddToExistingContact()) ); // open in addressbook mOpenAddrBookAction = new KAction( KIcon( QLatin1String("view-pim-contacts") ), i18n( "Open in Address Book" ), this ); mOpenAddrBookAction->setShortcutConfigurable( false ); ac->addAction( QLatin1String("openin_addr_book"), mOpenAddrBookAction ); connect( mOpenAddrBookAction, SIGNAL(triggered(bool)), SLOT(slotMailtoOpenAddrBook()) ); // bookmark message mAddBookmarksAction = new KAction( KIcon( QLatin1String("bookmark-new") ), i18n( "Bookmark This Link" ), this ); mAddBookmarksAction->setShortcutConfigurable( false ); ac->addAction( QLatin1String("add_bookmarks"), mAddBookmarksAction ); connect( mAddBookmarksAction, SIGNAL(triggered(bool)), SLOT(slotAddBookmarks()) ); mEditContactAction = new KAction( KIcon( QLatin1String("view-pim-contacts") ), i18n( "Edit contact..." ), this ); mEditContactAction->setShortcutConfigurable( false ); ac->addAction( QLatin1String("edit_contact"), mOpenAddrBookAction ); connect( mEditContactAction, SIGNAL(triggered(bool)), SLOT(slotEditContact()) ); // save URL as mUrlSaveAsAction = new KAction( i18n( "Save Link As..." ), this ); ac->addAction( QLatin1String("saveas_url"), mUrlSaveAsAction ); mUrlSaveAsAction->setShortcutConfigurable( false ); connect( mUrlSaveAsAction, SIGNAL(triggered(bool)), SLOT(slotUrlSave()) ); // find text KAction *action = new KAction(KIcon(QLatin1String("edit-find")), i18n("&Find in Message..."), this); ac->addAction(QLatin1String("find_in_messages"), action ); connect(action, SIGNAL(triggered(bool)), SLOT(slotFind())); action->setShortcut(KStandardShortcut::find()); // save Image On Disk mImageUrlSaveAsAction = new KAction( i18n( "Save Image On Disk..." ), this ); ac->addAction( QLatin1String("saveas_imageurl"), mImageUrlSaveAsAction ); mImageUrlSaveAsAction->setShortcutConfigurable( false ); connect( mImageUrlSaveAsAction, SIGNAL(triggered(bool)), SLOT(slotSaveImageOnDisk()) ); // View html options mViewHtmlOptions = new KMenu(i18n("Show HTML Format")); mViewAsHtml = new KAction( i18n("Show HTML format when mail comes from this contact"), mViewHtmlOptions); mViewAsHtml->setShortcutConfigurable( false ); connect( mViewAsHtml, SIGNAL(triggered(bool)), SLOT(slotContactHtmlOptions())); mViewAsHtml->setCheckable(true); mViewHtmlOptions->addAction(mViewAsHtml); mLoadExternalReference = new KAction( i18n("Load external reference when mail comes for this contact"), mViewHtmlOptions); mLoadExternalReference->setShortcutConfigurable( false ); connect(mLoadExternalReference, SIGNAL(triggered(bool)), SLOT(slotContactHtmlOptions())); mLoadExternalReference->setCheckable(true); mViewHtmlOptions->addAction(mLoadExternalReference); mShareImage = new KAction(i18n("Share image..."), this); ac->addAction( QLatin1String("share_imageurl"), mShareImage ); mShareImage->setShortcutConfigurable( false ); connect(mShareImage, SIGNAL(triggered(bool)), SLOT(slotShareImage())); } void KMReaderWin::setUseFixedFont( bool useFixedFont ) { mViewer->setUseFixedFont( useFixedFont ); } bool KMReaderWin::isFixedFont() const { return mViewer->isFixedFont(); } //----------------------------------------------------------------------------- KMReaderWin::~KMReaderWin() { } //----------------------------------------------------------------------------- void KMReaderWin::readConfig(void) { mViewer->readConfig(); } void KMReaderWin::setAttachmentStrategy( const AttachmentStrategy * strategy ) { mViewer->setAttachmentStrategy( strategy ); } void KMReaderWin::setHeaderStyleAndStrategy( HeaderStyle * style, HeaderStrategy * strategy ) { mViewer->setHeaderStyleAndStrategy( style, strategy ); } //----------------------------------------------------------------------------- void KMReaderWin::setOverrideEncoding( const QString & encoding ) { mViewer->setOverrideEncoding( encoding ); } //----------------------------------------------------------------------------- void KMReaderWin::clearCache() { clear(); } // enter items for the "Important changes" list here: static const char * const kmailChanges[] = { I18N_NOOP( "KMail is now based on the Akonadi Personal Information Management framework, which brings many " "changes all around.") }; static const int numKMailChanges = sizeof kmailChanges / sizeof *kmailChanges; // enter items for the "new features" list here, so the main body of // the welcome page can be left untouched (probably much easier for // the translators). Note that the
  • ...
  • tags are added // automatically below: static const char * const kmailNewFeatures[] = { I18N_NOOP( "Push email (IMAP IDLE)" ), I18N_NOOP( "Improved virtual folders" ), I18N_NOOP( "Improved searches" ), I18N_NOOP( "Support for adding notes (annotations) to mails" ), I18N_NOOP( "Tag folders" ), I18N_NOOP( "Less GUI freezes, mail checks happen in the background" ) }; static const int numKMailNewFeatures = sizeof kmailNewFeatures / sizeof *kmailNewFeatures; //----------------------------------------------------------------------------- //static QString KMReaderWin::newFeaturesMD5() { QByteArray str; for ( int i = 0 ; i < numKMailChanges ; ++i ) str += kmailChanges[i]; for ( int i = 0 ; i < numKMailNewFeatures ; ++i ) str += kmailNewFeatures[i]; KMD5 md5( str ); return QLatin1String(md5.base64Digest()); } //----------------------------------------------------------------------------- void KMReaderWin::displaySplashPage( const QString &info ) { mViewer->displaySplashPage( info ); } void KMReaderWin::displayBusyPage() { const QString info = i18n( "

    Retrieving Folder Contents

    Please wait . . .

     " ); displaySplashPage( info ); } void KMReaderWin::displayOfflinePage() { const QString info = i18n( "

    Offline

    KMail is currently in offline mode. " "Click here to go online . . .

     " ); displaySplashPage( info ); } void KMReaderWin::displayResourceOfflinePage() { const QString info = i18n( "

    Offline

    Account is currently in offline mode. " "Click here to go online . . .

     " ); displaySplashPage( info ); } //----------------------------------------------------------------------------- void KMReaderWin::displayAboutPage() { KLocalizedString info = ki18nc("%1: KMail version; %2: help:// URL; " "%3: generated list of new features; " "%4: First-time user text (only shown on first start); " "%5: generated list of important changes; " "--- end of comment ---", "

    Welcome to KMail %1

    KMail is the email client by KDE. " "It is designed to be fully compatible with " "Internet mailing standards including MIME, SMTP, POP3, and IMAP." "

    \n" "
    • KMail has many powerful features which are described in the " "documentation
    • \n" "%5\n" // important changes "%3\n" // new features "%4\n" // first start info "

      We hope that you will enjoy KMail.

      \n" "

      Thank you,

      \n" "

          The KMail Team

      ") .subs( QLatin1String(KDEPIM_VERSION) ) .subs( QLatin1String("help:/kmail/index.html") ); if ( ( numKMailNewFeatures > 1 ) || ( numKMailNewFeatures == 1 && strlen(kmailNewFeatures[0]) > 0 ) ) { QString featuresText = i18n("

      Some of the new features in this release of KMail include " "(compared to KMail %1, which is part of KDE Software Compilation %2):

      \n", QLatin1String("1.13"), QLatin1String(KDE::versionString()) ); // prior KMail and KDE version featuresText += QLatin1String("
        \n"); for ( int i = 0 ; i < numKMailNewFeatures ; ++i ) featuresText += QLatin1String("
      • ") + i18n( kmailNewFeatures[i] ) + QLatin1String("
      • \n"); featuresText += QLatin1String("
      \n"); info = info.subs( featuresText ); } else info = info.subs( QString() ); // remove the place holder if( kmkernel->firstStart() ) { info = info.subs( i18n("

      Please take a moment to fill in the KMail " "configuration panel at Settings->Configure " "KMail.\n" "You need to create at least a default identity and " "an incoming as well as outgoing mail account." "

      \n") ); } else { info = info.subs( QString() ); // remove the place holder } if ( ( numKMailChanges > 1 ) || ( numKMailChanges == 1 && strlen(kmailChanges[0]) > 0 ) ) { QString changesText = i18n("

      " "Important changes (compared to KMail %1):

      \n", QLatin1String("1.13")); changesText += QLatin1String("
        \n"); for ( int i = 0 ; i < numKMailChanges ; ++i ) changesText += i18n("
      • %1
      • \n", i18n( kmailChanges[i] ) ); changesText += QLatin1String("
      \n"); info = info.subs( changesText ); } else info = info.subs( QString() ); // remove the place holder displaySplashPage( info.toString() ); } //----------------------------------------------------------------------------- void KMReaderWin::slotFind() { mViewer->slotFind(); } //----------------------------------------------------------------------------- void KMReaderWin::slotCopySelectedText() { QString selection = mViewer->selectedText(); selection.replace( QChar::Nbsp, QLatin1Char(' ') ); QApplication::clipboard()->setText( selection ); } //----------------------------------------------------------------------------- void KMReaderWin::setMsgPart( KMime::Content* aMsgPart ) { mViewer->setMessagePart( aMsgPart ); } //----------------------------------------------------------------------------- QString KMReaderWin::copyText() const { return mViewer->selectedText(); } //----------------------------------------------------------------------------- void KMReaderWin::setHtmlOverride( bool override ) { mViewer->setHtmlOverride( override ); } bool KMReaderWin::htmlOverride() const { return mViewer->htmlOverride(); } //----------------------------------------------------------------------------- void KMReaderWin::setHtmlLoadExtOverride( bool override ) { mViewer->setHtmlLoadExtOverride( override ); } //----------------------------------------------------------------------------- bool KMReaderWin::htmlMail() const { return mViewer->htmlMail(); } //----------------------------------------------------------------------------- bool KMReaderWin::htmlLoadExternal() { return mViewer->htmlLoadExternal(); } //----------------------------------------------------------------------------- Akonadi::Item KMReaderWin::message() const { return mViewer->messageItem(); } //----------------------------------------------------------------------------- void KMReaderWin::slotMailtoCompose() { KMCommand *command = new KMMailtoComposeCommand( urlClicked(), message() ); command->start(); } //----------------------------------------------------------------------------- void KMReaderWin::slotMailtoForward() { KMCommand *command = new KMMailtoForwardCommand( mMainWindow, urlClicked(), message() ); command->start(); } //----------------------------------------------------------------------------- void KMReaderWin::slotMailtoAddAddrBook() { const KUrl url = urlClicked(); if( url.isEmpty() ) return; const QString emailString = KPIMUtils::decodeMailtoUrl( url ); KPIM::AddEmailAddressJob *job = new KPIM::AddEmailAddressJob( emailString, mMainWindow, this ); job->start(); } void KMReaderWin::slotMailToAddToExistingContact() { const KUrl url = urlClicked(); if( url.isEmpty() ) return; const QString emailString = KPIMUtils::decodeMailtoUrl( url ); QPointer dlg = new AddEmailToExistingContactDialog(this); if (dlg->exec()) { Akonadi::Item item = dlg->selectedContact(); if (item.isValid()) { AddEmailToExistingContactJob *job = new AddEmailToExistingContactJob(item, emailString, this); job->start(); } } delete dlg; } //----------------------------------------------------------------------------- void KMReaderWin::slotMailtoOpenAddrBook() { const KUrl url = urlClicked(); if( url.isEmpty() ) return; const QString emailString = KPIMUtils::decodeMailtoUrl( url ).toLower(); KPIM::OpenEmailAddressJob *job = new KPIM::OpenEmailAddressJob( emailString, mMainWindow, this ); job->start(); } //----------------------------------------------------------------------------- void KMReaderWin::slotAddBookmarks() { const KUrl url = urlClicked(); if( url.isEmpty() ) return; KMCommand *command = new KMAddBookmarksCommand( url, this ); command->start(); } //----------------------------------------------------------------------------- void KMReaderWin::slotUrlSave() { const KUrl url = urlClicked(); if( url.isEmpty() ) return; KMCommand *command = new KMUrlSaveCommand( url, mMainWindow ); command->start(); } void KMReaderWin::slotSaveImageOnDisk() { const KUrl url = imageUrlClicked(); if( url.isEmpty() ) return; KMCommand *command = new KMUrlSaveCommand( url, mMainWindow ); command->start(); } //----------------------------------------------------------------------------- void KMReaderWin::slotMailtoReply() { KMCommand *command = new KMMailtoReplyCommand( mMainWindow, urlClicked(), message(), copyText() ); command->start(); } CSSHelper* KMReaderWin::cssHelper() const { return mViewer->cssHelper(); } bool KMReaderWin::htmlLoadExtOverride() const { return mViewer->htmlLoadExtOverride(); } void KMReaderWin::setDecryptMessageOverwrite( bool overwrite ) { mViewer->setDecryptMessageOverwrite( overwrite ); } const AttachmentStrategy * KMReaderWin::attachmentStrategy() const { return mViewer->attachmentStrategy(); } QString KMReaderWin::overrideEncoding() const { return mViewer->overrideEncoding(); } KToggleAction *KMReaderWin::toggleFixFontAction() const { return mViewer->toggleFixFontAction(); } KAction *KMReaderWin::toggleMimePartTreeAction() const { return mViewer->toggleMimePartTreeAction(); } KAction *KMReaderWin::selectAllAction() const { return mViewer->selectAllAction(); } const HeaderStrategy * KMReaderWin::headerStrategy() const { return mViewer->headerStrategy(); } HeaderStyle * KMReaderWin::headerStyle() const { return mViewer->headerStyle(); } KAction *KMReaderWin::copyURLAction() const { return mViewer->copyURLAction(); } KAction *KMReaderWin::copyImageLocation() const { return mViewer->copyImageLocation(); } KAction *KMReaderWin::copyAction() const { return mViewer->copyAction(); } KAction *KMReaderWin::viewSourceAction() const { return mViewer->viewSourceAction(); } KAction *KMReaderWin::saveAsAction() const { return mViewer->saveAsAction(); } KAction *KMReaderWin::findInMessageAction() const { return mViewer->findInMessageAction(); } KAction *KMReaderWin::urlOpenAction() const { return mViewer->urlOpenAction(); } void KMReaderWin::setPrinting(bool enable) { mViewer->setPrinting( enable ); } KAction* KMReaderWin::speakTextAction() const { return mViewer->speakTextAction(); } KAction* KMReaderWin::downloadImageToDiskAction() const { return mImageUrlSaveAsAction; } KAction* KMReaderWin::translateAction() const { return mViewer->translateAction(); } void KMReaderWin::clear(bool force ) { mViewer->clear( force ? Viewer::Force : Viewer::Delayed ); } void KMReaderWin::setMessage( const Akonadi::Item &item, Viewer::UpdateMode updateMode) { kDebug() << Q_FUNC_INFO << parentWidget(); mViewer->setMessageItem( item, updateMode ); } void KMReaderWin::setMessage( KMime::Message::Ptr message) { mViewer->setMessage( message ); } KUrl KMReaderWin::urlClicked() const { return mViewer->urlClicked(); } KUrl KMReaderWin::imageUrlClicked() const { return mViewer->imageUrlClicked(); } void KMReaderWin::update( bool force ) { mViewer->update( force ? Viewer::Force : Viewer::Delayed ); } void KMReaderWin::slotUrlClicked( const Akonadi::Item & item, const KUrl & url ) { if ( item.isValid() && item.parentCollection().isValid() ) { QSharedPointer fd = FolderCollection::forCollection( MailCommon::Util::updatedCollection( item.parentCollection() ), false ); KMail::Util::handleClickedURL( url, fd ); return; } //No folder so we can't have identity and template. KMail::Util::handleClickedURL( url ); } void KMReaderWin::slotShowReader( KMime::Content* msgPart, bool htmlMail, const QString &encoding ) { KMReaderMainWin *win = new KMReaderMainWin( msgPart, htmlMail, encoding ); win->show(); } void KMReaderWin::slotShowMessage( KMime::Message::Ptr message, const QString& encoding ) { KMReaderMainWin *win = new KMReaderMainWin(); win->showMessage( encoding, message ); win->show(); } void KMReaderWin::slotDeleteMessage(const Akonadi::Item& item) { if ( !item.isValid() ) return; KMTrashMsgCommand *command = new KMTrashMsgCommand( MailCommon::Util::parentCollectionFromItem(item), item, -1 ); command->start(); } bool KMReaderWin::printSelectedText(bool preview) { const QString str = mViewer->selectedText(); if(str.isEmpty()) return false; ::MessageComposer::Composer* composer = new ::MessageComposer::Composer; composer->textPart()->setCleanPlainText(str); composer->textPart()->setWrappedPlainText(str); KMime::Message::Ptr messagePtr = message().payload(); composer->infoPart()->setFrom(messagePtr->from()->asUnicodeString()); composer->infoPart()->setTo(QStringList()<to()->asUnicodeString()); composer->infoPart()->setCc(QStringList()<cc()->asUnicodeString()); composer->infoPart()->setSubject(messagePtr->subject()->asUnicodeString()); composer->setProperty("preview",preview); connect( composer, SIGNAL(result(KJob*)), this, SLOT(slotPrintComposeResult(KJob*)) ); composer->start(); return true; } void KMReaderWin::slotPrintComposeResult( KJob *job ) { const bool preview = job->property("preview").toBool(); Q_ASSERT( dynamic_cast< ::MessageComposer::Composer* >( job ) ); ::MessageComposer::Composer* composer = dynamic_cast< ::MessageComposer::Composer* >( job ); if( composer->error() == ::MessageComposer::Composer::NoError ) { Q_ASSERT( composer->resultMessages().size() == 1 ); Akonadi::Item printItem; printItem.setPayload( composer->resultMessages().first() ); const bool useFixedFont = MessageViewer::GlobalSettings::self()->useFixedFont(); const QString overrideEncoding = MessageCore::GlobalSettings::self()->overrideCharacterEncoding(); KMPrintCommand *command = new KMPrintCommand( this, printItem, mViewer->headerStyle(), mViewer->headerStrategy() , mViewer->htmlOverride(), mViewer->htmlLoadExternal() ,useFixedFont, overrideEncoding ); command->setPrintPreview( preview ); command->start(); } else { if ( static_cast(job)->ui() ) { static_cast(job)->ui()->showErrorMessage(); } else { kWarning() << "Composer for printing failed:" << composer->errorString(); } } } void KMReaderWin::clearContactItem() { mSearchedContact = Akonadi::Item(); mSearchedAddress = KABC::Addressee(); mLoadExternalReference->setChecked(false); mViewAsHtml->setChecked(false); } void KMReaderWin::setContactItem(const Akonadi::Item& contact, const KABC::Addressee &address) { mSearchedContact = contact; mSearchedAddress = address; updateHtmlActions(); } void KMReaderWin::updateHtmlActions() { if (!mSearchedContact.isValid()) { mLoadExternalReference->setChecked(false); mViewAsHtml->setChecked(false); } else { const QStringList customs = mSearchedAddress.customs(); Q_FOREACH ( const QString& custom, customs ) { if ( custom.contains(QLatin1String( "MailPreferedFormatting")) ) { const QString value = mSearchedAddress.custom( QLatin1String( "KADDRESSBOOK" ), QLatin1String( "MailPreferedFormatting" ) ); mViewAsHtml->setChecked(value == QLatin1String( "HTML" )); } else if ( custom.contains(QLatin1String( "MailAllowToRemoteContent")) ) { const QString value = mSearchedAddress.custom( QLatin1String( "KADDRESSBOOK" ), QLatin1String( "MailAllowToRemoteContent" ) ); mLoadExternalReference->setChecked(( value == QLatin1String( "TRUE" ) )); } } } } void KMReaderWin::slotContactHtmlOptions() { const KUrl url = urlClicked(); if( url.isEmpty() ) return; const QString emailString = KPIMUtils::decodeMailtoUrl( url ).toLower(); KPIM::AddEmailDiplayJob *job = new KPIM::AddEmailDiplayJob( emailString, mMainWindow, this ); job->setRemoteContent(mLoadExternalReference->isChecked()); job->setShowAsHTML(mViewAsHtml->isChecked()); job->setContact(mSearchedContact); job->start(); } void KMReaderWin::slotEditContact() { if( mSearchedContact.isValid() ) { QPointer dlg = new Akonadi::ContactEditorDialog( Akonadi::ContactEditorDialog::EditMode, this ); connect( dlg, SIGNAL(contactStored(Akonadi::Item)), this, SLOT(contactStored(Akonadi::Item)) ); connect( dlg, SIGNAL(error(QString)), this, SLOT(slotContactEditorError(QString)) ); dlg->setContact( mSearchedContact ); dlg->exec(); delete dlg; } } void KMReaderWin::slotContactEditorError(const QString &error) { KMessageBox::error(this, i18n("Contact cannot be stored: %1", error), i18n("Failed to store contact")); } void KMReaderWin::contactStored( const Akonadi::Item &item ) { Q_UNUSED( item ); KPIM::BroadcastStatus::instance()->setStatusMsg( i18n( "Contact modified successfully" ) ); } KAction *KMReaderWin::saveMessageDisplayFormatAction() const { return mViewer->saveMessageDisplayFormatAction(); } KAction *KMReaderWin::resetMessageDisplayFormatAction() const { return mViewer->resetMessageDisplayFormatAction(); } KAction *KMReaderWin::blockImage() const { return mViewer->blockImage(); } bool KMReaderWin::adblockEnabled() const { return mViewer->adblockEnabled(); } KAction *KMReaderWin::openBlockableItems() const { return mViewer->openBlockableItems(); } //----------------------------------------------------------------------------- void KMReaderWin::slotShareImage() { KMCommand *command = new KMShareImageCommand( imageUrlClicked(), this); command->start(); } bool KMReaderWin::isAShortUrl(const KUrl &url) const { return mViewer->isAShortUrl(url); } KAction *KMReaderWin::expandShortUrlAction() const { return mViewer->expandShortUrlAction(); } -KAction *KMReaderWin::createTodoAction() const -{ - return mViewer->createTodoAction(); -} +// KAction *KMReaderWin::createTodoAction() const +// { +// return mViewer->createTodoAction(); +// } KAction *KMReaderWin::createEventAction() const { return mViewer->createEventAction(); } -KAction *KMReaderWin::createNoteAction() const -{ - return mViewer->createNoteAction(); -} +// KAction *KMReaderWin::createNoteAction() const +// { +// return mViewer->createNoteAction(); +// } diff --git a/kmail/kmreaderwin.h b/kmail/kmreaderwin.h index c95b22d241..9d59d0cd53 100644 --- a/kmail/kmreaderwin.h +++ b/kmail/kmreaderwin.h @@ -1,258 +1,258 @@ /* -*- mode: C++; c-file-style: "gnu" -*- This file is part of KMail, the KDE mail client. Copyright (c) 1997 Markus Wuebben Copyright (c) 2013 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KMREADERWIN_H #define KMREADERWIN_H #include #include #include #include #include #include class KActionCollection; class KAction; class KToggleAction; class KMenu; namespace MessageViewer { class HeaderStrategy; class HeaderStyle; class Viewer; class CSSHelper; class AttachmentStrategy; } class KJob; /** This class implements a "reader window", that is a window used for reading or viewing messages. */ class KMReaderWin: public QWidget { Q_OBJECT public: explicit KMReaderWin( QWidget *parent, QWidget *mainWindow, KActionCollection *actionCollection, Qt::WindowFlags f = 0 ); virtual ~KMReaderWin(); /** Read settings from app's config file. */ void readConfig(); MessageViewer::HeaderStyle * headerStyle() const; /** Set the header style and strategy. We only want them to be set together. */ void setHeaderStyleAndStrategy( MessageViewer::HeaderStyle * style, MessageViewer::HeaderStrategy * strategy ); /** Getthe message header strategy. */ const MessageViewer::HeaderStrategy * headerStrategy() const; /** Get/set the message attachment strategy. */ const MessageViewer::AttachmentStrategy * attachmentStrategy() const; void setAttachmentStrategy( const MessageViewer::AttachmentStrategy * strategy ); /** Get selected override character encoding. @return The encoding selected by the user or an empty string if auto-detection is selected. */ QString overrideEncoding() const; /** Set the override character encoding. */ void setOverrideEncoding( const QString & encoding ); virtual void setPrinting(bool enable ); void setMessage( const Akonadi::Item& item, MessageViewer::Viewer::UpdateMode updateMode = MessageViewer::Viewer::Delayed); void setMessage( KMime::Message::Ptr message ); /** Instead of settings a message to be shown sets a message part to be shown */ void setMsgPart( KMime::Content* aMsgPart ); /** Clear the reader and discard the current message. */ void clear(bool force = false); void update(bool force = false); /** Return selected text */ QString copyText() const; /** Override default html mail setting */ bool htmlOverride() const; void setHtmlOverride( bool override ); /** Override default load external references setting */ bool htmlLoadExtOverride() const; void setHtmlLoadExtOverride( bool override ); /** Is html mail to be supported? Takes into account override */ bool htmlMail() const; /** Is loading ext. references to be supported? Takes into account override */ bool htmlLoadExternal(); /** Returns the MD5 hash for the list of new features */ static QString newFeaturesMD5(); /** Display a generic HTML splash page instead of a message */ void displaySplashPage( const QString &info ); /** Display the about page instead of a message */ void displayAboutPage(); /** Display the 'please wait' page instead of a message */ void displayBusyPage(); /** Display the 'we are currently in offline mode' page instead of a message */ void displayOfflinePage(); void displayResourceOfflinePage(); bool isFixedFont() const; void setUseFixedFont( bool useFixedFont ); MessageViewer::Viewer *viewer() { return mViewer; } KToggleAction *toggleFixFontAction() const; KAction *mailToComposeAction() const { return mMailToComposeAction; } KAction *mailToReplyAction() const { return mMailToReplyAction; } KAction *mailToForwardAction() const { return mMailToForwardAction; } KAction *addAddrBookAction() const { return mAddAddrBookAction; } KAction *openAddrBookAction() const { return mOpenAddrBookAction; } KAction *copyAction() const; KAction *selectAllAction() const; KAction *copyURLAction() const; KAction *copyImageLocation() const; KAction *urlOpenAction() const; KAction *urlSaveAsAction() const { return mUrlSaveAsAction; } KAction *addBookmarksAction() const { return mAddBookmarksAction;} KAction *toggleMimePartTreeAction() const; KAction *speakTextAction() const; KAction* translateAction() const; KAction* downloadImageToDiskAction() const; KAction *viewSourceAction() const; KAction *findInMessageAction() const; KAction *saveAsAction() const; KAction *saveMessageDisplayFormatAction() const; KAction *resetMessageDisplayFormatAction() const; KAction *blockImage() const; KAction *openBlockableItems() const; KAction *expandShortUrlAction() const; - KAction *createTodoAction() const; + // KAction *createTodoAction() const; KAction *createEventAction() const; - KAction *createNoteAction() const; + // KAction *createNoteAction() const; KAction *editContactAction() const { return mEditContactAction; } KMenu *viewHtmlOption() const { return mViewHtmlOptions; } KAction *shareImage() const { return mShareImage; } KAction *addToExistingContactAction() const { return mAddEmailToExistingContactAction; } Akonadi::Item message() const; QWidget* mainWindow() { return mMainWindow; } /** Enforce message decryption. */ void setDecryptMessageOverwrite( bool overwrite = true ); MessageViewer::CSSHelper* cssHelper() const; bool printSelectedText(bool preview); void setContactItem(const Akonadi::Item& contact, const KABC::Addressee &address); void clearContactItem(); bool adblockEnabled() const; bool isAShortUrl(const KUrl &url) const; signals: /** Emitted after parsing of a message to have it stored in unencrypted state in it's folder. */ void replaceMsgByUnencryptedVersion(); void showStatusBarMessage( const QString &message ); public slots: /** Force update even if message is the same */ void clearCache(); /** The user selected "Find" from the menu. */ void slotFind(); /** Copy the selected text to the clipboard */ void slotCopySelectedText(); /** Operations on mailto: URLs. */ void slotMailtoReply(); void slotMailtoCompose(); void slotMailtoForward(); void slotMailtoAddAddrBook(); void slotMailtoOpenAddrBook(); /** Save the page to a file */ void slotUrlSave(); void slotAddBookmarks(); void slotUrlClicked( const Akonadi::Item &, const KUrl& ); void slotShowReader( KMime::Content* , bool, const QString& ); void slotShowMessage( KMime::Message::Ptr message, const QString& encoding ); void slotDeleteMessage( const Akonadi::Item& ); void slotSaveImageOnDisk(); void slotPrintComposeResult( KJob *job ); void slotEditContact(); void contactStored( const Akonadi::Item &item ); void slotContactEditorError(const QString &error); void slotContactHtmlOptions(); void slotShareImage(); void slotMailToAddToExistingContact(); protected: KUrl urlClicked() const; KUrl imageUrlClicked() const; private: void createActions(); void updateHtmlActions(); private: KABC::Addressee mSearchedAddress; Akonadi::Item mSearchedContact; QWidget *mMainWindow; KActionCollection *mActionCollection; KAction *mMailToComposeAction; KAction *mMailToReplyAction; KAction *mMailToForwardAction; KAction *mAddAddrBookAction; KAction *mOpenAddrBookAction; KAction *mUrlSaveAsAction; KAction *mAddBookmarksAction; KAction *mImageUrlSaveAsAction; KAction *mEditContactAction; KAction *mViewAsHtml; KAction *mLoadExternalReference; KAction *mShareImage; KAction *mAddEmailToExistingContactAction; KMenu *mViewHtmlOptions; MessageViewer::Viewer *mViewer; }; #endif diff --git a/messageviewer/viewer/viewer.cpp b/messageviewer/viewer/viewer.cpp index 3adf7672fa..c147138520 100644 --- a/messageviewer/viewer/viewer.cpp +++ b/messageviewer/viewer/viewer.cpp @@ -1,714 +1,714 @@ /* -*- mode: C++; c-file-style: "gnu" -*- This file is part of KMail, the KDE mail client. Copyright (c) 1997 Markus Wuebben Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net Copyright (c) 2009 Andras Mantia Copyright (c) 2013 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // define this to copy all html that is written to the readerwindow to // filehtmlwriter.out in the current working directory //#define KMAIL_READER_HTML_DEBUG 1 #include "viewer.h" #include "viewer_p.h" #include "widgets/configurewidget.h" #include "csshelper.h" #include "settings/globalsettings.h" #include "viewer/mailwebview.h" #include "viewer/mimetreemodel.h" #include "adblock/adblockmanager.h" #include #include #include #include //KDE includes #include #include #include namespace MessageViewer { Viewer::Viewer( QWidget *aParent, QWidget *mainWindow, KActionCollection *actionCollection, Qt::WindowFlags aFlags ) : QWidget( aParent, aFlags ), d_ptr( new ViewerPrivate( this, mainWindow, actionCollection ) ) { initialize(); } Viewer::~Viewer() { //the d_ptr is automatically deleted } void Viewer::initialize() { connect( d_ptr, SIGNAL(replaceMsgByUnencryptedVersion()), SIGNAL(replaceMsgByUnencryptedVersion()) ); connect( d_ptr, SIGNAL(popupMenu(Akonadi::Item,KUrl,KUrl,QPoint)), SIGNAL(popupMenu(Akonadi::Item,KUrl,KUrl,QPoint)) ); connect( d_ptr, SIGNAL(urlClicked(Akonadi::Item,KUrl)), SIGNAL(urlClicked(Akonadi::Item,KUrl)) ); connect( d_ptr, SIGNAL(requestConfigSync()), SIGNAL(requestConfigSync()) ); connect( d_ptr, SIGNAL(makeResourceOnline(MessageViewer::Viewer::ResourceOnlineMode)), SIGNAL(makeResourceOnline(MessageViewer::Viewer::ResourceOnlineMode)) ); connect( d_ptr, SIGNAL(showReader(KMime::Content*,bool,QString)), SIGNAL(showReader(KMime::Content*,bool,QString)) ); connect( d_ptr, SIGNAL(showMessage(KMime::Message::Ptr,QString)), this, SIGNAL(showMessage(KMime::Message::Ptr,QString)) ); connect( d_ptr, SIGNAL(showStatusBarMessage(QString)), this, SIGNAL(showStatusBarMessage(QString)) ); connect( d_ptr, SIGNAL(itemRemoved()), this, SIGNAL(itemRemoved()) ); connect( d_ptr, SIGNAL(changeDisplayMail(Viewer::ForceDisplayTo,bool)), SLOT(slotChangeDisplayMail(Viewer::ForceDisplayTo,bool)) ); connect( d_ptr, SIGNAL(moveMessageToTrash()), SIGNAL(moveMessageToTrash())); setMessage( KMime::Message::Ptr(), Delayed ); } void Viewer::setMessage(KMime::Message::Ptr message, UpdateMode updateMode ) { Q_D(Viewer); if ( message == d->message() ) return; d->setMessage( message, updateMode ); } void Viewer::setMessageItem( const Akonadi::Item &item, UpdateMode updateMode ) { Q_D(Viewer); if ( d->messageItem() == item ) return; if ( !item.isValid() || item.loadedPayloadParts().contains( Akonadi::MessagePart::Body ) ) { d->setMessageItem( item, updateMode ); } else { Akonadi::ItemFetchJob* job = createFetchJob( item ); connect( job, SIGNAL(result(KJob*)), d, SLOT(itemFetchResult(KJob*)) ); d->displaySplashPage( i18n( "Loading message..." ) ); } } QString Viewer::messagePath() const { Q_D( const Viewer ); return d->mMessagePath; } void Viewer::setMessagePath( const QString& path ) { Q_D( Viewer ); d->mMessagePath = path; } void Viewer::displaySplashPage( const QString &info ) { Q_D( Viewer ); d->displaySplashPage( info ); } void Viewer::enableMessageDisplay() { Q_D( Viewer ); d->enableMessageDisplay(); } void Viewer::printMessage( const Akonadi::Item &msg ) { Q_D( Viewer ); d->printMessage( msg ); } void Viewer::printPreviewMessage( const Akonadi::Item &message ) { Q_D( Viewer ); d->printPreviewMessage( message ); } void Viewer::printPreview() { Q_D(Viewer); d->slotPrintPreview(); } void Viewer::print() { Q_D(Viewer); d->slotPrintMsg(); } void Viewer::resizeEvent( QResizeEvent * ) { Q_D(Viewer); if( !d->mResizeTimer.isActive() ) { // // Combine all resize operations that are requested as long a // the timer runs. // d->mResizeTimer.start( 100 ); } } void Viewer::closeEvent( QCloseEvent *e ) { Q_D(Viewer); QWidget::closeEvent( e ); d->writeConfig(); } void Viewer::slotAttachmentSaveAs() { Q_D( Viewer ); d->slotAttachmentSaveAs(); } void Viewer::slotAttachmentSaveAll() { Q_D( Viewer ); d->slotAttachmentSaveAll(); } void Viewer::slotSaveMessage() { Q_D( Viewer ); d->slotSaveMessage(); } void Viewer::slotScrollUp( int pixels ) { Q_D(Viewer); d->mViewer->scrollUp( qAbs( pixels ) ); } void Viewer::slotScrollDown( int pixels ) { Q_D(Viewer); d->mViewer->scrollDown( qAbs( pixels ) ); } bool Viewer::atBottom() const { Q_D(const Viewer); return d->mViewer->isScrolledToBottom(); } void Viewer::slotJumpDown() { Q_D(Viewer); d->mViewer->scrollPageDown( 100 ); } void Viewer::slotScrollPrior() { Q_D(Viewer); d->mViewer->scrollPageUp( 80 ); } void Viewer::slotScrollNext() { Q_D(Viewer); d->mViewer->scrollPageDown( 80 ); } QString Viewer::selectedText() const { Q_D(const Viewer); QString temp = d->mViewer->selectedText(); return temp; } void Viewer::setHtmlOverride( bool override ) { Q_D(Viewer); d->setHtmlOverride( override ); } bool Viewer::htmlOverride() const { Q_D(const Viewer);; return d->htmlOverride(); } void Viewer::setHtmlLoadExtOverride( bool override ) { Q_D(Viewer); d->setHtmlLoadExtOverride( override ); } void Viewer::setAppName( const QString& appName ) { Q_D(Viewer); d->mAppName = appName; } bool Viewer::htmlLoadExtOverride() const { Q_D(const Viewer); return d->htmlLoadExtOverride(); } bool Viewer::htmlMail() const { Q_D(const Viewer); return d->htmlMail(); } bool Viewer::htmlLoadExternal() const { Q_D(const Viewer); return d->htmlLoadExternal(); } bool Viewer::isFixedFont() const { Q_D(const Viewer); return d->mUseFixedFont; } void Viewer::setUseFixedFont( bool useFixedFont ) { Q_D(Viewer); d->setUseFixedFont( useFixedFont ); } QWidget* Viewer::mainWindow() { Q_D(Viewer); return d->mMainWindow; } void Viewer::setDecryptMessageOverwrite( bool overwrite ) { Q_D(Viewer); d->setDecryptMessageOverwrite( overwrite ); } QWidget* Viewer::configWidget() { Q_D(Viewer); ConfigureWidget *w = new ConfigureWidget(); connect( w, SIGNAL(settingsChanged()), d, SLOT(slotSettingsChanged()) ); return w; } KMime::Message::Ptr Viewer::message() const { Q_D(const Viewer); return d->mMessage; } Akonadi::Item Viewer::messageItem() const { Q_D(const Viewer); return d->mMessageItem; } bool Viewer::event(QEvent *e) { Q_D(Viewer); if (e->type() == QEvent::PaletteChange) { delete d->mCSSHelper; d->mCSSHelper = new CSSHelper( d->mViewer ); d->update( Viewer::Force ); // Force update return true; } return QWidget::event(e); } void Viewer::slotFind() { Q_D(Viewer); d->slotFind(); } void Viewer::slotTranslate() { Q_D(Viewer); d->slotTranslate(); } const AttachmentStrategy * Viewer::attachmentStrategy() const { Q_D(const Viewer); return d->attachmentStrategy(); } void Viewer::setAttachmentStrategy( const AttachmentStrategy * strategy ) { Q_D(Viewer); d->setAttachmentStrategy( strategy ); } QString Viewer::overrideEncoding() const { Q_D( const Viewer ); return d->overrideEncoding(); } void Viewer::setOverrideEncoding( const QString &encoding ) { Q_D( Viewer ); d->setOverrideEncoding( encoding ); } CSSHelper* Viewer::cssHelper() const { Q_D( const Viewer ); return d->cssHelper(); } KToggleAction *Viewer::toggleFixFontAction() { Q_D( Viewer ); return d->mToggleFixFontAction; } KToggleAction *Viewer::toggleMimePartTreeAction() { Q_D( Viewer ); return d->mToggleMimePartTreeAction; } KAction *Viewer::selectAllAction() { Q_D( Viewer ); return d->mSelectAllAction; } HeaderStrategy * Viewer::headerStrategy() const { Q_D( const Viewer ); return d->headerStrategy(); } HeaderStyle * Viewer::headerStyle() const { Q_D( const Viewer ); return d->headerStyle(); } void Viewer::setHeaderStyleAndStrategy( HeaderStyle * style, HeaderStrategy * strategy ) { Q_D( Viewer ); d->setHeaderStyleAndStrategy( style, strategy ); } void Viewer::setExternalWindow( bool b ) { Q_D( Viewer ); d->setExternalWindow( b ); } KAction *Viewer::viewSourceAction() { Q_D( Viewer ); return d->mViewSourceAction; } KAction *Viewer::copyURLAction() { Q_D( Viewer ); return d->mCopyURLAction; } KAction *Viewer::copyAction() { Q_D( Viewer ); return d->mCopyAction; } KAction *Viewer::speakTextAction() { Q_D( Viewer ); return d->mSpeakTextAction; } KAction *Viewer::copyImageLocation() { Q_D( Viewer ); return d->mCopyImageLocation; } KAction *Viewer::translateAction() { Q_D( Viewer ); return d->mTranslateAction; } KAction *Viewer::saveAsAction() { Q_D( Viewer ); return d->mSaveMessageAction; } KAction *Viewer::urlOpenAction() { Q_D( Viewer ); return d->mUrlOpenAction; } void Viewer::setPrinting(bool enable) { Q_D( Viewer ); d->setPrinting( enable ); } void Viewer::writeConfig( bool force ) { Q_D( Viewer ); d->writeConfig( force ); } KUrl Viewer::urlClicked() const { Q_D( const Viewer ); return d->mClickedUrl; } KUrl Viewer::imageUrlClicked() const { Q_D( const Viewer ); return d->mImageUrl; } void Viewer::update( MessageViewer::Viewer::UpdateMode updateMode ) { Q_D( Viewer ); d->update( updateMode ); } void Viewer::setMessagePart( KMime::Content* aMsgPart ) { Q_D( Viewer ); d->setMessagePart( aMsgPart ); } void Viewer::slotShowMessageSource() { Q_D( Viewer ); d->slotShowMessageSource(); } void Viewer::readConfig() { Q_D( Viewer ); d->readConfig(); } QAbstractItemModel* Viewer::messageTreeModel() const { return d_func()->mMimePartModel; } Akonadi::ItemFetchJob* Viewer::createFetchJob( const Akonadi::Item &item ) { Akonadi::ItemFetchJob* job = new Akonadi::ItemFetchJob( item ); job->fetchScope().fetchAllAttributes(); job->fetchScope().setAncestorRetrieval( Akonadi::ItemFetchScope::Parent ); job->fetchScope().fetchFullPayload( true ); job->fetchScope().setFetchRelations( true ); // needed to know if we have notes or not job->fetchScope().fetchAttribute(); return job; } void Viewer::setScrollBarPolicy( Qt::Orientation orientation, Qt::ScrollBarPolicy policy ) { Q_D( Viewer ); d->mViewer->setScrollBarPolicy( orientation, policy ); } void Viewer::addMessageLoadedHandler( AbstractMessageLoadedHandler *handler ) { Q_D( Viewer ); if ( !handler ) return; d->mMessageLoadedHandlers.insert( handler ); } void Viewer::removeMessageLoadedHandler( AbstractMessageLoadedHandler *handler ) { Q_D( Viewer ); d->mMessageLoadedHandlers.remove( handler ); } void Viewer::deleteMessage() { Q_D( Viewer ); emit deleteMessage( d->messageItem() ); } void Viewer::selectAll() { Q_D( Viewer ); d->selectAll(); } void Viewer::clearSelection() { Q_D( Viewer ); d->clearSelection(); } void Viewer::copySelectionToClipboard() { Q_D( Viewer ); d->slotCopySelectedText(); } void Viewer::setZoomFactor( qreal zoomFactor ) { Q_D( Viewer ); d->setZoomFactor(zoomFactor); } void Viewer::slotZoomReset() { Q_D( Viewer ); d->slotZoomReset(); } void Viewer::slotZoomIn() { Q_D( Viewer ); d->slotZoomIn(); } void Viewer::slotZoomOut() { Q_D( Viewer ); d->slotZoomOut(); } void Viewer::setZoomTextOnly( bool textOnly ) { Q_D( Viewer ); d->setZoomTextOnly( textOnly ); } bool Viewer::zoomTextOnly() const { Q_D(const Viewer); return d->mZoomTextOnly; } KAction *Viewer::findInMessageAction() { Q_D( Viewer ); return d->mFindInMessageAction; } void Viewer::slotChangeDisplayMail(Viewer::ForceDisplayTo mode,bool loadExternal) { setHtmlLoadExtOverride(loadExternal); switch(mode) { case Viewer::Html: setHtmlOverride(true); break; case Viewer::Text: setHtmlOverride(false); break; default: break; } update(Viewer::Force); } KAction *Viewer::saveMessageDisplayFormatAction() { Q_D( Viewer ); return d->mSaveMessageDisplayFormat; } KAction *Viewer::resetMessageDisplayFormatAction() { Q_D( Viewer ); return d->mResetMessageDisplayFormat; } void Viewer::saveMainFrameScreenshotInFile(const QString &filename) { Q_D( Viewer ); return d->saveMainFrameScreenshotInFile(filename); } KAction *Viewer::blockImage() { Q_D( Viewer ); return d->mBlockImage; } bool Viewer::adblockEnabled() const { #ifndef KDEPIM_NO_WEBKIT return MessageViewer::AdBlockManager::self()->isEnabled(); #else return false; #endif } KAction *Viewer::openBlockableItems() { Q_D( Viewer ); return d->mBlockableItems; } bool Viewer::isAShortUrl(const KUrl &url) const { Q_D( const Viewer ); return d->isAShortUrl(url); } KAction *Viewer::expandShortUrlAction() { Q_D( Viewer ); return d->mExpandUrlAction; } -KAction *Viewer::createTodoAction() -{ - Q_D( Viewer ); - return d->mCreateTodoAction; -} +// KAction *Viewer::createTodoAction() +// { +// Q_D( Viewer ); +// return d->mCreateTodoAction; +// } KAction *Viewer::createEventAction() { Q_D( Viewer ); return d->mCreateEventAction; } -KAction *Viewer::createNoteAction() -{ - Q_D( Viewer ); - return d->mCreateNoteAction; -} +// KAction *Viewer::createNoteAction() +// { +// Q_D( Viewer ); +// return d->mCreateNoteAction; +// } } diff --git a/messageviewer/viewer/viewer.h b/messageviewer/viewer/viewer.h index 64d8b41a45..cd2cdd5801 100644 --- a/messageviewer/viewer/viewer.h +++ b/messageviewer/viewer/viewer.h @@ -1,430 +1,430 @@ /* -*- mode: C++; c-file-style: "gnu" -*- This file is part of KMail, the KDE mail client. Copyright (c) 1997 Markus Wuebben Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net Copyright (c) 2009 Andras Mantia This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef MESSAGEVIEWER_H #define MESSAGEVIEWER_H #include "messageviewer_export.h" #include #include namespace Akonadi { class Item; class ItemFetchJob; } class KActionCollection; class KAction; class KToggleAction; class KUrl; class QAbstractItemModel; class QCloseEvent; class QEvent; class QResizeEvent; namespace MessageViewer { class AttachmentStrategy; class CSSHelper; class HeaderStrategy; class HeaderStyle; class ViewerPrivate; /** * An interface to plug in a handler that is called when * an message item has been loaded into the view. */ class AbstractMessageLoadedHandler { public: virtual ~AbstractMessageLoadedHandler() {} /** * This method is called whenever a message item has been loaded * into the view. * * @param item The message item that has been loaded. */ virtual void setItem( const Akonadi::Item &item ) = 0; }; //TODO(Andras) once only those methods are public that really need to be public, probably export the whole class instead of just some methods /** * This is the main widget for the viewer. * See the documentation of ViewerPrivate for implementation details. * See Mainpage.dox for an overview of the classes in the messageviewer library. */ class MESSAGEVIEWER_EXPORT Viewer: public QWidget { Q_OBJECT Q_DECLARE_PRIVATE( Viewer ) public: /** * Create a mail viewer widget * @param parent parent widget * @param mainWindow the application's main window * @param actionCollection the action collection where the widget's actions will belong to * @param f window flags */ explicit Viewer( QWidget *parent, QWidget *mainWindow = 0, KActionCollection *actionCollection = 0, Qt::WindowFlags f = 0 ); virtual ~Viewer(); /** * Returns the current message displayed in the viewer. */ KMime::Message::Ptr message() const; /** * Returns the current message item displayed in the viewer. */ Akonadi::Item messageItem() const; enum ForceDisplayTo { Unknown = 0, Text = 1, Html = 2 }; enum AttachmentAction { Open = 1, OpenWith = 2, View = 3, Save = 4, Properties = 5, ChiasmusEncrypt = 6, Delete = 7, Edit = 8, Copy = 9, ScrollTo = 10 }; /** * The display update mode: Force updates the display immediately, Delayed updates * after some time (150ms by default) */ enum UpdateMode { Force = 0, Delayed }; enum ResourceOnlineMode { AllResources = 0, SelectedResource = 1 }; /** * Set the message that shall be shown. * @param msg - the message to be shown. If 0, an empty page is displayed. * @param updateMode - update the display immediately or not. See UpdateMode. */ void setMessage( KMime::Message::Ptr message, UpdateMode updateMode = Delayed ); /** * Set the Akonadi item that will be displayed. * @param item - the Akonadi item to be displayed. If it doesn't hold a mail (KMime::Message::Ptr as payload data), * an empty page is shown. * @param updateMode - update the display immediately or not. See UpdateMode. */ void setMessageItem( const Akonadi::Item& item, UpdateMode updateMode = Delayed ); /** * The path to the message in terms of Akonadi collection hierarchy. */ QString messagePath() const; /** * Set the path to the message in terms of Akonadi collection hierarchy. */ void setMessagePath( const QString &path ); /** * Instead of settings a message to be shown sets a message part * to be shown */ void setMessagePart( KMime::Content* aMsgPart ); /** * Convenience method to clear the reader and discard the current message. Sets the internal message pointer * returned by message() to 0. * @param updateMode - update the display immediately or not. See UpdateMode. */ void clear( UpdateMode updateMode = Delayed ) { setMessage( KMime::Message::Ptr(), updateMode ); } void update( UpdateMode updateMode = Delayed ); /** * Sets a message as the current one and print it immediately. * @param message the message to display and print */ void printMessage( const Akonadi::Item &msg ); void printPreviewMessage( const Akonadi::Item &message ); /** Print the currently displayed message */ void print(); void printPreview(); /** Get the html override setting */ bool htmlOverride() const; /** Override default html mail setting */ void setHtmlOverride( bool override ); /** Get the load external references override setting */ bool htmlLoadExtOverride() const; /** Override default load external references setting */ void setHtmlLoadExtOverride( bool override ); /** Is html mail to be supported? Takes into account override */ bool htmlMail() const; /** Is loading ext. references to be supported? Takes into account override */ bool htmlLoadExternal() const; /** * Set the application name that is shown when the splash screen is active. * @param appName - A QString that is set to the calling application name. */ void setAppName( const QString &appName ); /** * Display a generic HTML splash page instead of a message. * @param info - the text to be displayed in HTML format */ void displaySplashPage( const QString& info ); /** Enable the displaying of messages again after an splash (or other) page was displayed */ void enableMessageDisplay(); /** Returns true if the message view is scrolled to the bottom. */ bool atBottom() const; bool isFixedFont() const; void setUseFixedFont( bool useFixedFont ); QWidget* mainWindow(); /** Enforce message decryption. */ void setDecryptMessageOverwrite( bool overwrite = true ); /** * Get an instance for the configuration widget. The caller has the ownership and must delete the widget. See also configObject(); * The caller should also call the widget's slotSettingsChanged() if the configuration has changed. */ QWidget* configWidget(); /** * Initiates a delete, by sending a signal to delete the message item */ void deleteMessage(); const AttachmentStrategy * attachmentStrategy() const; void setAttachmentStrategy( const AttachmentStrategy * strategy ); QString overrideEncoding() const; void setOverrideEncoding( const QString &encoding ); CSSHelper* cssHelper() const; void setPrinting(bool enable); void selectAll(); void clearSelection(); void copySelectionToClipboard(); void setZoomFactor( qreal zoomFactor ); void setZoomTextOnly( bool textOnly ); bool zoomTextOnly() const; KToggleAction *toggleFixFontAction(); KToggleAction *toggleMimePartTreeAction(); KAction *selectAllAction(); KAction *copyURLAction(); KAction *copyAction(); KAction *urlOpenAction(); KAction *speakTextAction(); KAction *copyImageLocation(); KAction *translateAction(); KAction *viewSourceAction(); KAction *findInMessageAction(); KAction *saveAsAction(); KAction *saveMessageDisplayFormatAction(); KAction *resetMessageDisplayFormatAction(); KAction *blockImage(); KAction *openBlockableItems(); KAction *expandShortUrlAction(); - KAction *createTodoAction(); + // KAction *createTodoAction(); KAction *createEventAction(); - KAction *createNoteAction(); + // KAction *createNoteAction(); HeaderStrategy * headerStrategy() const; HeaderStyle * headerStyle() const; void setHeaderStyleAndStrategy( HeaderStyle * style, HeaderStrategy * strategy ); void writeConfig( bool withSync=true ); KUrl urlClicked() const; KUrl imageUrlClicked() const; void readConfig(); /** A QAIM tree model of the message structure. */ QAbstractItemModel* messageTreeModel() const; /** * Create an item fetch job that is suitable for using to fetch the message item that will * be displayed on this viewer. * It will set the correct fetch scope. * You still need to connect to the job's result signal. */ static Akonadi::ItemFetchJob* createFetchJob( const Akonadi::Item &item ); /** * Sets the scrollbar policy for the scrollbar defined by orientation to policy. * @see scrollBarPolicy() */ void setScrollBarPolicy( Qt::Orientation orientation, Qt::ScrollBarPolicy policy ); /** * Returns the scrollbar policy for the scrollbar defined by orientation. * @see setScrollBarPolicy() */ Qt::ScrollBarPolicy scrollBarPolicy( Qt::Orientation orientation ) const; /** * Adds a @p handler for actions that will be executed when the message * has been loaded into the view. */ void addMessageLoadedHandler( AbstractMessageLoadedHandler *handler ); /** * Removes the @p handler for actions that will be executed when the message * has been loaded into the view. */ void removeMessageLoadedHandler( AbstractMessageLoadedHandler *handler ); QString selectedText() const; void setExternalWindow( bool b ); void saveMainFrameScreenshotInFile(const QString &filename); bool adblockEnabled() const; bool isAShortUrl(const KUrl &url) const; signals: void moveMessageToTrash(); /** * Emitted when a status bar message is shown. Note that the status bar message is also set to * KPIM::BroadcastStatus in addition. */ void showStatusBarMessage( const QString &message ); /** * Emitted after parsing of a message to have it stored * in unencrypted state in it's folder. */ void replaceMsgByUnencryptedVersion(); /** The user presses the right mouse button. 'url' may be 0. */ void popupMenu(const Akonadi::Item &msg, const KUrl &url, const KUrl &imageUrl, const QPoint& mousePos); /** * The message viewer handles some types of urls itself, most notably http(s) * and ftp(s). When it can't handle the url it will emit this signal. */ void urlClicked( const Akonadi::Item &, const KUrl& ); void requestConfigSync(); /// Emitted when the content should be shown in a separate window void showReader( KMime::Content* aMsgPart, bool aHTML, const QString & encoding ); /// Emitted when the message should be shown in a separate window void showMessage( KMime::Message::Ptr message, const QString& encoding ); void deleteMessage( const Akonadi::Item & ); /// Emitted when the item, previously set with setMessageItem, has been removed. void itemRemoved(); void makeResourceOnline(MessageViewer::Viewer::ResourceOnlineMode mode); private: void initialize(); public slots: /** * HTML Widget scrollbar and layout handling. * * Scrolling always happens in the direction of the slot that is called. I.e. * the methods take the absolute value of */ void slotScrollUp( int pixels = 10 ); void slotScrollDown( int pixels = 10 ); void slotScrollPrior(); void slotScrollNext(); void slotJumpDown(); void slotFind(); void slotTranslate(); void slotSaveMessage(); void slotAttachmentSaveAs(); void slotAttachmentSaveAll(); void slotShowMessageSource(); void slotZoomIn(); void slotZoomOut(); void slotZoomReset(); void slotChangeDisplayMail(Viewer::ForceDisplayTo,bool); protected: /** Some necessary event handling. */ virtual void closeEvent(QCloseEvent *); virtual void resizeEvent(QResizeEvent *); /** Watch for palette changes */ virtual bool event(QEvent *e); #ifdef KDEPIM_MOBILE_UI friend class MessageViewItem; #endif ViewerPrivate* const d_ptr; }; } #endif