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 Wed Jul 28 23:58:01 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003