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

kmail

  • sources
  • kde-4.14
  • kdepim
  • kmail
kmsystemtray.cpp
Go to the documentation of this file.
1 // -*- mode: C++; c-file-style: "gnu" -*-
2 /***************************************************************************
3  kmsystemtray.cpp - description
4  ------------------
5  begin : Fri Aug 31 22:38:44 EDT 2001
6  copyright : (C) 2001 by Ryan Breen
7  email : ryan@porivo.com
8 
9  Copyright (c) 2010-2015 Montel Laurent <montel@kde.org>
10  ***************************************************************************/
11 
12 /***************************************************************************
13  * *
14  * This program is free software; you can redistribute it and/or modify *
15  * it under the terms of the GNU General Public License as published by *
16  * the Free Software Foundation; either version 2 of the License, or *
17  * (at your option) any later version. *
18  * *
19  ***************************************************************************/
20 
21 
22 #include "kmsystemtray.h"
23 #include "kmmainwidget.h"
24 #include "settings/globalsettings.h"
25 #include "util/mailutil.h"
26 #include "mailcommon/kernel/mailkernel.h"
27 #include "mailcommon/folder/foldertreeview.h"
28 #include "mailcommon/collectionpage/attributes/newmailnotifierattribute.h"
29 
30 #include <kiconloader.h>
31 #include <kcolorscheme.h>
32 #include <kwindowsystem.h>
33 #include <kdebug.h>
34 #include <KMenu>
35 #include <KLocalizedString>
36 #include <KAction>
37 #include <KActionMenu>
38 #include "widgets/kactionmenutransport.h"
39 #include <KActionCollection>
40 
41 #include <QPainter>
42 
43 #include <Akonadi/ChangeRecorder>
44 #include <Akonadi/EntityTreeModel>
45 #include <Akonadi/CollectionModel>
46 #include <Akonadi/EntityMimeTypeFilterModel>
47 
48 using namespace MailCommon;
49 
61 namespace KMail {
62 KMSystemTray::KMSystemTray(QObject *parent)
63  : KStatusNotifierItem( parent),
64  mDesktopOfMainWin( 0 ),
65  mMode( GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread ),
66  mCount( 0 ),
67  mShowUnreadMailCount( true ),
68  mIconNotificationsEnabled( true ),
69  mNewMessagesPopup( 0 ),
70  mSendQueued( 0 )
71 {
72  kDebug() << "Initting systray";
73  setToolTipTitle( i18n("KMail") );
74  setToolTipIconByName( QLatin1String("kmail") );
75  setIconByName( QLatin1String("kmail") );
76  mIcon = KIcon( QLatin1String("mail-unread-new") );
77 
78  KMMainWidget * mainWidget = kmkernel->getKMMainWidget();
79  if ( mainWidget ) {
80  QWidget * mainWin = mainWidget->window();
81  if ( mainWin ) {
82  mDesktopOfMainWin = KWindowSystem::windowInfo( mainWin->winId(),
83  NET::WMDesktop ).desktop();
84  }
85  }
86 
87 
88  connect( KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), this, SLOT(slotGeneralPaletteChanged()));
89  connect( KGlobalSettings::self(), SIGNAL(kdisplayFontChanged()), this, SLOT(slotGeneralFontChanged()) );
90 
91  connect( this, SIGNAL(activateRequested(bool,QPoint)),
92  this, SLOT(slotActivated()) );
93  connect( contextMenu(), SIGNAL(aboutToShow()),
94  this, SLOT(slotContextMenuAboutToShow()) );
95 
96  connect( kmkernel->folderCollectionMonitor(), SIGNAL(collectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics)), SLOT(slotCollectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics)) );
97 
98  connect( kmkernel->folderCollectionMonitor(), SIGNAL(collectionAdded(Akonadi::Collection,Akonadi::Collection)), this, SLOT(initListOfCollection()) );
99  connect( kmkernel->folderCollectionMonitor(), SIGNAL(collectionRemoved(Akonadi::Collection)), this, SLOT(initListOfCollection()) );
100  connect( kmkernel->folderCollectionMonitor(), SIGNAL(collectionSubscribed(Akonadi::Collection,Akonadi::Collection)),SLOT(initListOfCollection()) );
101  connect( kmkernel->folderCollectionMonitor(), SIGNAL(collectionUnsubscribed(Akonadi::Collection)),SLOT(initListOfCollection()) );
102 
103  initListOfCollection();
104 
105 }
106 
107 bool KMSystemTray::buildPopupMenu()
108 {
109  KMMainWidget * mainWidget = kmkernel->getKMMainWidget();
110  if ( !mainWidget || kmkernel->shuttingDown() ) {
111  return false;
112  }
113 
114  if ( !contextMenu() ) {
115  setContextMenu( new KMenu() );
116  }
117 
118  contextMenu()->clear();
119 
120  contextMenu()->addTitle(qApp->windowIcon(), i18n("KMail"));
121  QAction * action;
122  if ( ( action = mainWidget->action(QLatin1String("check_mail")) ) )
123  contextMenu()->addAction( action );
124  if ( ( action = mainWidget->action(QLatin1String("check_mail_in")) ) )
125  contextMenu()->addAction( action );
126 
127  mSendQueued = mainWidget->sendQueuedAction();
128  contextMenu()->addAction( mSendQueued );
129  contextMenu()->addAction( mainWidget->sendQueueViaMenu() );
130 
131  contextMenu()->addSeparator();
132  if ( ( action = mainWidget->action(QLatin1String("new_message")) ) )
133  contextMenu()->addAction( action );
134  if ( ( action = mainWidget->action(QLatin1String("kmail_configure_kmail")) ) )
135  contextMenu()->addAction( action );
136  contextMenu()->addSeparator();
137  if ( (action = mainWidget->action(QLatin1String("akonadi_work_offline")) ) )
138  contextMenu()->addAction( action );
139  contextMenu()->addSeparator();
140 
141  if ( ( action = actionCollection()->action(QLatin1String("file_quit")) ) )
142  contextMenu()->addAction( action );
143 
144  return true;
145 }
146 
147 KMSystemTray::~KMSystemTray()
148 {
149 }
150 
151 void KMSystemTray::setShowUnreadCount(bool showUnreadCount)
152 {
153  if (mShowUnreadMailCount == showUnreadCount)
154  return;
155  mShowUnreadMailCount = showUnreadCount;
156  updateSystemTray();
157 }
158 
159 void KMSystemTray::setMode(int newMode)
160 {
161  if (newMode == mMode)
162  return;
163 
164  kDebug() << "Setting systray mMode to" << newMode;
165  mMode = newMode;
166 
167  switch ( mMode ) {
168  case GlobalSettings::EnumSystemTrayPolicy::ShowAlways:
169  setStatus( KStatusNotifierItem::Active );
170  break;
171  case GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread:
172  setStatus( mCount > 0 ? KStatusNotifierItem::Active : KStatusNotifierItem::Passive );
173  break;
174  default:
175  kDebug() << "Unknown systray mode" << mMode;
176  }
177 }
178 
179 int KMSystemTray::mode() const
180 {
181  return mMode;
182 }
183 
184 void KMSystemTray::slotGeneralFontChanged()
185 {
186  updateSystemTray();
187 }
188 
189 void KMSystemTray::slotGeneralPaletteChanged()
190 {
191  const KColorScheme scheme( QPalette::Active, KColorScheme::View );
192  mTextColor = scheme.foreground( KColorScheme::LinkText ).color();
193  updateSystemTray();
194 }
195 
196 
202 void KMSystemTray::updateCount()
203 {
204  if (mCount == 0 || !mIconNotificationsEnabled) {
205  setIconByName( QLatin1String("kmail") );
206  return;
207  }
208  if (mShowUnreadMailCount) {
209  int overlaySize = KIconLoader::SizeSmallMedium;
210  if (!mIcon.availableSizes().isEmpty()) {
211  overlaySize = mIcon.availableSizes().at(0).width();
212  }
213 
214  const QString countString = QString::number( mCount );
215  QFont countFont = KGlobalSettings::generalFont();
216  countFont.setBold(true);
217 
218  // decrease the size of the font for the number of unread messages if the
219  // number doesn't fit into the available space
220  float countFontSize = countFont.pointSizeF();
221  QFontMetrics qfm( countFont );
222  const int width = qfm.width( countString );
223  if ( width > (overlaySize - 2) ) {
224  countFontSize *= float( overlaySize - 2 ) / float( width );
225  countFont.setPointSizeF( countFontSize );
226  }
227 
228  // Paint the number in a pixmap
229  QPixmap overlayPixmap( overlaySize, overlaySize );
230  overlayPixmap.fill( Qt::transparent );
231 
232  QPainter p( &overlayPixmap );
233  p.setFont( countFont );
234  if (!mTextColor.isValid()) {
235  slotGeneralPaletteChanged();
236  }
237 
238  p.setBrush( Qt::NoBrush );
239  p.setPen( mTextColor );
240  p.setOpacity( 1.0 );
241  p.drawText( overlayPixmap.rect(),Qt::AlignCenter, countString );
242  p.end();
243 
244  QPixmap iconPixmap = mIcon.pixmap(overlaySize, overlaySize);
245 
246  QPainter pp(&iconPixmap);
247  pp.drawPixmap(0, 0, overlayPixmap);
248  pp.end();
249 
250  setIconByPixmap( iconPixmap );
251  } else {
252  setIconByPixmap( mIcon );
253  }
254 }
255 
256 void KMSystemTray::setSystrayIconNotificationsEnabled( bool enabled )
257 {
258  if ( enabled != mIconNotificationsEnabled ) {
259  mIconNotificationsEnabled = enabled;
260  updateSystemTray();
261  }
262 }
263 
268 void KMSystemTray::slotActivated()
269 {
270  KMMainWidget * mainWidget = kmkernel->getKMMainWidget();
271  if ( !mainWidget )
272  return ;
273 
274  QWidget *mainWin = mainWidget->window();
275  if ( !mainWin )
276  return ;
277 
278  KWindowInfo cur = KWindowSystem::windowInfo( mainWin->winId(), NET::WMDesktop );
279 
280  const int currentDesktop = KWindowSystem::currentDesktop();
281  const bool wasMinimized = cur.isMinimized();
282 
283  if ( cur.valid() )
284  mDesktopOfMainWin = cur.desktop();
285 
286  if (wasMinimized && (currentDesktop != mDesktopOfMainWin) && ( mDesktopOfMainWin == NET::OnAllDesktops ))
287  KWindowSystem::setOnDesktop(mainWin->winId(), currentDesktop);
288 
289  if ( mDesktopOfMainWin == NET::OnAllDesktops )
290  KWindowSystem::setOnAllDesktops( mainWin->winId(), true );
291 
292  KWindowSystem::activateWindow( mainWin->winId() );
293 
294  if (wasMinimized )
295  kmkernel->raise();
296 }
297 
298 void KMSystemTray::slotContextMenuAboutToShow()
299 {
300  // Rebuild popup menu before show to minimize race condition if
301  // the base KMainWidget is closed.
302  if ( !buildPopupMenu() ) {
303  return;
304  }
305 
306  if ( mNewMessagesPopup != 0 ) {
307  contextMenu()->removeAction( mNewMessagesPopup->menuAction() );
308  delete mNewMessagesPopup;
309  mNewMessagesPopup = 0;
310  }
311  mNewMessagesPopup = new KMenu();
312  fillFoldersMenu( mNewMessagesPopup, kmkernel->treeviewModelSelection() );
313 
314  connect( mNewMessagesPopup, SIGNAL(triggered(QAction*)), this,
315  SLOT(slotSelectCollection(QAction*)) );
316 
317 
318  if ( mCount > 0 ) {
319  mNewMessagesPopup->setTitle( i18n("New Messages In") );
320  contextMenu()->insertAction( mSendQueued, mNewMessagesPopup->menuAction() );
321  }
322 }
323 
324 void KMSystemTray::fillFoldersMenu( QMenu *menu, const QAbstractItemModel *model, const QString &parentName, const QModelIndex &parentIndex )
325 {
326  const int rowCount = model->rowCount( parentIndex );
327  for ( int row = 0; row < rowCount; ++row ) {
328  const QModelIndex index = model->index( row, 0, parentIndex );
329  const Akonadi::Collection collection = model->data( index, Akonadi::CollectionModel::CollectionRole ).value<Akonadi::Collection>();
330  qint64 count = 0;
331  if ( !excludeFolder( collection ) ) {
332  Akonadi::CollectionStatistics statistics = collection.statistics();
333  count = qMax( 0LL, statistics.unreadCount() );
334  if ( count > 0 ) {
335  if (ignoreNewMailInFolder(collection)) {
336  count = 0;
337  } else {
338  mCount += count;
339  }
340  }
341  }
342  QString label = parentName.isEmpty() ? QString() : QString(parentName + QLatin1String("->"));
343  label += model->data( index ).toString();
344  label.replace( QLatin1Char( '&' ), QLatin1String( "&&" ) );
345  if ( count > 0 ) {
346  // insert an item
347  QAction* action = menu->addAction( label );
348  action->setData( collection.id() );
349  }
350  if ( model->rowCount( index ) > 0 ) {
351  fillFoldersMenu( menu, model, label, index );
352  }
353  }
354 }
355 
356 void KMSystemTray::hideKMail()
357 {
358  KMMainWidget * mainWidget = kmkernel->getKMMainWidget();
359  if (!mainWidget)
360  return;
361  QWidget *mainWin = mainWidget->window();
362  Q_ASSERT(mainWin);
363  if (mainWin) {
364  mDesktopOfMainWin = KWindowSystem::windowInfo( mainWin->winId(),
365  NET::WMDesktop ).desktop();
366  // iconifying is unnecessary, but it looks cooler
367  KWindowSystem::minimizeWindow( mainWin->winId() );
368  mainWin->hide();
369  }
370 }
371 
372 void KMSystemTray::initListOfCollection()
373 {
374  mCount = 0;
375  const QAbstractItemModel *model = kmkernel->collectionModel();
376  if (model->rowCount() == 0) {
377  QTimer::singleShot(1000,this,SLOT(initListOfCollection()));
378  return;
379  }
380  unreadMail( model );
381 
382  if ( mMode == GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread ) {
383  if (status() == KStatusNotifierItem::Passive && (mCount > 0)) {
384  setStatus( KStatusNotifierItem::Active );
385  } else if ( status() == KStatusNotifierItem::Active && (mCount == 0) ) {
386  setStatus( KStatusNotifierItem::Passive );
387  }
388  }
389 
390  //kDebug()<<" mCount :"<<mCount;
391  updateCount();
392 }
393 
394 void KMSystemTray::unreadMail( const QAbstractItemModel *model, const QModelIndex& parentIndex )
395 {
396  const int rowCount = model->rowCount( parentIndex );
397  for ( int row = 0; row < rowCount; ++row ) {
398  const QModelIndex index = model->index( row, 0, parentIndex );
399  const Akonadi::Collection collection = model->data( index, Akonadi::CollectionModel::CollectionRole ).value<Akonadi::Collection>();
400 
401  if ( !excludeFolder( collection ) ) {
402 
403  const Akonadi::CollectionStatistics statistics = collection.statistics();
404  const qint64 count = qMax( 0LL, statistics.unreadCount() );
405 
406  if ( count > 0 ) {
407  if (!ignoreNewMailInFolder(collection)) {
408  mCount += count;
409  }
410  }
411  }
412  if ( model->rowCount( index ) > 0 ) {
413  unreadMail( model, index );
414  }
415  }
416  // Update tooltip to reflect count of unread messages
417  setToolTipSubTitle( mCount == 0 ? i18n("There are no unread messages")
418  : i18np("1 unread message",
419  "%1 unread messages",
420  mCount));
421 }
422 
423 bool KMSystemTray::hasUnreadMail() const
424 {
425  return ( mCount != 0 );
426 }
427 
428 void KMSystemTray::slotSelectCollection(QAction *act)
429 {
430  const Akonadi::Collection::Id id = act->data().value<Akonadi::Collection::Id>();
431  kmkernel->selectCollectionFromId( id );
432  KMMainWidget * mainWidget = kmkernel->getKMMainWidget();
433  if ( !mainWidget )
434  return ;
435  QWidget *mainWin = mainWidget->window();
436  if ( mainWin && !mainWin->isVisible() )
437  activate();
438 }
439 
440 void KMSystemTray::updateSystemTray()
441 {
442  initListOfCollection();
443 }
444 
445 void KMSystemTray::slotCollectionStatisticsChanged( Akonadi::Collection::Id id, const Akonadi::CollectionStatistics & )
446 {
447  //Exclude sent mail folder
448 
449  if ( CommonKernel->outboxCollectionFolder().id() == id ||
450  CommonKernel->sentCollectionFolder().id() == id ||
451  CommonKernel->templatesCollectionFolder().id() == id ||
452  CommonKernel->trashCollectionFolder().id() == id ||
453  CommonKernel->draftsCollectionFolder().id() == id ) {
454  return;
455  }
456  initListOfCollection();
457 }
458 
459 bool KMSystemTray::excludeFolder( const Akonadi::Collection& collection ) const
460 {
461  if (!collection.isValid()) {
462  return true;
463  }
464  if (!collection.contentMimeTypes().contains(KMime::Message::mimeType())) {
465  return true;
466  }
467  if ( CommonKernel->outboxCollectionFolder() == collection ||
468  CommonKernel->sentCollectionFolder() == collection ||
469  CommonKernel->templatesCollectionFolder() == collection ||
470  CommonKernel->trashCollectionFolder() == collection ||
471  CommonKernel->draftsCollectionFolder() == collection ) {
472  return true;
473  }
474 
475  if ( MailCommon::Util::isVirtualCollection( collection ) )
476  return true;
477  return false;
478 }
479 
480 bool KMSystemTray::ignoreNewMailInFolder(const Akonadi::Collection &collection)
481 {
482  if ( collection.hasAttribute<NewMailNotifierAttribute>() ) {
483  if (collection.attribute<NewMailNotifierAttribute>()->ignoreNewMail()) {
484  return true;
485  }
486  }
487  return false;
488 }
489 
490 }
KMMainWidget::action
QAction * action(const QString &name)
Definition: kmmainwidget.h:129
QModelIndex
globalsettings.h
QWidget
QAbstractItemModel::rowCount
virtual int rowCount(const QModelIndex &parent) const =0
QAbstractItemModel::index
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const =0
KMail::KMSystemTray::updateSystemTray
void updateSystemTray()
Definition: kmsystemtray.cpp:440
kmmainwidget.h
QWidget::window
QWidget * window() const
QFont::pointSizeF
qreal pointSizeF() const
QAction::data
QVariant data() const
QFont
QMenu::addAction
void addAction(QAction *action)
QWidget::isVisible
bool isVisible() const
QVariant::value
T value() const
GlobalSettings
Definition: globalsettings.h:31
KMail::KMSystemTray::~KMSystemTray
~KMSystemTray()
destructor
Definition: kmsystemtray.cpp:147
QPoint
QFontMetrics
KMail::KMSystemTray::setSystrayIconNotificationsEnabled
void setSystrayIconNotificationsEnabled(bool enable)
Use this method to disable any systray icon changing.
Definition: kmsystemtray.cpp:256
QFont::setBold
void setBold(bool enable)
QString::number
QString number(int n, int base)
KMail::KMSystemTray::mode
int mode() const
Definition: kmsystemtray.cpp:179
kactionmenutransport.h
QObject
QPainter
QString::isEmpty
bool isEmpty() const
kmsystemtray.h
KMMainWidget
Definition: kmmainwidget.h:91
QAbstractItemModel::data
virtual QVariant data(const QModelIndex &index, int role) const =0
QMenu::setTitle
void setTitle(const QString &title)
QWidget::winId
WId winId() const
QString
QWidget::hide
void hide()
kmkernel
#define kmkernel
Definition: kmkernel.h:24
QPixmap
QAction::setData
void setData(const QVariant &userData)
QMenu
KMail::KMSystemTray::hasUnreadMail
bool hasUnreadMail() const
Definition: kmsystemtray.cpp:423
KMMainWidget::sendQueueViaMenu
KActionMenuTransport * sendQueueViaMenu() const
Definition: kmmainwidget.h:135
QLatin1Char
QFont::setPointSizeF
void setPointSizeF(qreal pointSize)
KMail::KMSystemTray::setMode
void setMode(int mode)
Definition: kmsystemtray.cpp:159
QString::replace
QString & replace(int position, int n, QChar after)
QLatin1String
QAction
KMail::KMSystemTray::hideKMail
void hideKMail()
Definition: kmsystemtray.cpp:356
QAbstractItemModel
KStatusNotifierItem
QMenu::menuAction
QAction * menuAction() const
KMail::KMSystemTray::setShowUnreadCount
void setShowUnreadCount(bool showUnreadCount)
Definition: kmsystemtray.cpp:151
KMMainWidget::sendQueuedAction
KAction * sendQueuedAction() const
Definition: kmmainwidget.h:134
QVariant::toString
QString toString() const
QColor::isValid
bool isValid() const
QTimer::singleShot
singleShot
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:34:33 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kmail

Skip menu "kmail"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer
  • pimprint

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal