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