You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
452 lines
14 KiB
452 lines
14 KiB
// -*- mode: C++; c-file-style: "gnu" -*- |
|
/*************************************************************************** |
|
kmsystemtray.cpp - description |
|
------------------ |
|
begin : Fri Aug 31 22:38:44 EDT 2001 |
|
copyright : (C) 2001 by Ryan Breen |
|
email : ryan@porivo.com |
|
|
|
Copyright (c) 2010, 2011, 2012 Montel Laurent <montel@kde.org> |
|
***************************************************************************/ |
|
|
|
/*************************************************************************** |
|
* * |
|
* 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. * |
|
* * |
|
***************************************************************************/ |
|
|
|
|
|
#include "kmsystemtray.h" |
|
#include "kmmainwidget.h" |
|
#include "foldercollection.h" |
|
#include "globalsettings.h" |
|
#include "mailutil.h" |
|
#include "mailcommon/mailkernel.h" |
|
#include "mailcommon/foldertreeview.h" |
|
|
|
#include <kiconloader.h> |
|
#include <kcolorscheme.h> |
|
#include <kwindowsystem.h> |
|
#include <kdebug.h> |
|
#include <KMenu> |
|
#include <KLocale> |
|
#include <KAction> |
|
#include <KActionMenu> |
|
#include <KActionCollection> |
|
|
|
#include <QPainter> |
|
|
|
#include <Akonadi/ChangeRecorder> |
|
#include <Akonadi/EntityTreeModel> |
|
#include <Akonadi/CollectionModel> |
|
|
|
using namespace MailCommon; |
|
|
|
/** |
|
* Construct a KSystemTray icon to be displayed when new mail |
|
* has arrived in a non-system folder. The KMSystemTray listens |
|
* for updateNewMessageNotification events from each non-system |
|
* KMFolder and maintains a store of all folders with unread |
|
* messages. |
|
* |
|
* The KMSystemTray also provides a popup menu listing each folder |
|
* with its count of unread messages, allowing the user to jump |
|
* to the first unread message in each folder. |
|
*/ |
|
namespace KMail { |
|
KMSystemTray::KMSystemTray(QObject *parent) |
|
: KStatusNotifierItem( parent), |
|
mDesktopOfMainWin( 0 ), |
|
mMode( GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread ), |
|
mCount( 0 ), |
|
mShowUnreadMail( true ), |
|
mNewMessagesPopup( 0 ), |
|
mSendQueued( 0 ) |
|
{ |
|
kDebug() << "Initting systray"; |
|
setToolTipTitle( i18n("KMail") ); |
|
setToolTipIconByName( "kmail" ); |
|
setIconByName( "kmail" ); |
|
mIcon = KIcon( "mail-unread-new" ); |
|
|
|
KMMainWidget * mainWidget = kmkernel->getKMMainWidget(); |
|
if ( mainWidget ) { |
|
QWidget * mainWin = mainWidget->window(); |
|
if ( mainWin ) { |
|
mDesktopOfMainWin = KWindowSystem::windowInfo( mainWin->winId(), |
|
NET::WMDesktop ).desktop(); |
|
} |
|
} |
|
|
|
|
|
connect( this, SIGNAL(activateRequested(bool,QPoint)), |
|
this, SLOT(slotActivated()) ); |
|
connect( contextMenu(), SIGNAL(aboutToShow()), |
|
this, SLOT(slotContextMenuAboutToShow()) ); |
|
|
|
connect( kmkernel->folderCollectionMonitor(), SIGNAL(collectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics)), SLOT(slotCollectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics)) ); |
|
|
|
connect( kmkernel->folderCollectionMonitor(), SIGNAL(collectionAdded(Akonadi::Collection,Akonadi::Collection)), this, SLOT(initListOfCollection()) ); |
|
connect( kmkernel->folderCollectionMonitor(), SIGNAL(collectionRemoved(Akonadi::Collection)), this, SLOT(initListOfCollection()) ); |
|
connect( kmkernel->folderCollectionMonitor(), SIGNAL(collectionSubscribed(Akonadi::Collection,Akonadi::Collection)),SLOT(initListOfCollection()) ); |
|
connect( kmkernel->folderCollectionMonitor(), SIGNAL(collectionUnsubscribed(Akonadi::Collection)),SLOT(initListOfCollection()) ); |
|
|
|
initListOfCollection(); |
|
|
|
} |
|
|
|
void KMSystemTray::buildPopupMenu() |
|
{ |
|
if ( !contextMenu() ) { |
|
setContextMenu( new KMenu() ); |
|
} |
|
|
|
contextMenu()->clear(); |
|
|
|
KMMainWidget * mainWidget = kmkernel->getKMMainWidget(); |
|
if ( !mainWidget ) |
|
return; |
|
|
|
contextMenu()->addTitle(qApp->windowIcon(), i18n("KMail")); |
|
QAction * action; |
|
if ( ( action = mainWidget->action("check_mail") ) ) |
|
contextMenu()->addAction( action ); |
|
if ( ( action = mainWidget->action("check_mail_in") ) ) |
|
contextMenu()->addAction( action ); |
|
|
|
mSendQueued = mainWidget->sendQueuedAction(); |
|
contextMenu()->addAction( mSendQueued ); |
|
contextMenu()->addAction( mainWidget->sendQueueViaMenu() ); |
|
|
|
contextMenu()->addSeparator(); |
|
if ( ( action = mainWidget->action("new_message") ) ) |
|
contextMenu()->addAction( action ); |
|
if ( ( action = mainWidget->action("kmail_configure_kmail") ) ) |
|
contextMenu()->addAction( action ); |
|
contextMenu()->addSeparator(); |
|
if ( (action = mainWidget->action("akonadi_work_offline") ) ) |
|
contextMenu()->addAction( action ); |
|
contextMenu()->addSeparator(); |
|
|
|
|
|
|
|
if ( ( action = actionCollection()->action("file_quit") ) ) |
|
contextMenu()->addAction( action ); |
|
} |
|
|
|
KMSystemTray::~KMSystemTray() |
|
{ |
|
} |
|
|
|
void KMSystemTray::setShowUnread(bool showUnread) |
|
{ |
|
if(mShowUnreadMail == showUnread) |
|
return; |
|
mShowUnreadMail = showUnread; |
|
updateSystemTray(); |
|
} |
|
|
|
void KMSystemTray::setMode(int newMode) |
|
{ |
|
if(newMode == mMode) return; |
|
|
|
kDebug() << "Setting systray mMode to" << newMode; |
|
mMode = newMode; |
|
|
|
switch ( mMode ) { |
|
case GlobalSettings::EnumSystemTrayPolicy::ShowAlways: |
|
setStatus( KStatusNotifierItem::Active ); |
|
break; |
|
case GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread: |
|
setStatus( mCount > 0 ? KStatusNotifierItem::Active : KStatusNotifierItem::Passive ); |
|
break; |
|
default: |
|
kDebug() << "Unknown systray mode" << mMode; |
|
} |
|
} |
|
|
|
int KMSystemTray::mode() const |
|
{ |
|
return mMode; |
|
} |
|
|
|
/** |
|
* Update the count of unread messages. If there are unread messages, |
|
* overlay the count on top of a transparent version of the KMail icon. |
|
* If there is no unread mail, restore the normal KMail icon. |
|
*/ |
|
void KMSystemTray::updateCount() |
|
{ |
|
if(mCount == 0) |
|
{ |
|
setIconByName( "kmail" ); |
|
return; |
|
} |
|
if(mShowUnreadMail) { |
|
const int overlaySize = KIconLoader::SizeSmallMedium; |
|
|
|
const QString countString = QString::number( mCount ); |
|
QFont countFont = KGlobalSettings::generalFont(); |
|
countFont.setBold(true); |
|
|
|
// decrease the size of the font for the number of unread messages if the |
|
// number doesn't fit into the available space |
|
float countFontSize = countFont.pointSizeF(); |
|
QFontMetrics qfm( countFont ); |
|
int width = qfm.width( countString ); |
|
if( width > (overlaySize - 2) ) |
|
{ |
|
countFontSize *= float( overlaySize - 2 ) / float( width ); |
|
countFont.setPointSizeF( countFontSize ); |
|
} |
|
|
|
// Paint the number in a pixmap |
|
QPixmap overlayPixmap( overlaySize, overlaySize ); |
|
overlayPixmap.fill( Qt::transparent ); |
|
|
|
QPainter p( &overlayPixmap ); |
|
p.setFont( countFont ); |
|
KColorScheme scheme( QPalette::Active, KColorScheme::View ); |
|
|
|
p.setBrush( Qt::NoBrush ); |
|
p.setPen( scheme.foreground( KColorScheme::LinkText ).color() ); |
|
p.setOpacity( 1.0 ); |
|
p.drawText( overlayPixmap.rect(),Qt::AlignCenter, countString ); |
|
p.end(); |
|
|
|
QPixmap iconPixmap = mIcon.pixmap(overlaySize, overlaySize); |
|
|
|
QPainter pp(&iconPixmap); |
|
pp.drawPixmap(0, 0, overlayPixmap); |
|
pp.end(); |
|
|
|
setIconByPixmap( iconPixmap ); |
|
} else { |
|
setIconByName( "mail-unread-new" ); |
|
} |
|
} |
|
|
|
|
|
/** |
|
* On left mouse click, switch focus to the first KMMainWidget. On right |
|
* click, bring up a list of all folders with a count of unread messages. |
|
*/ |
|
void KMSystemTray::slotActivated() |
|
{ |
|
KMMainWidget * mainWidget = kmkernel->getKMMainWidget(); |
|
if ( !mainWidget ) |
|
return ; |
|
|
|
QWidget *mainWin = mainWidget->window(); |
|
if ( !mainWin ) |
|
return ; |
|
|
|
KWindowInfo cur = KWindowSystem::windowInfo( mainWin->winId(), NET::WMDesktop ); |
|
|
|
int currentDesktop = KWindowSystem::currentDesktop(); |
|
bool wasMinimized = cur.isMinimized(); |
|
|
|
if ( cur.valid() ) |
|
mDesktopOfMainWin = cur.desktop(); |
|
|
|
if (wasMinimized && (currentDesktop != mDesktopOfMainWin) && ( mDesktopOfMainWin == NET::OnAllDesktops )) |
|
KWindowSystem::setOnDesktop(mainWin->winId(), currentDesktop); |
|
|
|
if ( mDesktopOfMainWin == NET::OnAllDesktops ) |
|
KWindowSystem::setOnAllDesktops( mainWin->winId(), true ); |
|
|
|
KWindowSystem::activateWindow( mainWin->winId() ); |
|
|
|
if (wasMinimized ) |
|
kmkernel->raise(); |
|
} |
|
|
|
void KMSystemTray::slotContextMenuAboutToShow() |
|
{ |
|
// Rebuild popup menu before show to minimize race condition if |
|
// the base KMainWidget is closed. |
|
buildPopupMenu(); |
|
|
|
if ( mNewMessagesPopup != 0 ) { |
|
contextMenu()->removeAction( mNewMessagesPopup->menuAction() ); |
|
delete mNewMessagesPopup; |
|
mNewMessagesPopup = 0; |
|
} |
|
mNewMessagesPopup = new KMenu(); |
|
fillFoldersMenu( mNewMessagesPopup, KMKernel::self()->treeviewModelSelection() ); |
|
|
|
connect( mNewMessagesPopup, SIGNAL(triggered(QAction*)), this, |
|
SLOT(slotSelectCollection(QAction*)) ); |
|
|
|
|
|
if ( mCount > 0 ) { |
|
mNewMessagesPopup->setTitle( i18n("New Messages In") ); |
|
contextMenu()->insertAction( mSendQueued, mNewMessagesPopup->menuAction() ); |
|
} |
|
} |
|
|
|
void KMSystemTray::fillFoldersMenu( QMenu *menu, const QAbstractItemModel *model, const QString& parentName, const QModelIndex& parentIndex ) |
|
{ |
|
const int rowCount = model->rowCount( parentIndex ); |
|
for ( int row = 0; row < rowCount; ++row ) { |
|
const QModelIndex index = model->index( row, 0, parentIndex ); |
|
const Akonadi::Collection collection = model->data( index, Akonadi::CollectionModel::CollectionRole ).value<Akonadi::Collection>(); |
|
qint64 count = 0; |
|
if ( !excludeFolder( collection ) ) { |
|
Akonadi::CollectionStatistics statistics = collection.statistics(); |
|
count = qMax( 0LL, statistics.unreadCount() ); |
|
if ( count > 0 ) { |
|
const QSharedPointer<FolderCollection> col = FolderCollection::forCollection( collection, false ); |
|
if ( col && !col->ignoreNewMail() ) { |
|
mCount += count; |
|
} else { //Don't show menu entry when we exclude it with ignoreNewMail |
|
count = 0; |
|
} |
|
} |
|
} |
|
QString label = parentName.isEmpty() ? QLatin1String("") : QString(parentName + QLatin1String("->")); |
|
label += model->data( index ).toString(); |
|
label.replace( QLatin1String( "&" ), QLatin1String( "&&" ) ); |
|
if ( count > 0 ) { |
|
// insert an item |
|
QAction* action = menu->addAction( label ); |
|
action->setData( collection.id() ); |
|
} |
|
if ( model->rowCount( index ) > 0 ) { |
|
fillFoldersMenu( menu, model, label, index ); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
void KMSystemTray::hideKMail() |
|
{ |
|
KMMainWidget * mainWidget = kmkernel->getKMMainWidget(); |
|
if (!mainWidget) |
|
return; |
|
QWidget *mainWin = mainWidget->window(); |
|
Q_ASSERT(mainWin); |
|
if(mainWin) |
|
{ |
|
mDesktopOfMainWin = KWindowSystem::windowInfo( mainWin->winId(), |
|
NET::WMDesktop ).desktop(); |
|
// iconifying is unnecessary, but it looks cooler |
|
KWindowSystem::minimizeWindow( mainWin->winId() ); |
|
mainWin->hide(); |
|
} |
|
} |
|
|
|
void KMSystemTray::initListOfCollection() |
|
{ |
|
mCount = 0; |
|
const QAbstractItemModel *model = KMKernel::self()->entityTreeModel(); |
|
if(model->rowCount() == 0) { |
|
QTimer::singleShot(1000,this,SLOT(initListOfCollection())); |
|
return; |
|
} |
|
unreadMail( model ); |
|
|
|
if ( mMode == GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread ) { |
|
if(status() == KStatusNotifierItem::Passive && (mCount > 0)) { |
|
setStatus( KStatusNotifierItem::Active ); |
|
} else if( status() == KStatusNotifierItem::Active && (mCount == 0) ) { |
|
setStatus( KStatusNotifierItem::Passive ); |
|
} |
|
} |
|
|
|
//kDebug()<<" mCount :"<<mCount; |
|
updateCount(); |
|
} |
|
|
|
void KMSystemTray::unreadMail( const QAbstractItemModel *model, const QModelIndex& parentIndex ) |
|
{ |
|
const int rowCount = model->rowCount( parentIndex ); |
|
for ( int row = 0; row < rowCount; ++row ) { |
|
const QModelIndex index = model->index( row, 0, parentIndex ); |
|
const Akonadi::Collection collection = model->data( index, Akonadi::CollectionModel::CollectionRole ).value<Akonadi::Collection>(); |
|
|
|
if ( !excludeFolder( collection ) ) { |
|
|
|
const Akonadi::CollectionStatistics statistics = collection.statistics(); |
|
const qint64 count = qMax( 0LL, statistics.unreadCount() ); |
|
|
|
if ( count > 0 ) { |
|
const QSharedPointer<FolderCollection> col = FolderCollection::forCollection( collection, false ); |
|
if ( col && !col->ignoreNewMail() ) { |
|
mCount += count; |
|
} |
|
} |
|
} |
|
if ( model->rowCount( index ) > 0 ) { |
|
unreadMail( model, index ); |
|
} |
|
} |
|
// Update tooltip to reflect count of unread messages |
|
setToolTipSubTitle( mCount == 0 ? i18n("There are no unread messages") |
|
: i18np("1 unread message", |
|
"%1 unread messages", |
|
mCount)); |
|
} |
|
|
|
bool KMSystemTray::hasUnreadMail() const |
|
{ |
|
return ( mCount != 0 ); |
|
} |
|
|
|
void KMSystemTray::slotSelectCollection(QAction*act) |
|
{ |
|
const Akonadi::Collection::Id id = act->data().value<Akonadi::Collection::Id>(); |
|
KMKernel::self()->selectCollectionFromId( id ); |
|
KMMainWidget * mainWidget = kmkernel->getKMMainWidget(); |
|
if ( !mainWidget ) |
|
return ; |
|
QWidget *mainWin = mainWidget->window(); |
|
if( mainWin && !mainWin->isVisible() ) |
|
activate(); |
|
} |
|
|
|
void KMSystemTray::updateSystemTray() |
|
{ |
|
initListOfCollection(); |
|
} |
|
|
|
void KMSystemTray::slotCollectionStatisticsChanged( Akonadi::Collection::Id id,const Akonadi::CollectionStatistics& ) |
|
{ |
|
//Exclude sent mail folder |
|
|
|
if ( CommonKernel->outboxCollectionFolder().id() == id || |
|
CommonKernel->sentCollectionFolder().id() == id || |
|
CommonKernel->templatesCollectionFolder().id() == id || |
|
CommonKernel->trashCollectionFolder().id() == id || |
|
CommonKernel->draftsCollectionFolder().id() == id ) { |
|
return; |
|
} |
|
initListOfCollection(); |
|
} |
|
|
|
bool KMSystemTray::excludeFolder( const Akonadi::Collection& collection ) const |
|
{ |
|
if(!collection.isValid()) { |
|
return true; |
|
} |
|
if(!collection.contentMimeTypes().contains(KMime::Message::mimeType())) { |
|
return true; |
|
} |
|
if ( CommonKernel->outboxCollectionFolder() == collection || |
|
CommonKernel->sentCollectionFolder() == collection || |
|
CommonKernel->templatesCollectionFolder() == collection || |
|
CommonKernel->trashCollectionFolder() == collection || |
|
CommonKernel->draftsCollectionFolder() == collection ) { |
|
return true; |
|
} |
|
|
|
if ( MailCommon::Util::isVirtualCollection( collection ) ) |
|
return true; |
|
return false; |
|
} |
|
} |
|
#include "kmsystemtray.moc"
|
|
|