00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <config.h>
00020
00021 #include "kmsystemtray.h"
00022 #include "kmfoldertree.h"
00023 #include "kmfoldermgr.h"
00024 #include "kmfolderimap.h"
00025 #include "kmmainwidget.h"
00026 #include "kmacctmgr.h"
00027 #include "globalsettings.h"
00028
00029 #include <kapplication.h>
00030 #include <kmainwindow.h>
00031 #include <kglobalsettings.h>
00032 #include <kiconloader.h>
00033 #include <kiconeffect.h>
00034 #include <kwin.h>
00035 #include <kdebug.h>
00036
00037 #include <qpainter.h>
00038 #include <qbitmap.h>
00039 #include <qtooltip.h>
00040 #include <qwidgetlist.h>
00041 #include <qobjectlist.h>
00042
00043 #include <math.h>
00044 #include <assert.h>
00045
00057 KMSystemTray::KMSystemTray(QWidget *parent, const char *name)
00058 : KSystemTray( parent, name ),
00059 mParentVisible( true ),
00060 mPosOfMainWin( 0, 0 ),
00061 mDesktopOfMainWin( 0 ),
00062 mMode( GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread ),
00063 mCount( 0 ),
00064 mNewMessagePopupId(-1),
00065 mPopupMenu(0)
00066 {
00067 setAlignment( AlignCenter );
00068 kdDebug(5006) << "Initting systray" << endl;
00069
00070 mLastUpdate = time( 0 );
00071 mUpdateTimer = new QTimer( this, "systraytimer" );
00072 connect( mUpdateTimer, SIGNAL( timeout() ), SLOT( updateNewMessages() ) );
00073
00074 mDefaultIcon = loadIcon( "kmail" );
00075 mLightIconImage = loadIcon( "kmaillight" ).convertToImage();
00076
00077 setPixmap(mDefaultIcon);
00078
00079 KMMainWidget * mainWidget = getKMMainWidget();
00080 if ( mainWidget ) {
00081 QWidget * mainWin = mainWidget->topLevelWidget();
00082 if ( mainWin ) {
00083 mDesktopOfMainWin = KWin::windowInfo( mainWin->winId(),
00084 NET::WMDesktop ).desktop();
00085 mPosOfMainWin = mainWin->pos();
00086 }
00087 }
00088
00089
00090 kmkernel->registerSystemTrayApplet( this );
00091
00093 foldersChanged();
00094
00095 connect( kmkernel->folderMgr(), SIGNAL(changed()), SLOT(foldersChanged()));
00096 connect( kmkernel->imapFolderMgr(), SIGNAL(changed()), SLOT(foldersChanged()));
00097 connect( kmkernel->dimapFolderMgr(), SIGNAL(changed()), SLOT(foldersChanged()));
00098 connect( kmkernel->searchFolderMgr(), SIGNAL(changed()), SLOT(foldersChanged()));
00099
00100 connect( kmkernel->acctMgr(), SIGNAL( checkedMail( bool, bool, const QMap<QString, int> & ) ),
00101 SLOT( updateNewMessages() ) );
00102 }
00103
00104 void KMSystemTray::buildPopupMenu()
00105 {
00106
00107 delete mPopupMenu;
00108 mPopupMenu = 0;
00109
00110 mPopupMenu = new KPopupMenu();
00111 KMMainWidget * mainWidget = getKMMainWidget();
00112 if ( !mainWidget )
00113 return;
00114
00115 mPopupMenu->insertTitle(*(this->pixmap()), "KMail");
00116 KAction * action;
00117 if ( ( action = mainWidget->action("check_mail") ) )
00118 action->plug( mPopupMenu );
00119 if ( ( action = mainWidget->action("check_mail_in") ) )
00120 action->plug( mPopupMenu );
00121 mPopupMenu->insertSeparator();
00122 if ( ( action = mainWidget->action("new_message") ) )
00123 action->plug( mPopupMenu );
00124 if ( ( action = mainWidget->action("kmail_configure_kmail") ) )
00125 action->plug( mPopupMenu );
00126 mPopupMenu->insertSeparator();
00127
00128 KMainWindow *mainWin = ::qt_cast<KMainWindow*>(getKMMainWidget()->topLevelWidget());
00129 if(mainWin)
00130 if ( ( action=mainWin->actionCollection()->action("file_quit") ) )
00131 action->plug( mPopupMenu );
00132 }
00133
00134 KMSystemTray::~KMSystemTray()
00135 {
00136
00137 kmkernel->unregisterSystemTrayApplet( this );
00138
00139 delete mPopupMenu;
00140 mPopupMenu = 0;
00141 }
00142
00143 void KMSystemTray::setMode(int newMode)
00144 {
00145 if(newMode == mMode) return;
00146
00147 kdDebug(5006) << "Setting systray mMode to " << newMode << endl;
00148 mMode = newMode;
00149
00150 switch ( mMode ) {
00151 case GlobalSettings::EnumSystemTrayPolicy::ShowAlways:
00152 if ( isHidden() )
00153 show();
00154 break;
00155 case GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread:
00156 if ( mCount == 0 && !isHidden() )
00157 hide();
00158 else if ( mCount > 0 && isHidden() )
00159 show();
00160 default:
00161 kdDebug(5006) << k_funcinfo << " Unknown systray mode " << mMode << endl;
00162 }
00163 }
00164
00165 int KMSystemTray::mode() const
00166 {
00167 return mMode;
00168 }
00169
00175 void KMSystemTray::updateCount()
00176 {
00177 if(mCount != 0)
00178 {
00179 int oldPixmapWidth = pixmap()->size().width();
00180 int oldPixmapHeight = pixmap()->size().height();
00181
00182 QString countString = QString::number( mCount );
00183 QFont countFont = KGlobalSettings::generalFont();
00184 countFont.setBold(true);
00185
00186
00187
00188 float countFontSize = countFont.pointSizeFloat();
00189 QFontMetrics qfm( countFont );
00190 int width = qfm.width( countString );
00191 if( width > oldPixmapWidth )
00192 {
00193 countFontSize *= float( oldPixmapWidth ) / float( width );
00194 countFont.setPointSizeFloat( countFontSize );
00195 }
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214 QPixmap numberPixmap( oldPixmapWidth, oldPixmapHeight );
00215 numberPixmap.fill( Qt::white );
00216 QPainter p( &numberPixmap );
00217 p.setFont( countFont );
00218 p.setPen( Qt::blue );
00219 p.drawText( numberPixmap.rect(), Qt::AlignCenter, countString );
00220 numberPixmap.setMask( numberPixmap.createHeuristicMask() );
00221 QImage numberImage = numberPixmap.convertToImage();
00222
00223
00224 QImage iconWithNumberImage = mLightIconImage.copy();
00225 KIconEffect::overlay( iconWithNumberImage, numberImage );
00226
00227 QPixmap iconWithNumber;
00228 iconWithNumber.convertFromImage( iconWithNumberImage );
00229 setPixmap( iconWithNumber );
00230 } else
00231 {
00232 setPixmap( mDefaultIcon );
00233 }
00234 }
00235
00240 void KMSystemTray::foldersChanged()
00241 {
00246 mFoldersWithUnread.clear();
00247 mCount = 0;
00248
00249 if ( mMode == GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread ) {
00250 hide();
00251 }
00252
00254 disconnect(this, SLOT(updateNewMessageNotification(KMFolder *)));
00255
00256 QStringList folderNames;
00257 QValueList<QGuardedPtr<KMFolder> > folderList;
00258 kmkernel->folderMgr()->createFolderList(&folderNames, &folderList);
00259 kmkernel->imapFolderMgr()->createFolderList(&folderNames, &folderList);
00260 kmkernel->dimapFolderMgr()->createFolderList(&folderNames, &folderList);
00261 kmkernel->searchFolderMgr()->createFolderList(&folderNames, &folderList);
00262
00263 QStringList::iterator strIt = folderNames.begin();
00264
00265 for(QValueList<QGuardedPtr<KMFolder> >::iterator it = folderList.begin();
00266 it != folderList.end() && strIt != folderNames.end(); ++it, ++strIt)
00267 {
00268 KMFolder * currentFolder = *it;
00269 QString currentName = *strIt;
00270
00271 if ( ((!currentFolder->isSystemFolder() || (currentFolder->name().lower() == "inbox")) ||
00272 (currentFolder->folderType() == KMFolderTypeImap)) &&
00273 !currentFolder->ignoreNewMail() )
00274 {
00276 connect(currentFolder, SIGNAL(numUnreadMsgsChanged(KMFolder *)),
00277 this, SLOT(updateNewMessageNotification(KMFolder *)));
00278
00280 updateNewMessageNotification(currentFolder);
00281 }
00282 }
00283 }
00284
00289 void KMSystemTray::mousePressEvent(QMouseEvent *e)
00290 {
00291
00292 if( e->button() == LeftButton )
00293 {
00294 if( mParentVisible && mainWindowIsOnCurrentDesktop() )
00295 hideKMail();
00296 else
00297 showKMail();
00298 }
00299
00300
00301 if( e->button() == RightButton )
00302 {
00303 mPopupFolders.clear();
00304 mPopupFolders.resize(mFoldersWithUnread.count());
00305
00306
00307
00308 buildPopupMenu();
00309
00310 if(mNewMessagePopupId != -1)
00311 {
00312 mPopupMenu->removeItem(mNewMessagePopupId);
00313 }
00314
00315 if(mFoldersWithUnread.count() > 0)
00316 {
00317 KPopupMenu *newMessagesPopup = new KPopupMenu();
00318
00319 QMap<QGuardedPtr<KMFolder>, int>::Iterator it = mFoldersWithUnread.begin();
00320 for(uint i=0; it != mFoldersWithUnread.end(); ++i)
00321 {
00322 kdDebug(5006) << "Adding folder" << endl;
00323 if(i > mPopupFolders.size()) mPopupFolders.resize(i * 2);
00324 mPopupFolders.insert(i, it.key());
00325 QString item = prettyName(it.key()) + "(" + QString::number(it.data()) + ")";
00326 newMessagesPopup->insertItem(item, this, SLOT(selectedAccount(int)), 0, i);
00327 ++it;
00328 }
00329
00330 mNewMessagePopupId = mPopupMenu->insertItem(i18n("New Messages In"),
00331 newMessagesPopup, mNewMessagePopupId, 3);
00332
00333 kdDebug(5006) << "Folders added" << endl;
00334 }
00335
00336 mPopupMenu->popup(e->globalPos());
00337 }
00338
00339 }
00340
00345 QString KMSystemTray::prettyName(KMFolder * fldr)
00346 {
00347 QString rvalue = fldr->label();
00348 if(fldr->folderType() == KMFolderTypeImap)
00349 {
00350 KMFolderImap * imap = dynamic_cast<KMFolderImap*> (fldr->storage());
00351 assert(imap);
00352
00353 if((imap->account() != 0) &&
00354 (imap->account()->name() != 0) )
00355 {
00356 kdDebug(5006) << "IMAP folder, prepend label with type" << endl;
00357 rvalue = imap->account()->name() + "->" + rvalue;
00358 }
00359 }
00360
00361 kdDebug(5006) << "Got label " << rvalue << endl;
00362
00363 return rvalue;
00364 }
00365
00366
00367 bool KMSystemTray::mainWindowIsOnCurrentDesktop()
00368 {
00369 KMMainWidget * mainWidget = getKMMainWidget();
00370 if ( !mainWidget )
00371 return false;
00372
00373 QWidget *mainWin = getKMMainWidget()->topLevelWidget();
00374 if ( !mainWin )
00375 return false;
00376
00377 return KWin::windowInfo( mainWin->winId(),
00378 NET::WMDesktop ).isOnCurrentDesktop();
00379 }
00380
00385 void KMSystemTray::showKMail()
00386 {
00387 if (!getKMMainWidget())
00388 return;
00389 QWidget *mainWin = getKMMainWidget()->topLevelWidget();
00390 assert(mainWin);
00391 if(mainWin)
00392 {
00393
00394 if ( mDesktopOfMainWin != NET::OnAllDesktops )
00395 KWin::setCurrentDesktop( mDesktopOfMainWin );
00396 if ( !mParentVisible ) {
00397 if ( mDesktopOfMainWin == NET::OnAllDesktops )
00398 KWin::setOnAllDesktops( mainWin->winId(), true );
00399 mainWin->move( mPosOfMainWin );
00400 mainWin->show();
00401 }
00402 KWin::activateWindow( mainWin->winId() );
00403 mParentVisible = true;
00404 }
00405
00406
00407 foldersChanged();
00408 }
00409
00410 void KMSystemTray::hideKMail()
00411 {
00412 if (!getKMMainWidget())
00413 return;
00414 QWidget *mainWin = getKMMainWidget()->topLevelWidget();
00415 assert(mainWin);
00416 if(mainWin)
00417 {
00418 mDesktopOfMainWin = KWin::windowInfo( mainWin->winId(),
00419 NET::WMDesktop ).desktop();
00420 mPosOfMainWin = mainWin->pos();
00421
00422 KWin::iconifyWindow( mainWin->winId() );
00423 mainWin->hide();
00424 mParentVisible = false;
00425 }
00426 }
00427
00431 KMMainWidget * KMSystemTray::getKMMainWidget()
00432 {
00433 QWidgetList *l = kapp->topLevelWidgets();
00434 QWidgetListIt it( *l );
00435 QWidget *wid;
00436
00437 while ( (wid = it.current()) != 0 ) {
00438 ++it;
00439 QObjectList *l2 = wid->topLevelWidget()->queryList("KMMainWidget");
00440 if (l2 && l2->first())
00441 {
00442 KMMainWidget* kmmw = dynamic_cast<KMMainWidget *>(l2->first());
00443 assert (kmmw);
00444 delete l2;
00445 delete l;
00446 return kmmw;
00447 }
00448 delete l2;
00449 }
00450 delete l;
00451 return 0;
00452 }
00453
00460 void KMSystemTray::updateNewMessageNotification(KMFolder * fldr)
00461 {
00462
00463
00464 if( !fldr ||
00465 fldr->folderType() == KMFolderTypeSearch )
00466 {
00467
00468 return;
00469 }
00470
00471 mPendingUpdates[ fldr ] = true;
00472 if ( time( 0 ) - mLastUpdate > 2 ) {
00473 mUpdateTimer->stop();
00474 updateNewMessages();
00475 }
00476 else {
00477 mUpdateTimer->start(150, true);
00478 }
00479 }
00480
00481 void KMSystemTray::updateNewMessages()
00482 {
00483 for ( QMap<QGuardedPtr<KMFolder>, bool>::Iterator it = mPendingUpdates.begin();
00484 it != mPendingUpdates.end(); ++it)
00485 {
00486 KMFolder *fldr = it.key();
00487 if ( !fldr )
00488 continue;
00489
00491 int unread = fldr->countUnread();
00492
00493 QMap<QGuardedPtr<KMFolder>, int>::Iterator it =
00494 mFoldersWithUnread.find(fldr);
00495 bool unmapped = (it == mFoldersWithUnread.end());
00496
00499 if(unmapped) mCount += unread;
00500
00501
00502 else
00503 {
00504 int diff = unread - it.data();
00505 mCount += diff;
00506 }
00507
00508 if(unread > 0)
00509 {
00511 mFoldersWithUnread.insert(fldr, unread);
00512
00513 }
00514
00520 if(unmapped)
00521 {
00523 if(unread == 0) continue;
00524
00526 if ( ( mMode == GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread )
00527 && isHidden() ) {
00528 show();
00529 }
00530
00531 } else
00532 {
00533
00534 if(unread == 0)
00535 {
00536 kdDebug(5006) << "Removing folder from internal store " << fldr->name() << endl;
00537
00539 mFoldersWithUnread.remove(fldr);
00540
00542 if(mFoldersWithUnread.count() == 0)
00543 {
00544 mPopupFolders.clear();
00545 disconnect(this, SLOT(selectedAccount(int)));
00546
00547 mCount = 0;
00548
00549 if ( mMode == GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread ) {
00550 hide();
00551 }
00552 }
00553 }
00554 }
00555
00556 }
00557 mPendingUpdates.clear();
00558 updateCount();
00559
00561 QToolTip::remove(this);
00562 QToolTip::add(this, i18n("There is 1 unread message.",
00563 "There are %n unread messages.",
00564 mCount));
00565
00566 mLastUpdate = time( 0 );
00567 }
00568
00574 void KMSystemTray::selectedAccount(int id)
00575 {
00576 showKMail();
00577
00578 KMMainWidget * mainWidget = getKMMainWidget();
00579 if (!mainWidget)
00580 {
00581 kmkernel->openReader();
00582 mainWidget = getKMMainWidget();
00583 }
00584
00585 assert(mainWidget);
00586
00588 KMFolder * fldr = mPopupFolders.at(id);
00589 if(!fldr) return;
00590 KMFolderTree * ft = mainWidget->folderTree();
00591 if(!ft) return;
00592 QListViewItem * fldrIdx = ft->indexOfFolder(fldr);
00593 if(!fldrIdx) return;
00594
00595 ft->setCurrentItem(fldrIdx);
00596 ft->selectCurrentFolder();
00597 }
00598
00599 #include "kmsystemtray.moc"