kmail Library API Documentation

kmfoldertree.cpp

00001 // kmfoldertree.cpp
00002 #ifdef HAVE_CONFIG_H
00003 #include <config.h>
00004 #endif
00005 
00006 #include "kmfoldertree.h"
00007 
00008 #include "kmfoldermgr.h"
00009 #include "kmfolderimap.h"
00010 #include "kmfoldercachedimap.h"
00011 #include "kmfolderdia.h"
00012 #include "kmcomposewin.h"
00013 #include "kmmainwidget.h"
00014 #include "kmailicalifaceimpl.h"
00015 #include "kmacctmgr.h"
00016 #include "kmkernel.h"
00017 
00018 #include <maillistdrag.h>
00019 using namespace KPIM;
00020 
00021 #include <kapplication.h>
00022 #include <kglobalsettings.h>
00023 #include <kiconloader.h>
00024 #include <kmessagebox.h>
00025 #include <kconfig.h>
00026 #include <kdebug.h>
00027 
00028 #include <qpainter.h>
00029 #include <qcursor.h>
00030 #include <qregexp.h>
00031 
00032 #include <unistd.h>
00033 #include <assert.h>
00034 
00035 #include <X11/Xlib.h>
00036 #include <fixx11h.h>
00037 
00038 //=============================================================================
00039 
00040 KMFolderTreeItem::KMFolderTreeItem( KFolderTree *parent, const QString & name,
00041                     KFolderTreeItem::Protocol protocol )
00042   : QObject( parent, name.latin1() ),
00043     KFolderTreeItem( parent, name, protocol, Root ),
00044     mFolder( 0 )
00045 {
00046   init();
00047   setPixmap( 0, normalIcon() );
00048 }
00049 
00050 //-----------------------------------------------------------------------------
00051 KMFolderTreeItem::KMFolderTreeItem( KFolderTree *parent, const QString & name,
00052                     KMFolder* folder )
00053   : QObject( parent, name.latin1() ),
00054     KFolderTreeItem( parent, name ),
00055     mFolder( folder )
00056 {
00057   init();
00058   setPixmap( 0, normalIcon() );
00059 }
00060 
00061 //-----------------------------------------------------------------------------
00062 KMFolderTreeItem::KMFolderTreeItem( KFolderTreeItem *parent, const QString & name,
00063                     KMFolder* folder )
00064   : QObject( 0, name.latin1() ),
00065     KFolderTreeItem( parent, name ),
00066     mFolder( folder )
00067 {
00068   init();
00069   setPixmap( 0, normalIcon() );
00070 }
00071 
00072 KMFolderTreeItem::~KMFolderTreeItem() {
00073 }
00074 
00075 static KFolderTreeItem::Protocol protocolFor( KMFolderType t ) {
00076   switch ( t ) {
00077   case KMFolderTypeImap:
00078     return KFolderTreeItem::Imap;
00079   case KMFolderTypeCachedImap:
00080     return KFolderTreeItem::CachedImap;
00081   case KMFolderTypeMbox:
00082   case KMFolderTypeMaildir:
00083     return KFolderTreeItem::Local;
00084   case KMFolderTypeSearch:
00085     return KFolderTreeItem::Search;
00086   default:
00087     return KFolderTreeItem::NONE;
00088   }
00089 }
00090 
00091 QPixmap KMFolderTreeItem::normalIcon(int size) const
00092 {
00093   QString icon;
00094   if ( (!mFolder && type() == Root) || depth() == 0 ) {
00095     switch ( protocol() ) {
00096       case KFolderTreeItem::Imap:
00097       case KFolderTreeItem::CachedImap:
00098       case KFolderTreeItem::News:
00099         icon = "server"; break;
00100       case KFolderTreeItem::Search:
00101         icon = "viewmag";break;
00102       default:
00103         icon = "folder";break;
00104     }
00105   } else if ( mFolder->isSystemFolder() ) {
00106     switch ( type() ) {
00107       case Inbox: icon = "folder_inbox"; break;
00108       case Outbox: icon = "folder_outbox"; break;
00109       case SentMail: icon = "folder_sent_mail"; break;
00110       case Trash: icon = "trashcan_empty"; break;
00111       default: icon = kmkernel->iCalIface().folderPixmap( type() ); break;
00112       case Drafts: icon = "edit";break;
00113     }
00114   } else if ( protocol() == KMFolderTreeItem::Search) {
00115     icon = "mail_find";
00116   }
00117 
00118   if ( icon.isEmpty() )
00119     icon = "folder";
00120 
00121   if (mFolder && mFolder->useCustomIcons() ) {
00122     icon = mFolder->normalIconPath();
00123   }
00124   KIconLoader * il = KGlobal::instance()->iconLoader();
00125   QPixmap pm = il->loadIcon( icon, KIcon::Small, size,
00126                              KIcon::DefaultState, 0, true );
00127   if ( pm.isNull() ) {
00128       pm = il->loadIcon( mFolder->normalIconPath(), KIcon::Small, size,
00129                          KIcon::DefaultState, 0, true );
00130   }
00131 
00132   return pm;
00133 }
00134 
00135 QPixmap KMFolderTreeItem::unreadIcon(int size) const
00136 {
00137   QPixmap pm;
00138 
00139   if ( !mFolder || depth() == 0 || mFolder->isSystemFolder() )
00140     pm = normalIcon( size );
00141 
00142   KIconLoader * il = KGlobal::instance()->iconLoader();
00143   if ( mFolder->useCustomIcons() ) {
00144     pm = il->loadIcon( mFolder->unreadIconPath(), KIcon::Small, size,
00145                        KIcon::DefaultState, 0, true );
00146     if ( pm.isNull() )
00147       pm = il->loadIcon( mFolder->normalIconPath(), KIcon::Small, size,
00148                          KIcon::DefaultState, 0, true );
00149   }
00150   if ( pm.isNull() )
00151     pm = il->loadIcon( "folder_open", KIcon::Small, size,
00152                        KIcon::DefaultState, 0, true );
00153 
00154   return pm;
00155 }
00156 
00157 void KMFolderTreeItem::init()
00158 {
00159   if ( !mFolder )
00160     return;
00161 
00162   setProtocol( protocolFor( mFolder->folderType() ) );
00163 
00164   if ( depth() == 0 )
00165     setType(Root);
00166   else if (mFolder->isSystemFolder()) {
00167     if (mFolder == kmkernel->inboxFolder()
00168     || mFolder->folderType() == KMFolderTypeImap)
00169       setType(Inbox);
00170     else if (mFolder == kmkernel->outboxFolder())
00171       setType(Outbox);
00172     else if (mFolder == kmkernel->sentFolder())
00173       setType(SentMail);
00174     else if (mFolder == kmkernel->draftsFolder())
00175       setType(Drafts);
00176     else if (mFolder == kmkernel->trashFolder())
00177       setType(Trash);
00178     else if(kmkernel->iCalIface().isResourceImapFolder(mFolder))
00179       setType(kmkernel->iCalIface().folderType(mFolder));
00180   } else
00181     setRenameEnabled(0, false);
00182 }
00183 
00184 bool KMFolderTreeItem::adjustUnreadCount() {
00185   if ( !folder() )
00186     return false;
00187   const int count = folder()->countUnread();
00188   //if ( count == unreadCount() )
00189   //return false;
00190   setUnreadCount( count );
00191   if ( count > 0 )
00192     setPixmap( 0, unreadIcon() );
00193   else
00194     setPixmap( 0, normalIcon() );
00195 
00196   return true;
00197 }
00198 
00199 void KMFolderTreeItem::slotRepaint() {
00200   if ( unreadCount() > 0 )
00201     setPixmap( 0, unreadIcon() );
00202   else
00203     setPixmap( 0, normalIcon() );
00204   emit iconChanged( this );
00205   repaint();
00206 }
00207 
00208 
00209 //-----------------------------------------------------------------------------
00210 bool KMFolderTreeItem::acceptDrag(QDropEvent*) const
00211 {
00212   if ( !mFolder ||
00213       (mFolder->noContent() && childCount() == 0) ||
00214       (mFolder->noContent() && isOpen()) )
00215     return false;
00216   else
00217     return true;
00218 }
00219 
00220 //-----------------------------------------------------------------------------
00221 void KMFolderTreeItem::properties()
00222 {
00223   if ( !mFolder )
00224     return;
00225 
00226   KMFolderDialog *props;
00227 
00228   props = new KMFolderDialog( mFolder, mFolder->parent(), 0,
00229                               i18n("Properties of Folder %1").arg( mFolder->label() ) );
00230   props->exec();
00231   //Nothing here the above exec() may actually delete this KMFolderTreeItem
00232   return;
00233 }
00234 
00235 //-----------------------------------------------------------------------------
00236 //=============================================================================
00237 
00238 
00239 KMFolderTree::KMFolderTree( KMMainWidget *mainWidget, QWidget *parent,
00240                             const char *name )
00241   : KFolderTree( parent, name )
00242 {
00243   oldSelected = 0;
00244   oldCurrent = 0;
00245   mLastItem = 0;
00246   mMainWidget = mainWidget;
00247 
00248   addAcceptableDropMimetype(MailListDrag::format(), false);
00249 
00250   int namecol = addColumn( i18n("Folder"), 250 );
00251   header()->setStretchEnabled( true, namecol );
00252 
00253   // connect
00254   connectSignals();
00255 
00256   // popup to switch columns
00257   header()->setClickEnabled(true);
00258   header()->installEventFilter(this);
00259   mPopup = new KPopupMenu(this);
00260   mPopup->insertTitle(i18n("View Columns"));
00261   mPopup->setCheckable(true);
00262   mUnreadPop = mPopup->insertItem(i18n("Unread Column"), this, SLOT(slotToggleUnreadColumn()));
00263   mTotalPop = mPopup->insertItem(i18n("Total Column"), this, SLOT(slotToggleTotalColumn()));
00264 }
00265 
00266 //-----------------------------------------------------------------------------
00267 // connects all needed signals to their slots
00268 void KMFolderTree::connectSignals()
00269 {
00270   connect(&mUpdateTimer, SIGNAL(timeout()),
00271           this, SLOT(delayedUpdate()));
00272 
00273   connect(kmkernel->folderMgr(), SIGNAL(changed()),
00274       this, SLOT(doFolderListChanged()));
00275 
00276   connect(kmkernel->folderMgr(), SIGNAL(folderRemoved(KMFolder*)),
00277           this, SLOT(slotFolderRemoved(KMFolder*)));
00278 
00279   connect(kmkernel->imapFolderMgr(), SIGNAL(changed()),
00280           this, SLOT(doFolderListChanged()));
00281 
00282   connect(kmkernel->imapFolderMgr(), SIGNAL(folderRemoved(KMFolder*)),
00283           this, SLOT(slotFolderRemoved(KMFolder*)));
00284 
00285   connect(kmkernel->dimapFolderMgr(), SIGNAL(changed()),
00286           this, SLOT(doFolderListChanged()));
00287 
00288   connect(kmkernel->dimapFolderMgr(), SIGNAL(folderRemoved(KMFolder*)),
00289           this, SLOT(slotFolderRemoved(KMFolder*)));
00290 
00291   connect(kmkernel->searchFolderMgr(), SIGNAL(changed()),
00292           this, SLOT(doFolderListChanged()));
00293 
00294   connect(kmkernel->acctMgr(), SIGNAL(accountRemoved(KMAccount*)),
00295           this, SLOT(slotAccountRemoved(KMAccount*)));
00296 
00297   connect(kmkernel->searchFolderMgr(), SIGNAL(folderRemoved(KMFolder*)),
00298           this, SLOT(slotFolderRemoved(KMFolder*)));
00299 
00300   connect( &autoopen_timer, SIGNAL( timeout() ),
00301        this, SLOT( openFolder() ) );
00302 
00303   connect( &autoscroll_timer, SIGNAL( timeout() ),
00304        this, SLOT( autoScroll() ) );
00305 
00306   connect( this, SIGNAL( contextMenuRequested( QListViewItem*, const QPoint &, int ) ),
00307        this, SLOT( slotContextMenuRequested( QListViewItem*, const QPoint & ) ) );
00308 
00309   connect( this, SIGNAL( expanded( QListViewItem* ) ),
00310            this, SLOT( slotFolderExpanded( QListViewItem* ) ) );
00311 
00312   connect( this, SIGNAL( collapsed( QListViewItem* ) ),
00313            this, SLOT( slotFolderCollapsed( QListViewItem* ) ) );
00314 
00315   connect( this, SIGNAL( itemRenamed( QListViewItem*, int, const QString &)),
00316        this, SLOT( slotRenameFolder( QListViewItem*, int, const QString &)));
00317 }
00318 
00319 //-----------------------------------------------------------------------------
00320 bool KMFolderTree::event(QEvent *e)
00321 {
00322   if (e->type() == QEvent::ApplicationPaletteChange)
00323   {
00324      readColorConfig();
00325      return true;
00326   }
00327   bool result = KListView::event(e);
00328 
00329   if ( e->type() == QEvent::KeyPress && currentItem() != mLastItem )
00330     doFolderSelected( currentItem() );
00331 
00332   return result;
00333 }
00334 
00335 //-----------------------------------------------------------------------------
00336 void KMFolderTree::createFolderList(QStringList *str,
00337   QValueList<QGuardedPtr<KMFolder> > *folders)
00338 {
00339   for ( QListViewItemIterator it( this ) ; it.current() ; ++it ) {
00340     KMFolderTreeItem * fti = static_cast<KMFolderTreeItem*>(it.current());
00341     if ( !fti || !fti->folder() )
00342       continue;
00343 
00344     QString prefix;
00345     prefix.fill( ' ', 2 * fti->depth() );
00346     str->append(prefix + fti->text(0));
00347     if (fti->folder()->noContent()) folders->append(0);
00348     else folders->append(fti->folder());
00349   }
00350 }
00351 
00352 //-----------------------------------------------------------------------------
00353 void KMFolderTree::createImapFolderList(KMFolderImap *aFolder, QStringList *names,
00354   QStringList *urls, QStringList *mimeTypes)
00355 {
00356   for ( QListViewItemIterator it( this ) ; it.current() ; ++it ) {
00357     KMFolderTreeItem * fti = static_cast<KMFolderTreeItem*>(it.current());
00358     if ( !fti || !fti->folder() )
00359       continue;
00360 
00361     KMFolderImap *folder = static_cast<KMFolderImap*>(fti->folder());
00362     if ( folder != aFolder )
00363       continue;
00364 
00365     names->append(fti->text(0));
00366     urls->append(folder->imapPath());
00367     mimeTypes->append((folder->noContent()) ? "inode/directory" :
00368           (fti->isExpandable()) ? "message/directory" : "message/digest");
00369   }
00370 }
00371 
00372 //-----------------------------------------------------------------------------
00373 void KMFolderTree::readColorConfig (void)
00374 {
00375   KConfig* conf = KMKernel::config();
00376   // Custom/System color support
00377   KConfigGroupSaver saver(conf, "Reader");
00378   QColor c1=QColor(kapp->palette().active().text());
00379   QColor c2=QColor("blue");
00380   QColor c4=QColor(kapp->palette().active().base());
00381 
00382   if (!conf->readBoolEntry("defaultColors",TRUE)) {
00383     mPaintInfo.colFore = conf->readColorEntry("ForegroundColor",&c1);
00384     mPaintInfo.colUnread = conf->readColorEntry("UnreadMessage",&c2);
00385     mPaintInfo.colBack = conf->readColorEntry("BackgroundColor",&c4);
00386   }
00387   else {
00388     mPaintInfo.colFore = c1;
00389     mPaintInfo.colUnread = c2;
00390     mPaintInfo.colBack = c4;
00391   }
00392   QPalette newPal = kapp->palette();
00393   newPal.setColor( QColorGroup::Base, mPaintInfo.colBack );
00394   newPal.setColor( QColorGroup::Text, mPaintInfo.colFore );
00395   setPalette( newPal );
00396 }
00397 
00398 //-----------------------------------------------------------------------------
00399 void KMFolderTree::readConfig (void)
00400 {
00401   KConfig* conf = KMKernel::config();
00402   QString fntStr;
00403 
00404   // Backing pixmap support
00405   { //area for config group "Pixmaps"
00406     KConfigGroupSaver saver(conf, "Pixmaps");
00407     QString pixmapFile = conf->readPathEntry("FolderTree");
00408     mPaintInfo.pixmapOn = FALSE;
00409     if (!pixmapFile.isEmpty()) {
00410       mPaintInfo.pixmapOn = TRUE;
00411       mPaintInfo.pixmap = QPixmap( pixmapFile );
00412     }
00413   }
00414 
00415   readColorConfig();
00416 
00417   // Custom/Ssystem font support
00418   { //area for config group "Pixmaps"
00419     KConfigGroupSaver saver(conf, "Fonts");
00420     if (!conf->readBoolEntry("defaultFonts",TRUE)) {
00421       QFont folderFont( KGlobalSettings::generalFont() );
00422       setFont(conf->readFontEntry("folder-font", &folderFont));
00423     }
00424     else
00425       setFont(KGlobalSettings::generalFont());
00426   }
00427 
00428   // read D'n'D behaviour setting
00429   KConfigGroup behaviour( KMKernel::config(), "Behaviour" );
00430   mShowPopupAfterDnD = behaviour.readBoolEntry( "ShowPopupAfterDnD", true );
00431 
00432   // restore the layout
00433   restoreLayout(conf, "Geometry");
00434 }
00435 
00436 //-----------------------------------------------------------------------------
00437 // Save the configuration file
00438 void KMFolderTree::writeConfig()
00439 {
00440   // save the current state of the folders
00441   for ( QListViewItemIterator it( this ) ; it.current() ; ++it ) {
00442     KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00443     if (fti)
00444       writeIsListViewItemOpen(fti);
00445   }
00446 
00447   // save the current layout
00448   saveLayout(KMKernel::config(), "Geometry");
00449 }
00450 
00451 //-----------------------------------------------------------------------------
00452 // Updates the count of unread messages (count of unread messages
00453 // is now cached in KMails config file)
00454 void KMFolderTree::updateUnreadAll()
00455 {
00456   bool upd = isUpdatesEnabled();
00457   setUpdatesEnabled(FALSE);
00458 
00459   KMFolderDir* fdir;
00460   KMFolderNode* folderNode;
00461   KMFolder* folder;
00462 
00463   fdir = &kmkernel->folderMgr()->dir();
00464   for (folderNode = fdir->first();
00465     folderNode != 0;
00466     folderNode =fdir->next())
00467   {
00468     if (!folderNode->isDir()) {
00469       folder = static_cast<KMFolder*>(folderNode);
00470 
00471       folder->open();
00472       folder->countUnread();
00473       folder->close();
00474     }
00475   }
00476 
00477   setUpdatesEnabled(upd);
00478 }
00479 
00480 //-----------------------------------------------------------------------------
00481 // Draw empty area of list view with support for a backing pixmap
00482 void KMFolderTree::paintEmptyArea( QPainter * p, const QRect & rect )
00483 {
00484   if (mPaintInfo.pixmapOn)
00485     p->drawTiledPixmap( rect.left(), rect.top(), rect.width(), rect.height(),
00486             mPaintInfo.pixmap,
00487             rect.left() + contentsX(),
00488             rect.top() + contentsY() );
00489   else
00490     p->fillRect( rect, colorGroup().base() );
00491 }
00492 
00493 //-----------------------------------------------------------------------------
00494 // Reload the tree of items in the list view
00495 void KMFolderTree::reload(bool openFolders)
00496 {
00497   int top = contentsY();
00498   mLastItem = 0;
00499   for ( QListViewItemIterator it( this ) ; it.current() ; ++it ) {
00500     KMFolderTreeItem * fti = static_cast<KMFolderTreeItem*>(it.current());
00501     if (fti && fti->folder())
00502       disconnect(fti->folder(),SIGNAL(numUnreadMsgsChanged(KMFolder*)),
00503          this,SLOT(refresh()));
00504     writeIsListViewItemOpen( fti );
00505   }
00506   clear();
00507 
00508   // construct the root of the local folders
00509   KMFolderTreeItem * root = new KMFolderTreeItem( this, i18n("Local Folders") );
00510   root->setOpen( readIsListViewItemOpen(root) );
00511 
00512   KMFolderDir * fdir = &kmkernel->folderMgr()->dir();
00513   addDirectory(fdir, root);
00514 
00515   fdir = &kmkernel->imapFolderMgr()->dir();
00516   // each imap-account creates it's own root
00517   addDirectory(fdir, 0);
00518 
00519   fdir = &kmkernel->dimapFolderMgr()->dir();
00520   // each dimap-account creates it's own root
00521   addDirectory(fdir, 0);
00522 
00523   // construct the root of the search folder hierarchy:
00524   root = new KMFolderTreeItem( this, i18n("Searches"), KFolderTreeItem::Search );
00525   root->setOpen( readIsListViewItemOpen( root ) );
00526 
00527   fdir = &kmkernel->searchFolderMgr()->dir();
00528   addDirectory(fdir, root);
00529 
00530   if (openFolders)
00531   {
00532     // we open all folders to update the count
00533     mUpdateIterator = QListViewItemIterator (this);
00534     QTimer::singleShot( 0, this, SLOT(slotUpdateOneCount()) );
00535   }
00536 
00537   for ( QListViewItemIterator it( this ) ; it.current() ; ++it ) {
00538     KMFolderTreeItem * fti = static_cast<KMFolderTreeItem*>(it.current());
00539     if ( !fti || !fti->folder() )
00540       continue;
00541 
00542     // first disconnect before each connect
00543     // to make sure we don't call it several times with each reload
00544     disconnect(fti->folder(),SIGNAL(numUnreadMsgsChanged(KMFolder*)),
00545            this,SLOT(refresh()));
00546     connect(fti->folder(),SIGNAL(numUnreadMsgsChanged(KMFolder*)),
00547         this,SLOT(refresh()));
00548     disconnect(fti->folder(),SIGNAL(iconsChanged()),
00549            fti,SLOT(slotRepaint()));
00550     connect(fti->folder(),SIGNAL(iconsChanged()),
00551         fti,SLOT(slotRepaint()));
00552 
00553     disconnect(fti->folder(),SIGNAL(nameChanged()),
00554            fti,SLOT(slotNameChanged()));
00555     connect(fti->folder(),SIGNAL(nameChanged()),
00556         fti,SLOT(slotNameChanged()));
00557 
00558     if (isTotalActive() || isUnreadActive())
00559     {
00560 
00561       if (fti->folder()->folderType() == KMFolderTypeImap)
00562       {
00563     // imap-only
00564     disconnect(fti->folder(), SIGNAL(folderComplete(KMFolderImap*, bool)),
00565            this,SLOT(slotUpdateCounts(KMFolderImap*, bool)));
00566     connect(fti->folder(), SIGNAL(folderComplete(KMFolderImap*, bool)),
00567         this,SLOT(slotUpdateCounts(KMFolderImap*, bool)));
00568       } else {
00569     // others-only, imap doesn't need this because of the folderComplete-signal
00570     // we want to be noticed of changes to update the unread/total columns
00571         disconnect(fti->folder(), SIGNAL(numUnreadMsgsChanged(KMFolder*)),
00572            this,SLOT(slotUpdateCounts(KMFolder*)));
00573         connect(fti->folder(), SIGNAL(numUnreadMsgsChanged(KMFolder*)),
00574         this,SLOT(slotUpdateCounts(KMFolder*)));
00575     disconnect(fti->folder(), SIGNAL(msgAdded(KMFolder*,Q_UINT32)),
00576            this,SLOT(slotUpdateCounts(KMFolder*)));
00577     connect(fti->folder(), SIGNAL(msgAdded(KMFolder*,Q_UINT32)),
00578         this,SLOT(slotUpdateCounts(KMFolder*)));
00579       }
00580       disconnect(fti->folder(), SIGNAL(msgRemoved(KMFolder*)),
00581          this,SLOT(slotUpdateCounts(KMFolder*)));
00582       connect(fti->folder(), SIGNAL(msgRemoved(KMFolder*)),
00583           this,SLOT(slotUpdateCounts(KMFolder*)));
00584     }
00585     if (!openFolders)
00586       slotUpdateCounts(fti->folder());
00587   }
00588   ensureVisible(0, top + visibleHeight(), 0, 0);
00589   refresh();
00590 }
00591 
00592 //-----------------------------------------------------------------------------
00593 void KMFolderTree::slotUpdateOneCount()
00594 {
00595   if ( !mUpdateIterator.current() ) return;
00596   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(mUpdateIterator.current());
00597   ++mUpdateIterator;
00598   if ( !fti->folder() ) {
00599     // next one please
00600     QTimer::singleShot( 0, this, SLOT(slotUpdateOneCount()) );
00601     return;
00602   }
00603 
00604   // open the folder and update the count
00605   bool open = fti->folder()->isOpened();
00606   if (!open) fti->folder()->open();
00607   slotUpdateCounts(fti->folder());
00608   // restore previous state
00609   if (!open) fti->folder()->close();
00610 
00611   QTimer::singleShot( 0, this, SLOT(slotUpdateOneCount()) );
00612 }
00613 
00614 //-----------------------------------------------------------------------------
00615 // Recursively add a directory of folders to the tree of folders
00616 void KMFolderTree::addDirectory( KMFolderDir *fdir, KMFolderTreeItem* parent )
00617 {
00618   for ( KMFolderNode * node = fdir->first() ; node ; node = fdir->next() ) {
00619     if ( node->isDir() )
00620       continue;
00621 
00622     KMFolder * folder = static_cast<KMFolder*>(node);
00623     KMFolderTreeItem * fti = 0;
00624     if (!parent)
00625     {
00626       // create new root-item
00627       // it needs a folder e.g. to save it's state (open/close)
00628       fti = new KMFolderTreeItem( this, folder->label(), folder );
00629       fti->setExpandable( true );
00630     } else {
00631       // create new child
00632       fti = new KMFolderTreeItem( parent, folder->label(), folder );
00633       connect (fti, SIGNAL(iconChanged(KMFolderTreeItem*)),
00634                this, SIGNAL(iconChanged(KMFolderTreeItem*)));
00635       connect (fti, SIGNAL(nameChanged(KMFolderTreeItem*)),
00636                this, SIGNAL(nameChanged(KMFolderTreeItem*)));
00637     }
00638     // restore last open-state
00639     fti->setOpen( readIsListViewItemOpen(fti) );
00640 
00641     // add child-folders
00642     if (folder && folder->child())
00643       addDirectory( folder->child(), fti );
00644     // make sure that the folder-settings are correctly read on startup by calling listDirectory
00645    if (readIsListViewItemOpen(fti) &&
00646     fti->folder() && fti->folder()->folderType() == KMFolderTypeImap) {
00647       disconnect( this, SIGNAL( expanded( QListViewItem* ) ),
00648            this, SLOT( slotFolderExpanded( QListViewItem* ) ) );
00649       slotFolderExpanded(fti);
00650       connect( this, SIGNAL( expanded( QListViewItem* ) ),
00651            this, SLOT( slotFolderExpanded( QListViewItem* ) ) );
00652    }
00653   } // for-end
00654 }
00655 //-----------------------------------------------------------------------------
00656 // The folder neds a refresh!
00657 void KMFolderTree::refresh(KMFolder* folder, bool doUpdate)
00658 {
00659   reload();
00660   QListViewItem *qlvi = indexOfFolder( folder );
00661   if (qlvi)
00662   {
00663     qlvi->setOpen(true);
00664     setCurrentItem( qlvi );
00665     mMainWidget->slotMsgChanged();
00666 
00667     // FIXME: fugly, fugly hack that shows a deffinite design problem
00668     // this came over from kmoflderdia
00669     static_cast<KMHeaders*>(mMainWidget->child("headers"))->setFolder(folder);
00670   }
00671   if ( doUpdate )
00672     delayedUpdate();
00673 }
00674 
00675 //-----------------------------------------------------------------------------
00676 // Initiate a delayed refresh of the count of unread messages
00677 // Not really need anymore as count is cached in config file. But causes
00678 // a nice blink in the foldertree, that indicates kmail did something
00679 // when the user manually checks for mail and none was found.
00680 void KMFolderTree::refresh()
00681 {
00682   mUpdateTimer.changeInterval(200);
00683 }
00684 
00685 //-----------------------------------------------------------------------------
00686 // Updates the pixmap and extendedLabel information for items
00687 void KMFolderTree::delayedUpdate()
00688 {
00689   bool upd = isUpdatesEnabled();
00690   setUpdatesEnabled(FALSE);
00691 
00692   for ( QListViewItemIterator it( this ) ; it.current() ; ++it ) {
00693     KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00694     if (!fti || !fti->folder())
00695       continue;
00696 
00697     bool repaintRequired = fti->adjustUnreadCount();
00698 
00699     if (upd && repaintRequired)
00700       for (QListViewItem *p = fti; p; p = p->parent())
00701         p->repaint();
00702   }
00703   setUpdatesEnabled(upd);
00704   mUpdateTimer.stop();
00705 }
00706 
00707 //-----------------------------------------------------------------------------
00708 // Folders have been added/deleted update the tree of folders
00709 void KMFolderTree::doFolderListChanged()
00710 {
00711   KMFolderTreeItem* fti = static_cast< KMFolderTreeItem* >(currentItem());
00712   KMFolder* folder = (fti) ? fti->folder() : 0;
00713   reload();
00714   QListViewItem *qlvi = indexOfFolder(folder);
00715   if (qlvi) {
00716     setCurrentItem( qlvi );
00717     setSelected( qlvi, TRUE );
00718   }
00719 }
00720 
00721 //-----------------------------------------------------------------------------
00722 void KMFolderTree::slotAccountRemoved(KMAccount *)
00723 {
00724     doFolderSelected( firstChild() );
00725 }
00726 
00727 //-----------------------------------------------------------------------------
00728 void KMFolderTree::slotFolderRemoved(KMFolder *aFolder)
00729 {
00730   KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>
00731     (indexOfFolder(aFolder));
00732   if (!fti || !fti->folder()) return;
00733   if (fti == currentItem())
00734   {
00735     QListViewItem *qlvi = fti->itemAbove();
00736     if (!qlvi) qlvi = fti->itemBelow();
00737     doFolderSelected( qlvi );
00738   }
00739   delete fti;
00740 }
00741 
00742 //-----------------------------------------------------------------------------
00743 // Methods for navigating folders with the keyboard
00744 void KMFolderTree::prepareItem( KMFolderTreeItem* fti )
00745 {
00746   for ( QListViewItem * parent = fti->parent() ; parent ; parent = parent->parent() )
00747     parent->setOpen( TRUE );
00748   ensureItemVisible( fti );
00749 }
00750 
00751 //-----------------------------------------------------------------------------
00752 void KMFolderTree::nextUnreadFolder()
00753 {
00754     nextUnreadFolder( false );
00755 }
00756 
00757 //-----------------------------------------------------------------------------
00758 void KMFolderTree::nextUnreadFolder(bool confirm)
00759 {
00760   QListViewItemIterator it( currentItem() ? currentItem() : firstChild() );
00761   if ( currentItem() )
00762     ++it; // don't find current item
00763   for ( ; it.current() ; ++it ) {
00764     //check if folder is one to stop on
00765     KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00766     if (checkUnreadFolder(fti,confirm)) return;
00767   }
00768   //Now if confirm is true we are doing "ReadOn"
00769   //we have got to the bottom of the folder list
00770   //so we have to start at the top
00771   if (confirm) {
00772     for ( it = firstChild() ; it.current() ; ++it ) {
00773       //check if folder is one to stop on
00774       KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00775       if (checkUnreadFolder(fti,confirm)) return;
00776     }
00777   }
00778 }
00779 
00780 //-----------------------------------------------------------------------------
00781 bool KMFolderTree::checkUnreadFolder (KMFolderTreeItem* fti, bool confirm)
00782 {
00783   if (fti && fti->folder()  &&
00784       (fti->folder()->countUnread() > 0)) {
00785 
00786     // Don't change into the trash folder.
00787     if (fti->type() == KFolderTreeItem::Trash)
00788       return false;
00789 
00790     if (confirm) {
00791       //  warn user that going to next folder - but keep track of
00792       //  whether he wishes to be notified again in "AskNextFolder"
00793       //  parameter (kept in the config file for kmail)
00794       if ( KMessageBox::questionYesNo( this,
00795             i18n( "<qt>Go to the next unread message in folder <b>%1</b>?</qt>" )
00796             .arg( fti->folder()->label() ),
00797             i18n( "Go to the Next Unread Message" ),
00798             KStdGuiItem::yes(), KStdGuiItem::no(), // defaults
00799             "AskNextFolder",
00800             false)
00801           == KMessageBox::No ) return true;
00802     }
00803     prepareItem( fti );
00804     blockSignals( true );
00805     doFolderSelected( fti );
00806     blockSignals( false );
00807     emit folderSelectedUnread( fti->folder() );
00808     return true;
00809   }
00810   return false;
00811 }
00812 
00813 //-----------------------------------------------------------------------------
00814 void KMFolderTree::prevUnreadFolder()
00815 {
00816   QListViewItemIterator it( currentItem() ? currentItem() : lastItem() );
00817   if ( currentItem() )
00818     --it; // don't find current item
00819   for ( ; it.current() ; --it ) {
00820     KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00821     if (checkUnreadFolder(fti,false)) return;
00822   }
00823 }
00824 
00825 //-----------------------------------------------------------------------------
00826 void KMFolderTree::incCurrentFolder()
00827 {
00828   QListViewItemIterator it( currentItem() );
00829   ++it;
00830   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00831   if (fti && fti->folder()) {
00832       prepareItem( fti );
00833       setFocus();
00834       setCurrentItem( fti );
00835   }
00836 }
00837 
00838 //-----------------------------------------------------------------------------
00839 void KMFolderTree::decCurrentFolder()
00840 {
00841   QListViewItemIterator it( currentItem() );
00842   --it;
00843   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
00844   if (fti && fti->folder()) {
00845       prepareItem( fti );
00846       setFocus();
00847       setCurrentItem( fti );
00848   }
00849 }
00850 
00851 //-----------------------------------------------------------------------------
00852 void KMFolderTree::selectCurrentFolder()
00853 {
00854   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>( currentItem() );
00855   if (fti && fti->folder()) {
00856       prepareItem( fti );
00857       doFolderSelected( fti );
00858   }
00859 }
00860 
00861 //-----------------------------------------------------------------------------
00862 KMFolder *KMFolderTree::currentFolder() const
00863 {
00864     KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>( currentItem() );
00865     if (fti )
00866         return fti->folder();
00867     else
00868         return 0;
00869 }
00870 
00871 //-----------------------------------------------------------------------------
00872 // When not dragging and dropping a change in the selected item
00873 // indicates the user has changed the active folder emit a signal
00874 // so that the header list and reader window can be udpated.
00875 void KMFolderTree::doFolderSelected( QListViewItem* qlvi )
00876 {
00877   if (!qlvi) return;
00878 
00879   KMFolderTreeItem* fti = static_cast< KMFolderTreeItem* >(qlvi);
00880   KMFolder* folder = 0;
00881   if (fti) folder = fti->folder();
00882 
00883   if (mLastItem && mLastItem != fti && mLastItem->folder()
00884      && (mLastItem->folder()->folderType() == KMFolderTypeImap))
00885   {
00886     KMFolderImap *imapFolder = static_cast<KMFolderImap*>(mLastItem->folder());
00887     imapFolder->setSelected(FALSE);
00888     KMAcctImap *act = imapFolder->account();
00889     if (act)
00890     {
00891       // Can't we do without this? -till
00892       //act->killAllJobs();
00893       act->setIdle(TRUE);
00894     }
00895   }
00896   mLastItem = fti;
00897 
00898   clearSelection();
00899   setCurrentItem( qlvi );
00900   setSelected( qlvi, TRUE );
00901   if (!folder) {
00902     emit folderSelected(0); // Root has been selected
00903   }
00904   else {
00905     emit folderSelected(folder);
00906     if (folder->folderType() == KMFolderTypeImap)
00907     {
00908       KMFolderImap *imap_folder = static_cast<KMFolderImap*>(folder);
00909       imap_folder->setSelected(TRUE);
00910       if (imap_folder->getContentState() != KMFolderImap::imapInProgress)
00911         imap_folder->getAndCheckFolder();
00912     } else {
00913       // we don't need this for imap-folders because
00914       // they're updated with the folderComplete-signal
00915       slotUpdateCounts(folder);
00916     }
00917   }
00918 }
00919 
00920 //-----------------------------------------------------------------------------
00921 void KMFolderTree::resizeEvent(QResizeEvent* e)
00922 {
00923   KConfig* conf = KMKernel::config();
00924 
00925   KConfigGroupSaver saver(conf, "Geometry");
00926   conf->writeEntry(name(), size().width());
00927 
00928   KListView::resizeEvent(e);
00929 }
00930 
00931 //-----------------------------------------------------------------------------
00932 QListViewItem* KMFolderTree::indexOfFolder(const KMFolder* folder)
00933 {
00934   for ( QListViewItemIterator it( this ) ; it.current() ; ++it )
00935     if ( static_cast<KMFolderTreeItem*>(it.current())->folder() == folder )
00936       return it.current();
00937   return 0;
00938 }
00939 
00940 //-----------------------------------------------------------------------------
00941 // show context menu
00942 void KMFolderTree::slotContextMenuRequested( QListViewItem *lvi,
00943                                              const QPoint &p )
00944 {
00945   if (!lvi)
00946     return;
00947   setCurrentItem( lvi );
00948   setSelected( lvi, TRUE );
00949 
00950   if (!mMainWidget) return; // safe bet
00951 
00952   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(lvi);
00953   if ( fti != mLastItem )
00954     doFolderSelected( fti );
00955 
00956   if (!fti )
00957     return;
00958 
00959   KPopupMenu *folderMenu = new KPopupMenu;
00960   if (fti->folder()) folderMenu->insertTitle(fti->folder()->label());
00961 
00962   if ((!fti->folder() || (fti->folder()->noContent()
00963     && !fti->parent())))
00964   {
00965     QString createChild = i18n("&New Subfolder...");
00966     if (!fti->folder()) createChild = i18n("&New Folder...");
00967 
00968     if (fti->folder() || (fti->text(0) != i18n("Searches")))
00969     folderMenu->insertItem(SmallIcon("folder_new"),
00970                    createChild, this,
00971                    SLOT(addChildFolder()));
00972 
00973     if (!fti->folder()) {
00974       folderMenu->insertItem(i18n("&Compact All Folders"),
00975                      kmkernel->folderMgr(), SLOT(compactAll()));
00976       folderMenu->insertItem(i18n("&Expire All Folders"),
00977                  kmkernel->folderMgr(), SLOT(expireAll()));
00978     } else if (fti->folder()->folderType() == KMFolderTypeImap) {
00979       folderMenu->insertItem(SmallIcon("mail_get"), i18n("Check &Mail"),
00980         this,
00981         SLOT(slotCheckMail()));
00982     }
00983   } else {
00984     if ((fti->folder() == kmkernel->outboxFolder()) && (fti->folder()->count()) )
00985         folderMenu->insertItem(SmallIcon("mail_send"),
00986                                i18n("&Send Queued Messages"), mMainWidget,
00987                                SLOT(slotSendQueued()));
00988     if ((!fti->folder()->isSystemFolder() && 
00989      (fti->folder()->folderType() != KMFolderTypeSearch)) ||
00990     fti->folder()->folderType() == KMFolderTypeImap)
00991     {
00992       folderMenu->insertItem(SmallIcon("folder_new"),
00993                              i18n("&New Subfolder..."), this,
00994                              SLOT(addChildFolder()));
00995     }
00996 
00997     // Want to be able to display properties for ALL folders,
00998     // so we can edit expiry properties.
00999     // -- smp.
01000     if (!fti->folder()->noContent())
01001     {
01002       int itemId = folderMenu->insertItem( SmallIcon("goto"),
01003                                            i18n("Mark All Messages as &Read"),
01004                                            mMainWidget,
01005                                            SLOT( slotMarkAllAsRead() ) );
01006       folderMenu->setItemEnabled( itemId, fti->folder()->countUnread() > 0 );
01007 
01008       folderMenu->insertItem(i18n("&Compact"), mMainWidget,
01009                              SLOT(slotCompactFolder()));
01010 
01011       itemId = folderMenu->insertItem(i18n("&Expire"), mMainWidget,
01012                                       SLOT(slotExpireFolder()));
01013       folderMenu->setItemEnabled( itemId, fti->folder()->isAutoExpire() );
01014 
01015 
01016       folderMenu->insertSeparator();
01017 
01018       itemId = folderMenu->insertItem(SmallIcon("edittrash"),
01019         (kmkernel->folderIsTrash(fti->folder())) ? i18n("&Empty") :
01020                              i18n("&Move All Messages to Trash"), mMainWidget,
01021                              SLOT(slotEmptyFolder()));
01022       folderMenu->setItemEnabled( itemId, fti->folder()->count() > 0 );
01023     }
01024     if ( !fti->folder()->isSystemFolder() )
01025       folderMenu->insertItem(SmallIcon("editdelete"),
01026                              i18n("&Delete Folder"), mMainWidget,
01027                              SLOT(slotRemoveFolder()));
01028 
01029   }
01030   if (fti->folder() &&
01031       (fti->folder()->folderType() == KMFolderTypeImap || fti->folder()->folderType() == KMFolderTypeCachedImap ))
01032   {
01033     folderMenu->insertSeparator();
01034     folderMenu->insertItem(SmallIcon("configure"),
01035         i18n("Subscription..."), mMainWidget,
01036         SLOT(slotSubscriptionDialog()));
01037 
01038     if (!fti->folder()->noContent())
01039     {
01040       folderMenu->insertItem(SmallIcon("reload"), i18n("Check Mail in this Folder"), mMainWidget,
01041           SLOT(slotRefreshFolder()));
01042     }
01043     if ( fti->folder()->folderType() == KMFolderTypeCachedImap ) {
01044       KMFolderCachedImap * folder = static_cast<KMFolderCachedImap*>( fti->folder() );
01045       folderMenu->insertItem( SmallIcon("wizard"),
01046                   i18n("&Troubleshoot IMAP Cache..."),
01047                   folder, SLOT(slotTroubleshoot()) );
01048     }
01049   }
01050 
01051   if (fti->folder() && !fti->folder()->noContent())
01052   {
01053     folderMenu->insertSeparator();
01054     folderMenu->insertItem(SmallIcon("configure"),
01055         i18n("&Properties"),
01056         fti,
01057         SLOT(properties()));
01058   }
01059 
01060 
01061   kmkernel->setContextMenuShown( true );
01062   folderMenu->exec (p, 0);
01063   kmkernel->setContextMenuShown( false );
01064   triggerUpdate();
01065   delete folderMenu;
01066   folderMenu = 0;
01067 }
01068 
01069 //-----------------------------------------------------------------------------
01070 // If middle button and folder holds mailing-list, create a message to that list
01071 void KMFolderTree::contentsMouseReleaseEvent(QMouseEvent* me)
01072 {
01073   QListViewItem *lvi = currentItem(); // Needed for when branches are clicked on
01074   ButtonState btn = me->button();
01075   doFolderSelected(lvi);
01076 
01077   // get underlying folder
01078   KMFolderTreeItem* fti = dynamic_cast<KMFolderTreeItem*>(lvi);
01079 
01080   if (!fti || !fti->folder())
01081     return;
01082 
01083   // react on middle-button only
01084   if (btn != Qt::MidButton) return;
01085 
01086   if (!fti->folder()->isMailingList())
01087     return;
01088 
01089   KMMessage *msg = new KMMessage;
01090   msg->initHeader(fti->folder()->identity());
01091   msg->setTo(fti->folder()->mailingListPostAddress());
01092   KMComposeWin *win = new KMComposeWin(msg, fti->folder()->identity());
01093   win->show();
01094 
01095   KFolderTree::contentsMouseReleaseEvent(me);
01096 }
01097 
01098 //-----------------------------------------------------------------------------
01099 // Create a subfolder.
01100 // Requires creating the appropriate subdirectory and show a dialog
01101 void KMFolderTree::addChildFolder()
01102 {
01103   KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(currentItem());
01104   if (!fti)
01105     return;
01106   KMFolder *aFolder = fti->folder();
01107   if (fti->folder())
01108     if (!fti->folder()->createChildFolder())
01109       return;
01110 
01111   KMFolderDir *dir = &(kmkernel->folderMgr()->dir());
01112   if (fti->folder())
01113     dir = fti->folder()->child();
01114 
01115   KMFolderDialog *d =
01116     new KMFolderDialog(0, dir, mMainWidget, i18n("Create Subfolder") );
01117 
01118   if (d->exec()) /* fti may be deleted here */ {
01119     QListViewItem *qlvi = indexOfFolder( aFolder );
01120     if (qlvi) {
01121       qlvi->setOpen(TRUE);
01122       blockSignals( true );
01123       setCurrentItem( qlvi );
01124       blockSignals( false );
01125     }
01126   }
01127   delete d;
01128   // update if added to root Folder
01129   if (!aFolder || aFolder->noContent()) {
01130      doFolderListChanged();
01131   }
01132 }
01133 
01134 //-----------------------------------------------------------------------------
01135 // Returns whether a folder directory should be open as specified in the
01136 // config file.
01137 bool KMFolderTree::readIsListViewItemOpen(KMFolderTreeItem *fti)
01138 {
01139   KConfig* config = KMKernel::config();
01140   KMFolder *folder = fti->folder();
01141   QString name;
01142   if (folder)
01143   {
01144     name = "Folder-" + folder->idString();
01145   } else if (fti->type() == KFolderTreeItem::Root)
01146   {
01147     if (fti->protocol() == KFolderTreeItem::NONE) // local root
01148       name = "Folder_local_root";
01149     else if (fti->protocol() == KFolderTreeItem::Search)
01150       name = "Folder_search";
01151     else
01152       return false;
01153   } else {
01154     return false;
01155   }
01156   KConfigGroupSaver saver(config, name);
01157 
01158   return config->readBoolEntry("isOpen", true);
01159 }
01160 
01161 //-----------------------------------------------------------------------------
01162 // Saves open/closed state of a folder directory into the config file
01163 void KMFolderTree::writeIsListViewItemOpen(KMFolderTreeItem *fti)
01164 {
01165   KConfig* config = KMKernel::config();
01166   KMFolder *folder = fti->folder();
01167   QString name;
01168   if (folder)
01169   {
01170     name = "Folder-" + folder->idString();
01171   } else if (fti->type() == KFolderTreeItem::Root)
01172   {
01173     if (fti->protocol() == KFolderTreeItem::NONE) // local root
01174       name = "Folder_local_root";
01175     else if (fti->protocol() == KFolderTreeItem::Search)
01176       name = "Folder_search";
01177     else
01178       return;
01179   } else {
01180     return;
01181   }
01182   KConfigGroupSaver saver(config, name);
01183   config->writeEntry("isOpen", fti->isOpen());
01184 }
01185 
01186 
01187 //-----------------------------------------------------------------------------
01188 void KMFolderTree::cleanupConfigFile()
01189 {
01190   KConfig* config = KMKernel::config();
01191   QStringList existingFolders;
01192   QListViewItemIterator fldIt(this);
01193   QMap<QString,bool> folderMap;
01194   KMFolderTreeItem *fti;
01195   for (QListViewItemIterator fldIt(this); fldIt.current(); fldIt++)
01196   {
01197     fti = static_cast<KMFolderTreeItem*>(fldIt.current());
01198     if (fti && fti->folder())
01199       folderMap.insert(fti->folder()->idString(), fti->isExpandable());
01200   }
01201   QStringList groupList = config->groupList();
01202   QString name;
01203   for (QStringList::Iterator grpIt = groupList.begin();
01204     grpIt != groupList.end(); grpIt++)
01205   {
01206     if ((*grpIt).left(7) != "Folder-") continue;
01207     name = (*grpIt).mid(7);
01208     if (folderMap.find(name) == folderMap.end())
01209     {
01210       config->deleteGroup(*grpIt, TRUE);
01211       kdDebug(5006) << "Deleting information about folder " << name << endl;
01212     }
01213   }
01214 }
01215 
01216 
01217 //-----------------------------------------------------------------------------
01218 // Drag and Drop handling -- based on the Troll Tech dirview example
01219 
01220 enum {
01221   DRAG_COPY = 0,
01222   DRAG_MOVE = 1,
01223   DRAG_CANCEL = 2
01224 };
01225 
01226 //-----------------------------------------------------------------------------
01227 void KMFolderTree::openFolder()
01228 {
01229     autoopen_timer.stop();
01230     if ( dropItem && !dropItem->isOpen() ) {
01231         dropItem->setOpen( TRUE );
01232         dropItem->repaint();
01233     }
01234 }
01235 
01236 static const int autoopenTime = 750;
01237 
01238 //-----------------------------------------------------------------------------
01239 void KMFolderTree::contentsDragEnterEvent( QDragEnterEvent *e )
01240 {
01241   oldCurrent = 0;
01242   oldSelected = 0;
01243 
01244   oldCurrent = currentItem();
01245   for ( QListViewItemIterator it( this ) ; it.current() ; ++it )
01246     if ( it.current()->isSelected() )
01247       oldSelected = it.current();
01248 
01249   setFocus();
01250 
01251   QListViewItem *i = itemAt( contentsToViewport(e->pos()) );
01252   if ( i ) {
01253     dropItem = i;
01254     autoopen_timer.start( autoopenTime );
01255   }
01256   if ( !acceptDrag(e) ) {
01257     e->ignore();
01258   }
01259 }
01260 
01261 static const int autoscroll_margin = 16;
01262 static const int initialScrollTime = 30;
01263 static const int initialScrollAccel = 5;
01264 
01265 //-----------------------------------------------------------------------------
01266 void KMFolderTree::startAutoScroll()
01267 {
01268     if ( !autoscroll_timer.isActive() ) {
01269         autoscroll_time = initialScrollTime;
01270         autoscroll_accel = initialScrollAccel;
01271         autoscroll_timer.start( autoscroll_time );
01272     }
01273 }
01274 
01275 //-----------------------------------------------------------------------------
01276 void KMFolderTree::stopAutoScroll()
01277 {
01278     autoscroll_timer.stop();
01279 }
01280 
01281 //-----------------------------------------------------------------------------
01282 void KMFolderTree::autoScroll()
01283 {
01284     QPoint p = viewport()->mapFromGlobal( QCursor::pos() );
01285 
01286     if ( autoscroll_accel-- <= 0 && autoscroll_time ) {
01287         autoscroll_accel = initialScrollAccel;
01288         autoscroll_time--;
01289         autoscroll_timer.start( autoscroll_time );
01290     }
01291     int l = QMAX(1,(initialScrollTime-autoscroll_time));
01292 
01293     int dx=0,dy=0;
01294     if ( p.y() < autoscroll_margin ) {
01295         dy = -l;
01296     } else if ( p.y() > visibleHeight()-autoscroll_margin ) {
01297         dy = +l;
01298     }
01299     if ( p.x() < autoscroll_margin ) {
01300         dx = -l;
01301     } else if ( p.x() > visibleWidth()-autoscroll_margin ) {
01302         dx = +l;
01303     }
01304     if ( dx || dy ) {
01305         scrollBy(dx,dy);
01306     } else {
01307         stopAutoScroll();
01308     }
01309 }
01310 
01311 //-----------------------------------------------------------------------------
01312 void KMFolderTree::contentsDragMoveEvent( QDragMoveEvent *e )
01313 {
01314     QPoint vp = contentsToViewport(e->pos());
01315     QRect inside_margin((contentsX() > 0) ? autoscroll_margin : 0,
01316                         (contentsY() > 0) ? autoscroll_margin : 0,
01317       visibleWidth() - ((contentsX() + visibleWidth() < contentsWidth())
01318         ? autoscroll_margin*2 : 0),
01319       visibleHeight() - ((contentsY() + visibleHeight() < contentsHeight())
01320         ? autoscroll_margin*2 : 0));
01321     QListViewItem *i = itemAt( vp );
01322     if ( i ) {
01323         if ( acceptDrag(e) ) {
01324             setCurrentItem( i );
01325         }
01326         if ( !inside_margin.contains(vp) ) {
01327             startAutoScroll();
01328             e->accept(QRect(0,0,0,0)); // Keep sending move events
01329             autoopen_timer.stop();
01330         } else {
01331             if ( acceptDrag(e) ) {
01332                 e->accept();
01333             }
01334             else {
01335                 e->ignore();
01336             }
01337             if ( i != dropItem ) {
01338                 autoopen_timer.stop();
01339                 dropItem = i;
01340                 autoopen_timer.start( autoopenTime );
01341             }
01342         }
01343         if ( acceptDrag(e) ) {
01344             switch ( e->action() ) {
01345                 case QDropEvent::Copy:
01346                 break;
01347                 case QDropEvent::Move:
01348                 e->acceptAction();
01349                 break;
01350                 case QDropEvent::Link:
01351                 e->acceptAction();
01352                 break;
01353                 default:
01354                 ;
01355             }
01356         }
01357     } else {
01358         e->ignore();
01359         autoopen_timer.stop();
01360         dropItem = 0;
01361     }
01362 }
01363 
01364 //-----------------------------------------------------------------------------
01365 void KMFolderTree::contentsDragLeaveEvent( QDragLeaveEvent * )
01366 {
01367     if (!oldCurrent) return;
01368 
01369     autoopen_timer.stop();
01370     stopAutoScroll();
01371     dropItem = 0;
01372 
01373     setCurrentItem( oldCurrent );
01374     if (oldSelected)
01375       setSelected( oldSelected, TRUE );
01376 }
01377 
01378 //-----------------------------------------------------------------------------
01379 void KMFolderTree::contentsDropEvent( QDropEvent *e )
01380 {
01381     autoopen_timer.stop();
01382     stopAutoScroll();
01383 
01384     QListViewItem *item = itemAt( contentsToViewport(e->pos()) );
01385     if (! item ) e->ignore();
01386 
01387     KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
01388     if (fti && (fti != oldSelected) && (fti->folder()))
01389     {
01390       int root_x, root_y, win_x, win_y;
01391       uint keybstate;
01392       Window rootw, childw;
01393       XQueryPointer( qt_xdisplay(), qt_xrootwin(), &rootw, &childw,
01394           &root_x, &root_y, &win_x, &win_y, &keybstate );
01395 
01396       if ( keybstate & ControlMask ) {
01397         emit folderDropCopy(fti->folder());
01398       } else if ( keybstate & ShiftMask ) {
01399         emit folderDrop(fti->folder());
01400       } else {
01401         if ( mShowPopupAfterDnD ) {
01402           KPopupMenu *menu = new KPopupMenu( this );
01403           menu->insertItem( i18n("&Move Here"), DRAG_MOVE, 0 );
01404           menu->insertItem( SmallIcon("editcopy"), i18n("&Copy Here"), DRAG_COPY, 1 );
01405           menu->insertSeparator();
01406           menu->insertItem( SmallIcon("cancel"), i18n("C&ancel"), DRAG_CANCEL, 3 );
01407           int id = menu->exec( QCursor::pos(), 0 );
01408           switch(id) {
01409             case DRAG_COPY:
01410               emit folderDropCopy(fti->folder());
01411               break;
01412             case DRAG_MOVE:
01413               emit folderDrop(fti->folder());
01414               break;
01415             case DRAG_CANCEL:
01416               //just chill, doing nothing
01417               break;
01418             default:
01419               kdDebug(5006) << "Unknown dnd-type!" << endl;
01420           }
01421         }
01422         else
01423           emit folderDrop(fti->folder());
01424       }
01425       e->accept();
01426     } else
01427       e->ignore();
01428 
01429     dropItem = 0;
01430 
01431     clearSelection();
01432     setCurrentItem( oldCurrent );
01433     if ( oldSelected )
01434       setSelected( oldSelected, TRUE );
01435 }
01436 
01437 //-----------------------------------------------------------------------------
01438 void KMFolderTree::slotFolderExpanded( QListViewItem * item )
01439 {
01440   KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
01441   if (fti && fti->folder() && fti->folder()->folderType() == KMFolderTypeImap &&
01442       !fti->parent())
01443   {
01444     KMFolderImap *folder = static_cast<KMFolderImap*>(fti->folder());
01445     if (folder->getSubfolderState() == KMFolderImap::imapNoInformation)
01446     {
01447       // the tree will be reloaded after that
01448       bool success = folder->listDirectory();
01449       if (!success) fti->setOpen( false );
01450     }
01451   }
01452 }
01453 
01454 
01455 //-----------------------------------------------------------------------------
01456 void KMFolderTree::slotFolderCollapsed( QListViewItem * item )
01457 {
01458   KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
01459   if (fti && fti->parent() == firstChild() && fti->folder()
01460     && fti->folder()->folderType() == KMFolderTypeImap)
01461   {
01462     KMFolderImap *folder = static_cast<KMFolderImap*>(fti->folder());
01463     folder->setSubfolderState(KMFolderImap::imapNoInformation);
01464   }
01465 }
01466 
01467 //-----------------------------------------------------------------------------
01468 void KMFolderTree::slotRenameFolder(QListViewItem *item, int col,
01469         const QString &text)
01470 {
01471 
01472   KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
01473 
01474   if (fti && fti->folder() && col != 0 && !currentFolder()->child())
01475       return;
01476 
01477   QString fldName, oldFldName;
01478 
01479   oldFldName = fti->name(0);
01480 
01481   if (!text.isEmpty())
01482       fldName = text;
01483   else
01484       fldName = oldFldName;
01485 
01486   fldName.replace("/", "");
01487   fldName.replace(QRegExp("^\\."), "");
01488 
01489   if (fldName.isEmpty())
01490       fldName = i18n("unnamed");
01491 
01492   fti->setText(0, fldName);
01493   fti->folder()->rename(fldName, &(kmkernel->folderMgr()->dir()));
01494 }
01495 
01496 //-----------------------------------------------------------------------------
01497 void KMFolderTree::slotUpdateCounts(KMFolderImap * folder, bool success)
01498 {
01499   if (success) slotUpdateCounts(static_cast<KMFolder*>(folder));
01500 }
01501 
01502 //-----------------------------------------------------------------------------
01503 void KMFolderTree::slotUpdateCounts(KMFolder * folder)
01504 {
01505   QListViewItem * current;
01506 
01507   if (folder) current = indexOfFolder(folder);
01508   else current = currentItem();
01509 
01510   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(current);
01511   // sanity check
01512   if (!fti) return;
01513   if (!fti->folder()) fti->setTotalCount(-1);
01514 
01515   // get the unread count
01516   int count = 0;
01517   if (folder->noContent()) // always empty
01518     count = -1;
01519   else if (fti->folder()->countUnread() == 0)
01520     count = 0;
01521   else
01522     count = fti->folder()->countUnread();
01523 
01524   // set it
01525   bool repaint = false;
01526   if (fti->unreadCount() != count) repaint = true;
01527   fti->setUnreadCount(count);
01528 
01529   if (isTotalActive())
01530   {
01531     count = 0;
01532     // get the total-count
01533     if (fti->folder()->isOpened())
01534       count = fti->folder()->count();
01535     else
01536       count = fti->folder()->count(true); // count with caching
01537 
01538     if (fti->folder()->noContent())
01539       count = -1;
01540 
01541     // set it
01542     fti->setTotalCount(count);
01543   }
01544   if (repaint) {
01545     // repaint the item and it's parents
01546     for (QListViewItem *p = fti; p; p = p->parent())
01547       p->repaint();
01548   }
01549 }
01550 
01551 
01552 //-----------------------------------------------------------------------------
01553 void KMFolderTree::toggleColumn(int column, bool openFolders)
01554 {
01555   if (column == unread)
01556   {
01557     // switch unread
01558     if ( isUnreadActive() )
01559     {
01560       removeUnreadColumn();
01561       reload();
01562     } else {
01563       addUnreadColumn( i18n("Unread"), 70 );
01564       reload();
01565     }
01566     // toggle KPopupMenu
01567     mPopup->setItemChecked( mUnreadPop, isUnreadActive() );
01568 
01569   } else if (column == total) {
01570     // switch total
01571     if ( isTotalActive() )
01572     {
01573       removeTotalColumn();
01574       reload();
01575     } else {
01576       addTotalColumn( i18n("Total"), 70 );
01577       reload(openFolders);
01578     }
01579     // toggle KPopupMenu
01580     mPopup->setItemChecked( mTotalPop, isTotalActive() );
01581 
01582   } else kdDebug(5006) << "unknown column:" << column << endl;
01583 
01584   // toggles the switches of the mainwin
01585   emit columnsChanged();
01586 }
01587 
01588 //-----------------------------------------------------------------------------
01589 void KMFolderTree::slotToggleUnreadColumn()
01590 {
01591   toggleColumn(unread);
01592 }
01593 
01594 //-----------------------------------------------------------------------------
01595 void KMFolderTree::slotToggleTotalColumn()
01596 {
01597   // activate the total-column and force the folders to be opened
01598   toggleColumn(total, true);
01599 }
01600 
01601 //-----------------------------------------------------------------------------
01602 bool KMFolderTree::eventFilter( QObject *o, QEvent *e )
01603 {
01604   if ( e->type() == QEvent::MouseButtonPress &&
01605       static_cast<QMouseEvent*>(e)->button() == RightButton &&
01606       o->isA("QHeader") )
01607   {
01608     mPopup->popup( static_cast<QMouseEvent*>(e)->globalPos() );
01609     return true;
01610   }
01611   return KFolderTree::eventFilter(o, e);
01612 }
01613 
01614 //-----------------------------------------------------------------------------
01615 void KMFolderTree::slotCheckMail()
01616 {
01617   if (!currentItem())
01618     return;
01619   KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(currentItem());
01620   KMFolder* folder = fti->folder();
01621   if (folder && folder->folderType() == KMFolderTypeImap)
01622   {
01623     KMAccount* acct = static_cast<KMFolderImap*>(folder)->account();
01624     kmkernel->acctMgr()->singleCheckMail(acct, true);
01625   }
01626 }
01627 
01628 #include "kmfoldertree.moc"
01629 
KDE Logo
This file is part of the documentation for kmail Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat May 1 11:37:28 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003