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 break;
00168 default:
00169 kdDebug(5006) << k_funcinfo << " Unknown systray mode " << mMode << endl;
00170 }
00171 }
00172
00173 int KMSystemTray::mode() const
00174 {
00175 return mMode;
00176 }
00177
00183 void KMSystemTray::updateCount()
00184 {
00185 if(mCount != 0)
00186 {
00187 int oldPixmapWidth = pixmap()->size().width();
00188 int oldPixmapHeight = pixmap()->size().height();
00189
00190 QString countString = QString::number( mCount );
00191 QFont countFont = KGlobalSettings::generalFont();
00192 countFont.setBold(true);
00193
00194
00195
00196 float countFontSize = countFont.pointSizeFloat();
00197 QFontMetrics qfm( countFont );
00198 int width = qfm.width( countString );
00199 if( width > oldPixmapWidth )
00200 {
00201 countFontSize *= float( oldPixmapWidth ) / float( width );
00202 countFont.setPointSizeFloat( countFontSize );
00203 }
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222 QPixmap numberPixmap( oldPixmapWidth, oldPixmapHeight );
00223 numberPixmap.fill( Qt::white );
00224 QPainter p( &numberPixmap );
00225 p.setFont( countFont );
00226 p.setPen( Qt::blue );
00227 p.drawText( numberPixmap.rect(), Qt::AlignCenter, countString );
00228 numberPixmap.setMask( numberPixmap.createHeuristicMask() );
00229 QImage numberImage = numberPixmap.convertToImage();
00230
00231
00232 QImage iconWithNumberImage = mLightIconImage.copy();
00233 KIconEffect::overlay( iconWithNumberImage, numberImage );
00234
00235 QPixmap iconWithNumber;
00236 iconWithNumber.convertFromImage( iconWithNumberImage );
00237 setPixmap( iconWithNumber );
00238 } else
00239 {
00240 setPixmap( mDefaultIcon );
00241 }
00242 }
00243
00248 void KMSystemTray::foldersChanged()
00249 {
00254 mFoldersWithUnread.clear();
00255 mCount = 0;
00256
00257 if ( mMode == GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread ) {
00258 hide();
00259 }
00260
00262 disconnect(this, SLOT(updateNewMessageNotification(KMFolder *)));
00263
00264 QStringList folderNames;
00265 QValueList<QGuardedPtr<KMFolder> > folderList;
00266 kmkernel->folderMgr()->createFolderList(&folderNames, &folderList);
00267 kmkernel->imapFolderMgr()->createFolderList(&folderNames, &folderList);
00268 kmkernel->dimapFolderMgr()->createFolderList(&folderNames, &folderList);
00269 kmkernel->searchFolderMgr()->createFolderList(&folderNames, &folderList);
00270
00271 QStringList::iterator strIt = folderNames.begin();
00272
00273 for(QValueList<QGuardedPtr<KMFolder> >::iterator it = folderList.begin();
00274 it != folderList.end() && strIt != folderNames.end(); ++it, ++strIt)
00275 {
00276 KMFolder * currentFolder = *it;
00277 QString currentName = *strIt;
00278
00279 if ( ((!currentFolder->isSystemFolder() || (currentFolder->name().lower() == "inbox")) ||
00280 (currentFolder->folderType() == KMFolderTypeImap)) &&
00281 !currentFolder->ignoreNewMail() )
00282 {
00284 connect(currentFolder, SIGNAL(numUnreadMsgsChanged(KMFolder *)),
00285 this, SLOT(updateNewMessageNotification(KMFolder *)));
00286
00288 updateNewMessageNotification(currentFolder);
00289 }
00290 }
00291 }
00292
00297 void KMSystemTray::mousePressEvent(QMouseEvent *e)
00298 {
00299
00300 if( e->button() == LeftButton )
00301 {
00302 if( mParentVisible && mainWindowIsOnCurrentDesktop() )
00303 hideKMail();
00304 else
00305 showKMail();
00306 }
00307
00308
00309 if( e->button() == RightButton )
00310 {
00311 mPopupFolders.clear();
00312 mPopupFolders.reserve( mFoldersWithUnread.count() );
00313
00314
00315
00316 buildPopupMenu();
00317
00318 if(mNewMessagePopupId != -1)
00319 {
00320 mPopupMenu->removeItem(mNewMessagePopupId);
00321 }
00322
00323 if(mFoldersWithUnread.count() > 0)
00324 {
00325 KPopupMenu *newMessagesPopup = new KPopupMenu();
00326
00327 QMap<QGuardedPtr<KMFolder>, int>::Iterator it = mFoldersWithUnread.begin();
00328 for(uint i=0; it != mFoldersWithUnread.end(); ++i)
00329 {
00330 kdDebug(5006) << "Adding folder" << endl;
00331 mPopupFolders.append( it.key() );
00332 QString item = prettyName(it.key()) + " (" + QString::number(it.data()) + ")";
00333 newMessagesPopup->insertItem(item, this, SLOT(selectedAccount(int)), 0, i);
00334 ++it;
00335 }
00336
00337 mNewMessagePopupId = mPopupMenu->insertItem(i18n("New Messages In"),
00338 newMessagesPopup, mNewMessagePopupId, 3);
00339
00340 kdDebug(5006) << "Folders added" << endl;
00341 }
00342
00343 mPopupMenu->popup(e->globalPos());
00344 }
00345
00346 }
00347
00352 QString KMSystemTray::prettyName(KMFolder * fldr)
00353 {
00354 QString rvalue = fldr->label();
00355 if(fldr->folderType() == KMFolderTypeImap)
00356 {
00357 KMFolderImap * imap = dynamic_cast<KMFolderImap*> (fldr->storage());
00358 assert(imap);
00359
00360 if((imap->account() != 0) &&
00361 (imap->account()->name() != 0) )
00362 {
00363 kdDebug(5006) << "IMAP folder, prepend label with type" << endl;
00364 rvalue = imap->account()->name() + "->" + rvalue;
00365 }
00366 }
00367
00368 kdDebug(5006) << "Got label " << rvalue << endl;
00369
00370 return rvalue;
00371 }
00372
00373
00374 bool KMSystemTray::mainWindowIsOnCurrentDesktop()
00375 {
00376 KMMainWidget * mainWidget = kmkernel->getKMMainWidget();
00377 if ( !mainWidget )
00378 return false;
00379
00380 QWidget *mainWin = kmkernel->getKMMainWidget()->topLevelWidget();
00381 if ( !mainWin )
00382 return false;
00383
00384 return KWin::windowInfo( mainWin->winId(),
00385 NET::WMDesktop ).isOnCurrentDesktop();
00386 }
00387
00392 void KMSystemTray::showKMail()
00393 {
00394 if (!kmkernel->getKMMainWidget())
00395 return;
00396 QWidget *mainWin = kmkernel->getKMMainWidget()->topLevelWidget();
00397 assert(mainWin);
00398 if(mainWin)
00399 {
00400 KWin::WindowInfo cur = KWin::windowInfo( mainWin->winId(), NET::WMDesktop );
00401 if ( cur.valid() ) mDesktopOfMainWin = cur.desktop();
00402
00403 if ( mDesktopOfMainWin != NET::OnAllDesktops )
00404 KWin::setCurrentDesktop( mDesktopOfMainWin );
00405 if ( !mParentVisible ) {
00406 if ( mDesktopOfMainWin == NET::OnAllDesktops )
00407 KWin::setOnAllDesktops( mainWin->winId(), true );
00408 mainWin->move( mPosOfMainWin );
00409 mainWin->show();
00410 }
00411 KWin::activateWindow( mainWin->winId() );
00412 mParentVisible = true;
00413 }
00414 kmkernel->raise();
00415
00416
00417 foldersChanged();
00418 }
00419
00420 void KMSystemTray::hideKMail()
00421 {
00422 if (!kmkernel->getKMMainWidget())
00423 return;
00424 QWidget *mainWin = kmkernel->getKMMainWidget()->topLevelWidget();
00425 assert(mainWin);
00426 if(mainWin)
00427 {
00428 mDesktopOfMainWin = KWin::windowInfo( mainWin->winId(),
00429 NET::WMDesktop ).desktop();
00430 mPosOfMainWin = mainWin->pos();
00431
00432 KWin::iconifyWindow( mainWin->winId() );
00433 mainWin->hide();
00434 mParentVisible = false;
00435 }
00436 }
00437
00444 void KMSystemTray::updateNewMessageNotification(KMFolder * fldr)
00445 {
00446
00447
00448 if( !fldr ||
00449 fldr->folderType() == KMFolderTypeSearch )
00450 {
00451
00452 return;
00453 }
00454
00455 mPendingUpdates[ fldr ] = true;
00456 if ( time( 0 ) - mLastUpdate > 2 ) {
00457 mUpdateTimer->stop();
00458 updateNewMessages();
00459 }
00460 else {
00461 mUpdateTimer->start(150, true);
00462 }
00463 }
00464
00465 void KMSystemTray::updateNewMessages()
00466 {
00467 for ( QMap<QGuardedPtr<KMFolder>, bool>::Iterator it = mPendingUpdates.begin();
00468 it != mPendingUpdates.end(); ++it)
00469 {
00470 KMFolder *fldr = it.key();
00471 if ( !fldr )
00472 continue;
00473
00475 int unread = fldr->countUnread();
00476
00477 QMap<QGuardedPtr<KMFolder>, int>::Iterator it =
00478 mFoldersWithUnread.find(fldr);
00479 bool unmapped = (it == mFoldersWithUnread.end());
00480
00483 if(unmapped) mCount += unread;
00484
00485
00486 else
00487 {
00488 int diff = unread - it.data();
00489 mCount += diff;
00490 }
00491
00492 if(unread > 0)
00493 {
00495 mFoldersWithUnread.insert(fldr, unread);
00496
00497 }
00498
00504 if(unmapped)
00505 {
00507 if(unread == 0) continue;
00508
00510 if ( ( mMode == GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread )
00511 && isHidden() ) {
00512 show();
00513 }
00514
00515 } else
00516 {
00517
00518 if(unread == 0)
00519 {
00520 kdDebug(5006) << "Removing folder from internal store " << fldr->name() << endl;
00521
00523 mFoldersWithUnread.remove(fldr);
00524
00526 if(mFoldersWithUnread.count() == 0)
00527 {
00528 mPopupFolders.clear();
00529 disconnect(this, SLOT(selectedAccount(int)));
00530
00531 mCount = 0;
00532
00533 if ( mMode == GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread ) {
00534 hide();
00535 }
00536 }
00537 }
00538 }
00539
00540 }
00541 mPendingUpdates.clear();
00542 updateCount();
00543
00545 QToolTip::remove(this);
00546 QToolTip::add(this, mCount == 0 ?
00547 i18n("There are no unread messages")
00548 : i18n("There is 1 unread message.",
00549 "There are %n unread messages.",
00550 mCount));
00551
00552 mLastUpdate = time( 0 );
00553 }
00554
00560 void KMSystemTray::selectedAccount(int id)
00561 {
00562 showKMail();
00563
00564 KMMainWidget * mainWidget = kmkernel->getKMMainWidget();
00565 if (!mainWidget)
00566 {
00567 kmkernel->openReader();
00568 mainWidget = kmkernel->getKMMainWidget();
00569 }
00570
00571 assert(mainWidget);
00572
00574 KMFolder * fldr = mPopupFolders.at(id);
00575 if(!fldr) return;
00576 KMFolderTree * ft = mainWidget->folderTree();
00577 if(!ft) return;
00578 QListViewItem * fldrIdx = ft->indexOfFolder(fldr);
00579 if(!fldrIdx) return;
00580
00581 ft->setCurrentItem(fldrIdx);
00582 ft->selectCurrentFolder();
00583 }
00584
00585 #include "kmsystemtray.moc"