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