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 mPopupMenu = 0;
00112
00113 mPopupMenu = new KPopupMenu();
00114 KMMainWidget * mainWidget = kmkernel->getKMMainWidget();
00115 if ( !mainWidget )
00116 return;
00117
00118 mPopupMenu->insertTitle(*(this->pixmap()), "KMail");
00119 KAction * action;
00120 if ( ( action = mainWidget->action("check_mail") ) )
00121 action->plug( mPopupMenu );
00122 if ( ( action = mainWidget->action("check_mail_in") ) )
00123 action->plug( mPopupMenu );
00124 if ( ( action = mainWidget->action("send_queued") ) )
00125 action->plug( mPopupMenu );
00126 if ( ( action = mainWidget->action("send_queued_via") ) )
00127 action->plug( mPopupMenu );
00128 mPopupMenu->insertSeparator();
00129 if ( ( action = mainWidget->action("new_message") ) )
00130 action->plug( mPopupMenu );
00131 if ( ( action = mainWidget->action("kmail_configure_kmail") ) )
00132 action->plug( mPopupMenu );
00133 mPopupMenu->insertSeparator();
00134
00135 KMainWindow *mainWin = ::qt_cast<KMainWindow*>(kmkernel->getKMMainWidget()->topLevelWidget());
00136 if(mainWin)
00137 if ( ( action=mainWin->actionCollection()->action("file_quit") ) )
00138 action->plug( mPopupMenu );
00139 }
00140
00141 KMSystemTray::~KMSystemTray()
00142 {
00143
00144 kmkernel->unregisterSystemTrayApplet( this );
00145
00146 delete mPopupMenu;
00147 mPopupMenu = 0;
00148 }
00149
00150 void KMSystemTray::setMode(int newMode)
00151 {
00152 if(newMode == mMode) return;
00153
00154 kdDebug(5006) << "Setting systray mMode to " << newMode << endl;
00155 mMode = newMode;
00156
00157 switch ( mMode ) {
00158 case GlobalSettings::EnumSystemTrayPolicy::ShowAlways:
00159 if ( isHidden() )
00160 show();
00161 break;
00162 case GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread:
00163 if ( mCount == 0 && !isHidden() )
00164 hide();
00165 else if ( mCount > 0 && isHidden() )
00166 show();
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 }
00290 }
00291
00296 void KMSystemTray::mousePressEvent(QMouseEvent *e)
00297 {
00298
00299 if( e->button() == LeftButton )
00300 {
00301 if( mParentVisible && mainWindowIsOnCurrentDesktop() )
00302 hideKMail();
00303 else
00304 showKMail();
00305 }
00306
00307
00308 if( e->button() == RightButton )
00309 {
00310 mPopupFolders.clear();
00311 mPopupFolders.reserve( mFoldersWithUnread.count() );
00312
00313
00314
00315 buildPopupMenu();
00316
00317 if(mNewMessagePopupId != -1)
00318 {
00319 mPopupMenu->removeItem(mNewMessagePopupId);
00320 }
00321
00322 if(mFoldersWithUnread.count() > 0)
00323 {
00324 KPopupMenu *newMessagesPopup = new KPopupMenu();
00325
00326 QMap<QGuardedPtr<KMFolder>, int>::Iterator it = mFoldersWithUnread.begin();
00327 for(uint i=0; it != mFoldersWithUnread.end(); ++i)
00328 {
00329 kdDebug(5006) << "Adding folder" << endl;
00330 mPopupFolders.append( it.key() );
00331 QString item = prettyName(it.key()) + " (" + QString::number(it.data()) + ")";
00332 newMessagesPopup->insertItem(item, this, SLOT(selectedAccount(int)), 0, i);
00333 ++it;
00334 }
00335
00336 mNewMessagePopupId = mPopupMenu->insertItem(i18n("New Messages In"),
00337 newMessagesPopup, mNewMessagePopupId, 3);
00338
00339 kdDebug(5006) << "Folders added" << endl;
00340 }
00341
00342 mPopupMenu->popup(e->globalPos());
00343 }
00344
00345 }
00346
00351 QString KMSystemTray::prettyName(KMFolder * fldr)
00352 {
00353 QString rvalue = fldr->label();
00354 if(fldr->folderType() == KMFolderTypeImap)
00355 {
00356 KMFolderImap * imap = dynamic_cast<KMFolderImap*> (fldr->storage());
00357 assert(imap);
00358
00359 if((imap->account() != 0) &&
00360 (imap->account()->name() != 0) )
00361 {
00362 kdDebug(5006) << "IMAP folder, prepend label with type" << endl;
00363 rvalue = imap->account()->name() + "->" + rvalue;
00364 }
00365 }
00366
00367 kdDebug(5006) << "Got label " << rvalue << endl;
00368
00369 return rvalue;
00370 }
00371
00372
00373 bool KMSystemTray::mainWindowIsOnCurrentDesktop()
00374 {
00375 KMMainWidget * mainWidget = kmkernel->getKMMainWidget();
00376 if ( !mainWidget )
00377 return false;
00378
00379 QWidget *mainWin = kmkernel->getKMMainWidget()->topLevelWidget();
00380 if ( !mainWin )
00381 return false;
00382
00383 return KWin::windowInfo( mainWin->winId(),
00384 NET::WMDesktop ).isOnCurrentDesktop();
00385 }
00386
00391 void KMSystemTray::showKMail()
00392 {
00393 if (!kmkernel->getKMMainWidget())
00394 return;
00395 QWidget *mainWin = kmkernel->getKMMainWidget()->topLevelWidget();
00396 assert(mainWin);
00397 if(mainWin)
00398 {
00399 KWin::WindowInfo cur = KWin::windowInfo( mainWin->winId(), NET::WMDesktop );
00400 if ( cur.valid() ) mDesktopOfMainWin = cur.desktop();
00401
00402 if ( mDesktopOfMainWin != NET::OnAllDesktops )
00403 KWin::setCurrentDesktop( mDesktopOfMainWin );
00404 if ( !mParentVisible ) {
00405 if ( mDesktopOfMainWin == NET::OnAllDesktops )
00406 KWin::setOnAllDesktops( mainWin->winId(), true );
00407 mainWin->move( mPosOfMainWin );
00408 mainWin->show();
00409 }
00410 KWin::activateWindow( mainWin->winId() );
00411 mParentVisible = true;
00412 }
00413 kmkernel->raise();
00414
00415
00416 foldersChanged();
00417 }
00418
00419 void KMSystemTray::hideKMail()
00420 {
00421 if (!kmkernel->getKMMainWidget())
00422 return;
00423 QWidget *mainWin = kmkernel->getKMMainWidget()->topLevelWidget();
00424 assert(mainWin);
00425 if(mainWin)
00426 {
00427 mDesktopOfMainWin = KWin::windowInfo( mainWin->winId(),
00428 NET::WMDesktop ).desktop();
00429 mPosOfMainWin = mainWin->pos();
00430
00431 KWin::iconifyWindow( mainWin->winId() );
00432 mainWin->hide();
00433 mParentVisible = false;
00434 }
00435 }
00436
00443 void KMSystemTray::updateNewMessageNotification(KMFolder * fldr)
00444 {
00445
00446
00447 if( !fldr ||
00448 fldr->folderType() == KMFolderTypeSearch )
00449 {
00450
00451 return;
00452 }
00453
00454 mPendingUpdates[ fldr ] = true;
00455 if ( time( 0 ) - mLastUpdate > 2 ) {
00456 mUpdateTimer->stop();
00457 updateNewMessages();
00458 }
00459 else {
00460 mUpdateTimer->start(150, true);
00461 }
00462 }
00463
00464 void KMSystemTray::updateNewMessages()
00465 {
00466 for ( QMap<QGuardedPtr<KMFolder>, bool>::Iterator it = mPendingUpdates.begin();
00467 it != mPendingUpdates.end(); ++it)
00468 {
00469 KMFolder *fldr = it.key();
00470 if ( !fldr )
00471 continue;
00472
00474 int unread = fldr->countUnread();
00475
00476 QMap<QGuardedPtr<KMFolder>, int>::Iterator it =
00477 mFoldersWithUnread.find(fldr);
00478 bool unmapped = (it == mFoldersWithUnread.end());
00479
00482 if(unmapped) mCount += unread;
00483
00484
00485 else
00486 {
00487 int diff = unread - it.data();
00488 mCount += diff;
00489 }
00490
00491 if(unread > 0)
00492 {
00494 mFoldersWithUnread.insert(fldr, unread);
00495
00496 }
00497
00503 if(unmapped)
00504 {
00506 if(unread == 0) continue;
00507
00509 if ( ( mMode == GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread )
00510 && isHidden() ) {
00511 show();
00512 }
00513
00514 } else
00515 {
00516
00517 if(unread == 0)
00518 {
00519 kdDebug(5006) << "Removing folder from internal store " << fldr->name() << endl;
00520
00522 mFoldersWithUnread.remove(fldr);
00523
00525 if(mFoldersWithUnread.count() == 0)
00526 {
00527 mPopupFolders.clear();
00528 disconnect(this, SLOT(selectedAccount(int)));
00529
00530 mCount = 0;
00531
00532 if ( mMode == GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread ) {
00533 hide();
00534 }
00535 }
00536 }
00537 }
00538
00539 }
00540 mPendingUpdates.clear();
00541 updateCount();
00542
00544 QToolTip::remove(this);
00545 QToolTip::add(this, mCount == 0 ?
00546 i18n("There are no unread messages")
00547 : i18n("There is 1 unread message.",
00548 "There are %n unread messages.",
00549 mCount));
00550
00551 mLastUpdate = time( 0 );
00552 }
00553
00559 void KMSystemTray::selectedAccount(int id)
00560 {
00561 showKMail();
00562
00563 KMMainWidget * mainWidget = kmkernel->getKMMainWidget();
00564 if (!mainWidget)
00565 {
00566 kmkernel->openReader();
00567 mainWidget = kmkernel->getKMMainWidget();
00568 }
00569
00570 assert(mainWidget);
00571
00573 KMFolder * fldr = mPopupFolders.at(id);
00574 if(!fldr) return;
00575 KMFolderTree * ft = mainWidget->folderTree();
00576 if(!ft) return;
00577 QListViewItem * fldrIdx = ft->indexOfFolder(fldr);
00578 if(!fldrIdx) return;
00579
00580 ft->setCurrentItem(fldrIdx);
00581 ft->selectCurrentFolder();
00582 }
00583
00584 #include "kmsystemtray.moc"