summaryrefslogtreecommitdiffstats
path: root/kmail/kmfoldertree.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kmail/kmfoldertree.cpp')
-rw-r--r--kmail/kmfoldertree.cpp2126
1 files changed, 2126 insertions, 0 deletions
diff --git a/kmail/kmfoldertree.cpp b/kmail/kmfoldertree.cpp
new file mode 100644
index 000000000..6e67399c6
--- /dev/null
+++ b/kmail/kmfoldertree.cpp
@@ -0,0 +1,2126 @@
+// kmfoldertree.cpp
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "kmfoldertree.h"
+
+#include "kmfoldermgr.h"
+#include "kmfolder.h"
+#include "kmfolderimap.h"
+#include "kmfoldercachedimap.h"
+#include "kmfolderdia.h"
+#include "kmheaders.h"
+#include "kmmainwidget.h"
+#include "kmailicalifaceimpl.h"
+#include "accountmanager.h"
+using KMail::AccountManager;
+#include "globalsettings.h"
+#include "kmcommands.h"
+#include "foldershortcutdialog.h"
+#include "expirypropertiesdialog.h"
+#include "newfolderdialog.h"
+#include "acljobs.h"
+#include "messagecopyhelper.h"
+using KMail::MessageCopyHelper;
+#include "favoritefolderview.h"
+#include "folderviewtooltip.h"
+using KMail::FolderViewToolTip;
+
+#include <maillistdrag.h>
+using namespace KPIM;
+
+#include <kapplication.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <kconfig.h>
+#include <kpopupmenu.h>
+#include <kdebug.h>
+
+#include <qpainter.h>
+#include <qcursor.h>
+#include <qregexp.h>
+#include <qpopupmenu.h>
+
+#include <unistd.h>
+#include <assert.h>
+
+#include <X11/Xlib.h>
+#include <fixx11h.h>
+
+//=============================================================================
+
+KMFolderTreeItem::KMFolderTreeItem( KFolderTree *parent, const QString & name,
+ KFolderTreeItem::Protocol protocol )
+ : QObject( parent, name.latin1() ),
+ KFolderTreeItem( parent, name, protocol, Root ),
+ mFolder( 0 ), mNeedsRepaint( true )
+{
+ init();
+ setPixmap( 0, normalIcon( iconSize() ) );
+}
+
+//-----------------------------------------------------------------------------
+KMFolderTreeItem::KMFolderTreeItem( KFolderTree *parent, const QString & name,
+ KMFolder* folder )
+ : QObject( parent, name.latin1() ),
+ KFolderTreeItem( parent, name ),
+ mFolder( folder ), mNeedsRepaint( true )
+{
+ init();
+ setPixmap( 0, normalIcon( iconSize() ) );
+}
+
+//-----------------------------------------------------------------------------
+KMFolderTreeItem::KMFolderTreeItem( KFolderTreeItem *parent, const QString & name,
+ KMFolder* folder )
+ : QObject( 0, name.latin1() ),
+ KFolderTreeItem( parent, name ),
+ mFolder( folder ), mNeedsRepaint( true )
+{
+ init();
+ setPixmap( 0, normalIcon( iconSize() ) );
+}
+
+KMFolderTreeItem::~KMFolderTreeItem()
+{
+}
+
+static KFolderTreeItem::Protocol protocolFor( KMFolderType t ) {
+ switch ( t ) {
+ case KMFolderTypeImap:
+ return KFolderTreeItem::Imap;
+ case KMFolderTypeCachedImap:
+ return KFolderTreeItem::CachedImap;
+ case KMFolderTypeMbox:
+ case KMFolderTypeMaildir:
+ return KFolderTreeItem::Local;
+ case KMFolderTypeSearch:
+ return KFolderTreeItem::Search;
+ default:
+ return KFolderTreeItem::NONE;
+ }
+}
+
+QPixmap KMFolderTreeItem::normalIcon(int size) const
+{
+ QString icon;
+ if ( (!mFolder && type() == Root) || useTopLevelIcon() ) {
+ switch ( protocol() ) {
+ case KFolderTreeItem::Imap:
+ case KFolderTreeItem::CachedImap:
+ case KFolderTreeItem::News:
+ icon = "server"; break;
+ case KFolderTreeItem::Search:
+ icon = "viewmag";break;
+ default:
+ icon = "folder";break;
+ }
+ } else {
+ // special folders
+ switch ( type() ) {
+ case Inbox: icon = "folder_inbox"; break;
+ case Outbox: icon = "folder_outbox"; break;
+ case SentMail: icon = "folder_sent_mail"; break;
+ case Trash: icon = "trashcan_empty"; break;
+ case Drafts: icon = "edit"; break;
+ case Templates: icon = "filenew"; break;
+ default: icon = kmkernel->iCalIface().folderPixmap( type() ); break;
+ }
+ // non-root search folders
+ if ( protocol() == KMFolderTreeItem::Search ) {
+ icon = "mail_find";
+ }
+ if ( mFolder && mFolder->noContent() ) {
+ icon = "folder_grey";
+ }
+ }
+
+ if ( icon.isEmpty() )
+ icon = "folder";
+
+ if (mFolder && mFolder->useCustomIcons() ) {
+ icon = mFolder->normalIconPath();
+ }
+ KIconLoader * il = KGlobal::instance()->iconLoader();
+ QPixmap pm = il->loadIcon( icon, KIcon::Small, size,
+ KIcon::DefaultState, 0, true );
+ if ( mFolder && pm.isNull() ) {
+ pm = il->loadIcon( mFolder->normalIconPath(), KIcon::Small, size,
+ KIcon::DefaultState, 0, true );
+ }
+
+ return pm;
+}
+
+QPixmap KMFolderTreeItem::unreadIcon(int size) const
+{
+ QPixmap pm;
+
+ if ( !mFolder || useTopLevelIcon() || mFolder->isSystemFolder() ||
+ kmkernel->folderIsTrash( mFolder ) ||
+ kmkernel->folderIsTemplates( mFolder ) ||
+ kmkernel->folderIsDraftOrOutbox( mFolder ) )
+ pm = normalIcon( size );
+
+ KIconLoader * il = KGlobal::instance()->iconLoader();
+ if ( mFolder && mFolder->useCustomIcons() ) {
+ pm = il->loadIcon( mFolder->unreadIconPath(), KIcon::Small, size,
+ KIcon::DefaultState, 0, true );
+ if ( pm.isNull() )
+ pm = il->loadIcon( mFolder->normalIconPath(), KIcon::Small, size,
+ KIcon::DefaultState, 0, true );
+ }
+ if ( pm.isNull() ) {
+ if ( mFolder && mFolder->noContent() ) {
+ pm = il->loadIcon( "folder_grey_open", KIcon::Small, size,
+ KIcon::DefaultState, 0, true );
+ } else {
+ pm = il->loadIcon( kmkernel->iCalIface().folderPixmap( type() ),
+ KIcon::Small, size, KIcon::DefaultState, 0, true );
+ if ( pm.isNull() )
+ pm = il->loadIcon( "folder_open", KIcon::Small, size,
+ KIcon::DefaultState, 0, true );
+ }
+ }
+
+ return pm;
+}
+
+void KMFolderTreeItem::init()
+{
+ if ( !mFolder )
+ return;
+
+ setProtocol( protocolFor( mFolder->folderType() ) );
+
+ if ( useTopLevelIcon() )
+ setType(Root);
+ else {
+ if ( mFolder == kmkernel->inboxFolder() )
+ setType( Inbox );
+ else if ( kmkernel->folderIsDraftOrOutbox( mFolder ) ) {
+ if ( mFolder == kmkernel->outboxFolder() )
+ setType( Outbox );
+ else
+ setType( Drafts );
+ }
+ else if ( kmkernel->folderIsSentMailFolder( mFolder ) )
+ setType( SentMail );
+ else if ( kmkernel->folderIsTrash( mFolder ) )
+ setType( Trash );
+ else if ( kmkernel->folderIsTemplates( mFolder ) )
+ setType( Templates );
+ else if( kmkernel->iCalIface().isResourceFolder(mFolder) )
+ setType( kmkernel->iCalIface().folderType(mFolder) );
+ // System folders on dimap or imap which are not resource folders are
+ // inboxes. Urgs.
+ if ( mFolder->isSystemFolder() &&
+ !kmkernel->iCalIface().isResourceFolder( mFolder) &&
+ ( mFolder->folderType() == KMFolderTypeImap
+ || mFolder->folderType() == KMFolderTypeCachedImap ) )
+ setType( Inbox );
+ }
+ if ( !mFolder->isSystemFolder() )
+ setRenameEnabled( 0, false );
+
+ KMFolderTree* tree = dynamic_cast<KMFolderTree*>( listView() );
+ if ( tree )
+ tree->insertIntoFolderToItemMap( mFolder, this );
+}
+
+void KMFolderTreeItem::adjustUnreadCount( int newUnreadCount ) {
+ // adjust the icons if the folder is now newly unread or
+ // now newly not-unread
+ if ( newUnreadCount != 0 && unreadCount() == 0 )
+ setPixmap( 0, unreadIcon( iconSize() ) );
+ if ( unreadCount() != 0 && newUnreadCount == 0 )
+ setPixmap( 0, normalIcon( iconSize() ) );
+
+ setUnreadCount( newUnreadCount );
+}
+
+void KMFolderTreeItem::slotIconsChanged()
+{
+ kdDebug(5006) << k_funcinfo << endl;
+ // this is prone to change, so better check
+ if( kmkernel->iCalIface().isResourceFolder( mFolder ) )
+ setType( kmkernel->iCalIface().folderType(mFolder) );
+
+ if ( unreadCount() > 0 )
+ setPixmap( 0, unreadIcon( iconSize() ) );
+ else
+ setPixmap( 0, normalIcon( iconSize() ) );
+ emit iconChanged( this );
+ repaint();
+}
+
+void KMFolderTreeItem::slotNameChanged()
+{
+ setText( 0, mFolder->label() );
+ emit nameChanged( this );
+ repaint();
+}
+
+
+//-----------------------------------------------------------------------------
+bool KMFolderTreeItem::acceptDrag(QDropEvent* e) const
+{
+ // Do not allow drags from the favorite folder view, as they don't really
+ // make sense and do not work.
+ KMMainWidget *mainWidget = static_cast<KMFolderTree*>( listView() )->mainWidget();
+ assert( mainWidget );
+ if ( mainWidget->favoriteFolderView() &&
+ e->source() == mainWidget->favoriteFolderView()->viewport() )
+ return false;
+
+ if ( protocol() == KFolderTreeItem::Search )
+ return false; // nothing can be dragged into search folders
+
+ if ( e->provides( KPIM::MailListDrag::format() ) ) {
+ if ( !mFolder || mFolder->moveInProgress() || mFolder->isReadOnly() ||
+ (mFolder->noContent() && childCount() == 0) ||
+ (mFolder->noContent() && isOpen()) ) {
+ return false;
+ }
+ else {
+ return true;
+ }
+ } else if ( e->provides("application/x-qlistviewitem") ) {
+ // wtf: protocol() is NONE instead of Local for the local root folder
+ if ( !mFolder && protocol() == KFolderTreeItem::NONE && type() == KFolderTreeItem::Root )
+ return true; // local top-level folder
+ if ( !mFolder || mFolder->isReadOnly() || mFolder->noContent() )
+ return false;
+ return true;
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTreeItem::slotShowExpiryProperties()
+{
+ if ( !mFolder )
+ return;
+
+ KMFolderTree* tree = static_cast<KMFolderTree*>( listView() );
+ KMail::ExpiryPropertiesDialog *dlg =
+ new KMail::ExpiryPropertiesDialog( tree, mFolder );
+ dlg->show();
+}
+
+
+//-----------------------------------------------------------------------------
+void KMFolderTreeItem::properties()
+{
+ if ( !mFolder )
+ return;
+
+ KMail::FolderTreeBase* tree = static_cast<KMail::FolderTreeBase*>( listView() );
+ tree->mainWidget()->modifyFolder( this );
+ //Nothing here the above may actually delete this KMFolderTreeItem
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTreeItem::assignShortcut()
+{
+ if ( !mFolder )
+ return;
+
+ KMail::FolderShortcutDialog *shorty =
+ new KMail::FolderShortcutDialog( mFolder,
+ kmkernel->getKMMainWidget(),
+ listView() );
+ shorty->exec();
+ return;
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTreeItem::updateCount()
+{
+ if ( !folder() ) {
+ setTotalCount( -1 );
+ return;
+ }
+ KMail::FolderTreeBase* tree = dynamic_cast<KMail::FolderTreeBase*>( listView() );
+ if ( !tree ) return;
+
+ tree->slotUpdateCounts( folder(), true /* force update */ );
+}
+
+
+//=============================================================================
+
+
+KMFolderTree::KMFolderTree( KMMainWidget *mainWidget, QWidget *parent,
+ const char *name )
+ : KMail::FolderTreeBase( mainWidget, parent, name )
+ , mUpdateTimer( 0, "mUpdateTimer" )
+ , autoopen_timer( 0, "autoopen_timer" )
+{
+ oldSelected = 0;
+ oldCurrent = 0;
+ mLastItem = 0;
+ mMainWidget = mainWidget;
+ mReloading = false;
+ mCutFolder = false;
+
+ mUpdateCountTimer= new QTimer( this, "mUpdateCountTimer" );
+
+ setDragEnabled( true );
+ addAcceptableDropMimetype( "application/x-qlistviewitem", false );
+
+ setSelectionModeExt( Extended );
+
+ int namecol = addColumn( i18n("Folder"), 250 );
+ header()->setStretchEnabled( true, namecol );
+
+ // connect
+ connectSignals();
+
+ // popup to switch columns
+ header()->setClickEnabled(true);
+ header()->installEventFilter(this);
+ mPopup = new KPopupMenu(this);
+ mPopup->insertTitle(i18n("View Columns"));
+ mPopup->setCheckable(true);
+ mUnreadPop = mPopup->insertItem(i18n("Unread Column"), this, SLOT(slotToggleUnreadColumn()));
+ mTotalPop = mPopup->insertItem(i18n("Total Column"), this, SLOT(slotToggleTotalColumn()));
+ mSizePop = mPopup->insertItem(i18n("Size Column"), this, SLOT(slotToggleSizeColumn()));
+
+ connect( this, SIGNAL( triggerRefresh() ),
+ this, SLOT( refresh() ) );
+
+ new FolderViewToolTip( this );
+}
+
+//-----------------------------------------------------------------------------
+// connects all needed signals to their slots
+void KMFolderTree::connectSignals()
+{
+ connect( mUpdateCountTimer, SIGNAL(timeout()),
+ this, SLOT(slotUpdateCountTimeout()) );
+
+ connect(&mUpdateTimer, SIGNAL(timeout()),
+ this, SLOT(delayedUpdate()));
+
+ connect(kmkernel->folderMgr(), SIGNAL(changed()),
+ this, SLOT(doFolderListChanged()));
+
+ connect(kmkernel->folderMgr(), SIGNAL(folderRemoved(KMFolder*)),
+ this, SLOT(slotFolderRemoved(KMFolder*)));
+
+ connect(kmkernel->folderMgr(), SIGNAL(folderMoveOrCopyOperationFinished()),
+ this, SLOT(slotFolderMoveOrCopyOperationFinished()));
+
+ connect(kmkernel->imapFolderMgr(), SIGNAL(changed()),
+ this, SLOT(doFolderListChanged()));
+
+ connect(kmkernel->imapFolderMgr(), SIGNAL(folderRemoved(KMFolder*)),
+ this, SLOT(slotFolderRemoved(KMFolder*)));
+
+ connect(kmkernel->dimapFolderMgr(), SIGNAL(changed()),
+ this, SLOT(doFolderListChanged()));
+
+ connect(kmkernel->dimapFolderMgr(), SIGNAL(folderRemoved(KMFolder*)),
+ this, SLOT(slotFolderRemoved(KMFolder*)));
+
+ connect(kmkernel->searchFolderMgr(), SIGNAL(changed()),
+ this, SLOT(doFolderListChanged()));
+
+ connect(kmkernel->acctMgr(), SIGNAL(accountRemoved(KMAccount*)),
+ this, SLOT(slotAccountRemoved(KMAccount*)));
+
+ connect(kmkernel->acctMgr(), SIGNAL(accountAdded(KMAccount*)),
+ this, SLOT(slotUnhideLocalInbox()));
+
+ connect(kmkernel->searchFolderMgr(), SIGNAL(folderRemoved(KMFolder*)),
+ this, SLOT(slotFolderRemoved(KMFolder*)));
+
+ connect( &autoopen_timer, SIGNAL( timeout() ),
+ this, SLOT( openFolder() ) );
+
+ connect( this, SIGNAL( contextMenuRequested( QListViewItem*, const QPoint &, int ) ),
+ this, SLOT( slotContextMenuRequested( QListViewItem*, const QPoint & ) ) );
+
+ connect( this, SIGNAL( expanded( QListViewItem* ) ),
+ this, SLOT( slotFolderExpanded( QListViewItem* ) ) );
+
+ connect( this, SIGNAL( collapsed( QListViewItem* ) ),
+ this, SLOT( slotFolderCollapsed( QListViewItem* ) ) );
+
+ connect( this, SIGNAL( itemRenamed( QListViewItem*, int, const QString &)),
+ this, SLOT( slotRenameFolder( QListViewItem*, int, const QString &)));
+
+ connect( this, SIGNAL(folderSelected(KMFolder*)), SLOT(updateCopyActions()) );
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::readConfig (void)
+{
+ KConfig* conf = KMKernel::config();
+
+ readColorConfig();
+
+ // Custom/Ssystem font support
+ {
+ KConfigGroupSaver saver(conf, "Fonts");
+ if (!conf->readBoolEntry("defaultFonts",true)) {
+ QFont folderFont( KGlobalSettings::generalFont() );
+ setFont(conf->readFontEntry("folder-font", &folderFont));
+ }
+ else
+ setFont(KGlobalSettings::generalFont());
+ }
+
+ // restore the layout
+ restoreLayout(conf, "Geometry");
+}
+
+//-----------------------------------------------------------------------------
+// Save the configuration file
+void KMFolderTree::writeConfig()
+{
+ // save the current state of the folders
+ for ( QListViewItemIterator it( this ) ; it.current() ; ++it ) {
+ KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
+ if (fti)
+ writeIsListViewItemOpen(fti);
+ }
+
+ // save the current layout
+ saveLayout(KMKernel::config(), "Geometry");
+}
+
+//-----------------------------------------------------------------------------
+// Updates the count of unread messages (count of unread messages
+// is now cached in KMails config file)
+void KMFolderTree::updateUnreadAll()
+{
+ bool upd = isUpdatesEnabled();
+ setUpdatesEnabled(false);
+
+ KMFolderDir* fdir;
+ KMFolderNode* folderNode;
+ KMFolder* folder;
+
+ fdir = &kmkernel->folderMgr()->dir();
+ for (folderNode = fdir->first();
+ folderNode != 0;
+ folderNode =fdir->next())
+ {
+ if (!folderNode->isDir()) {
+ folder = static_cast<KMFolder*>(folderNode);
+
+ folder->open("updateunread");
+ folder->countUnread();
+ folder->close("updateunread");
+ }
+ }
+
+ setUpdatesEnabled(upd);
+}
+
+//-----------------------------------------------------------------------------
+// Reload the tree of items in the list view
+void KMFolderTree::reload(bool openFolders)
+{
+ if ( mReloading ) {
+ // no parallel reloads are allowed
+ kdDebug(5006) << "KMFolderTree::reload - already reloading" << endl;
+ return;
+ }
+ mReloading = true;
+
+ int top = contentsY();
+ mLastItem = 0;
+ // invalidate selected drop item
+ oldSelected = 0;
+ // remember last
+ KMFolder* last = currentFolder();
+ KMFolder* selected = 0;
+ KMFolder* oldCurrentFolder =
+ ( oldCurrent ? static_cast<KMFolderTreeItem*>(oldCurrent)->folder(): 0 );
+ for ( QListViewItemIterator it( this ) ; it.current() ; ++it ) {
+ KMFolderTreeItem * fti = static_cast<KMFolderTreeItem*>(it.current());
+ writeIsListViewItemOpen( fti );
+ if ( fti->isSelected() )
+ selected = fti->folder();
+ }
+ mFolderToItem.clear();
+ clear();
+
+ // construct the root of the local folders
+ KMFolderTreeItem * root = new KMFolderTreeItem( this, i18n("Local Folders") );
+ root->setOpen( readIsListViewItemOpen(root) );
+
+ KMFolderDir * fdir = &kmkernel->folderMgr()->dir();
+ addDirectory(fdir, root);
+
+ fdir = &kmkernel->imapFolderMgr()->dir();
+ // each imap-account creates it's own root
+ addDirectory(fdir, 0);
+
+ fdir = &kmkernel->dimapFolderMgr()->dir();
+ // each dimap-account creates it's own root
+ addDirectory(fdir, 0);
+
+ // construct the root of the search folder hierarchy:
+ root = new KMFolderTreeItem( this, i18n("Searches"), KFolderTreeItem::Search );
+ root->setOpen( readIsListViewItemOpen( root ) );
+
+ fdir = &kmkernel->searchFolderMgr()->dir();
+ addDirectory(fdir, root);
+
+ if (openFolders)
+ {
+ // we open all folders to update the count
+ mUpdateIterator = QListViewItemIterator (this);
+ QTimer::singleShot( 0, this, SLOT(slotUpdateOneCount()) );
+ }
+
+ for ( QListViewItemIterator it( this ) ; it.current() ; ++it ) {
+ KMFolderTreeItem * fti = static_cast<KMFolderTreeItem*>(it.current());
+ if ( !fti || !fti->folder() )
+ continue;
+
+ disconnect(fti->folder(),SIGNAL(iconsChanged()),
+ fti,SLOT(slotIconsChanged()));
+ connect(fti->folder(),SIGNAL(iconsChanged()),
+ fti,SLOT(slotIconsChanged()));
+
+ disconnect(fti->folder(),SIGNAL(nameChanged()),
+ fti,SLOT(slotNameChanged()));
+ connect(fti->folder(),SIGNAL(nameChanged()),
+ fti,SLOT(slotNameChanged()));
+
+ // we want to be noticed of changes to update the unread/total columns
+ disconnect(fti->folder(), SIGNAL(msgAdded(KMFolder*,Q_UINT32)),
+ this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
+ connect(fti->folder(), SIGNAL(msgAdded(KMFolder*,Q_UINT32)),
+ this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
+ //}
+
+ disconnect(fti->folder(), SIGNAL(numUnreadMsgsChanged(KMFolder*)),
+ this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
+ connect(fti->folder(), SIGNAL(numUnreadMsgsChanged(KMFolder*)),
+ this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
+ disconnect(fti->folder(), SIGNAL(msgRemoved(KMFolder*)),
+ this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
+ connect(fti->folder(), SIGNAL(msgRemoved(KMFolder*)),
+ this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
+
+ disconnect(fti->folder(), SIGNAL(folderSizeChanged( KMFolder* )),
+ this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
+ connect(fti->folder(), SIGNAL(folderSizeChanged( KMFolder* )),
+ this,SLOT(slotUpdateCountsDelayed(KMFolder*)));
+
+
+
+ disconnect(fti->folder(), SIGNAL(shortcutChanged(KMFolder*)),
+ mMainWidget, SLOT( slotShortcutChanged(KMFolder*)));
+ connect(fti->folder(), SIGNAL(shortcutChanged(KMFolder*)),
+ mMainWidget, SLOT( slotShortcutChanged(KMFolder*)));
+
+
+ if (!openFolders)
+ slotUpdateCounts(fti->folder());
+
+ // populate the size column
+ fti->setFolderSize( 0 );
+ fti->setFolderIsCloseToQuota( fti->folder()->storage()->isCloseToQuota() );
+
+ }
+ ensureVisible(0, top + visibleHeight(), 0, 0);
+ // if current and selected folder did not change set it again
+ for ( QListViewItemIterator it( this ) ; it.current() ; ++it )
+ {
+ if ( last &&
+ static_cast<KMFolderTreeItem*>( it.current() )->folder() == last )
+ {
+ mLastItem = static_cast<KMFolderTreeItem*>( it.current() );
+ setCurrentItem( it.current() );
+ }
+ if ( selected &&
+ static_cast<KMFolderTreeItem*>( it.current() )->folder() == selected )
+ {
+ setSelected( it.current(), true );
+ }
+ if ( oldCurrentFolder &&
+ static_cast<KMFolderTreeItem*>( it.current() )->folder() == oldCurrentFolder )
+ {
+ oldCurrent = it.current();
+ }
+ }
+ refresh();
+ mReloading = false;
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::slotUpdateOneCount()
+{
+ if ( !mUpdateIterator.current() ) return;
+ KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(mUpdateIterator.current());
+ ++mUpdateIterator;
+ if ( !fti->folder() ) {
+ // next one please
+ QTimer::singleShot( 0, this, SLOT(slotUpdateOneCount()) );
+ return;
+ }
+
+ // open the folder and update the count
+ bool open = fti->folder()->isOpened();
+ if (!open) fti->folder()->open("updatecount");
+ slotUpdateCounts(fti->folder());
+ // restore previous state
+ if (!open) fti->folder()->close("updatecount");
+
+ QTimer::singleShot( 0, this, SLOT(slotUpdateOneCount()) );
+}
+
+//-----------------------------------------------------------------------------
+// Recursively add a directory of folders to the tree of folders
+void KMFolderTree::addDirectory( KMFolderDir *fdir, KMFolderTreeItem* parent )
+{
+ for ( KMFolderNode * node = fdir->first() ; node ; node = fdir->next() ) {
+ if ( node->isDir() )
+ continue;
+
+ KMFolder * folder = static_cast<KMFolder*>(node);
+ KMFolderTreeItem * fti = 0;
+ if (!parent)
+ {
+ // create new root-item, but only if this is not the root of a
+ // "groupware folders only" account
+ if ( kmkernel->iCalIface().hideResourceAccountRoot( folder ) )
+ continue;
+ // it needs a folder e.g. to save it's state (open/close)
+ fti = new KMFolderTreeItem( this, folder->label(), folder );
+ fti->setExpandable( true );
+
+ // add child-folders
+ if (folder && folder->child()) {
+ addDirectory( folder->child(), fti );
+ }
+ } else {
+ // hide local inbox if unused
+ if ( kmkernel->inboxFolder() == folder && hideLocalInbox() ) {
+ connect( kmkernel->inboxFolder(), SIGNAL(msgAdded(KMFolder*,Q_UINT32)), SLOT(slotUnhideLocalInbox()) );
+ continue;
+ }
+
+ // create new child
+ fti = new KMFolderTreeItem( parent, folder->label(), folder );
+ // set folders explicitely to exandable when they have children
+ // this way we can do a listing for IMAP folders when the user expands them
+ // even when the child folders are not created yet
+ if ( folder->storage()->hasChildren() == FolderStorage::HasChildren ) {
+ fti->setExpandable( true );
+ } else {
+ fti->setExpandable( false );
+ }
+
+ // add child-folders
+ if (folder && folder->child()) {
+ addDirectory( folder->child(), fti );
+ }
+
+ // Check if this is an IMAP resource folder or a no-content parent only
+ // containing groupware folders
+ if ( (kmkernel->iCalIface().hideResourceFolder( folder ) || folder->noContent())
+ && fti->childCount() == 0 ) {
+ // It is
+ removeFromFolderToItemMap( folder );
+ delete fti;
+ continue;
+ }
+
+ connect (fti, SIGNAL(iconChanged(KMFolderTreeItem*)),
+ this, SIGNAL(iconChanged(KMFolderTreeItem*)));
+ connect (fti, SIGNAL(nameChanged(KMFolderTreeItem*)),
+ this, SIGNAL(nameChanged(KMFolderTreeItem*)));
+ }
+ // restore last open-state
+ fti->setOpen( readIsListViewItemOpen(fti) );
+ } // for-end
+}
+
+//-----------------------------------------------------------------------------
+// Initiate a delayed refresh of the tree
+void KMFolderTree::refresh()
+{
+ mUpdateTimer.changeInterval(200);
+}
+
+//-----------------------------------------------------------------------------
+// Updates the pixmap and extendedLabel information for items
+void KMFolderTree::delayedUpdate()
+{
+ bool upd = isUpdatesEnabled();
+ if ( upd ) {
+ setUpdatesEnabled(false);
+
+ for ( QListViewItemIterator it( this ) ; it.current() ; ++it ) {
+ KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
+ if (!fti || !fti->folder())
+ continue;
+
+ if ( fti->needsRepaint() ) {
+ fti->repaint();
+ fti->setNeedsRepaint( false );
+ }
+ }
+ setUpdatesEnabled(upd);
+ }
+ mUpdateTimer.stop();
+}
+
+//-----------------------------------------------------------------------------
+// Folders have been added/deleted update the tree of folders
+void KMFolderTree::doFolderListChanged()
+{
+ reload();
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::slotAccountRemoved(KMAccount *)
+{
+ doFolderSelected( firstChild() );
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::slotFolderMoveOrCopyOperationFinished()
+{
+ setDragEnabled( true );
+}
+//-----------------------------------------------------------------------------
+void KMFolderTree::slotFolderRemoved(KMFolder *aFolder)
+{
+ QListViewItem *item = indexOfFolder(aFolder);
+ if (!item) return;
+ KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*> ( item );
+ if ( oldCurrent == fti )
+ oldCurrent = 0;
+ if ( oldSelected == fti )
+ oldSelected = 0;
+ if (!fti || !fti->folder()) return;
+ if (fti == currentItem())
+ {
+ QListViewItem *qlvi = fti->itemAbove();
+ if (!qlvi) qlvi = fti->itemBelow();
+ doFolderSelected( qlvi );
+ }
+ removeFromFolderToItemMap( aFolder );
+
+ if ( dropItem == fti ) { // The removed item is the dropItem
+ dropItem = 0; // it becomes invalid
+ }
+
+ delete fti;
+ updateCopyActions();
+}
+
+//-----------------------------------------------------------------------------
+// Methods for navigating folders with the keyboard
+void KMFolderTree::prepareItem( KMFolderTreeItem* fti )
+{
+ for ( QListViewItem * parent = fti->parent() ; parent ; parent = parent->parent() )
+ parent->setOpen( true );
+ ensureItemVisible( fti );
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::nextUnreadFolder()
+{
+ nextUnreadFolder( false );
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::nextUnreadFolder(bool confirm)
+{
+ QListViewItemIterator it( currentItem() ? currentItem() : firstChild() );
+ if ( currentItem() )
+ ++it; // don't find current item
+ for ( ; it.current() ; ++it ) {
+ //check if folder is one to stop on
+ KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
+ if (checkUnreadFolder(fti,confirm)) return;
+ }
+ //Now if confirm is true we are doing "ReadOn"
+ //we have got to the bottom of the folder list
+ //so we have to start at the top
+ if (confirm) {
+ for ( it = firstChild() ; it.current() ; ++it ) {
+ //check if folder is one to stop on
+ KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
+ if (checkUnreadFolder(fti,confirm)) return;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+bool KMFolderTree::checkUnreadFolder (KMFolderTreeItem* fti, bool confirm)
+{
+ if ( fti && fti->folder() && !fti->folder()->ignoreNewMail() &&
+ ( fti->folder()->countUnread() > 0 ) ) {
+
+ // Don't change into the trash or outbox folders.
+ if (fti->type() == KFolderTreeItem::Trash ||
+ fti->type() == KFolderTreeItem::Outbox )
+ return false;
+
+ if (confirm) {
+ // Skip drafts, sent mail and templates as well, when reading mail with
+ // the space bar but not when changing into the next folder with unread
+ // mail via ctrl+ or ctrl- so we do this only if (confirm == true),
+ // which means we are doing readOn.
+ if ( fti->type() == KFolderTreeItem::Drafts ||
+ fti->type() == KFolderTreeItem::Templates ||
+ fti->type() == KFolderTreeItem::SentMail )
+ return false;
+
+ // warn user that going to next folder - but keep track of
+ // whether he wishes to be notified again in "AskNextFolder"
+ // parameter (kept in the config file for kmail)
+ if ( KMessageBox::questionYesNo( this,
+ i18n( "<qt>Go to the next unread message in folder <b>%1</b>?</qt>" )
+ .arg( fti->folder()->label() ),
+ i18n( "Go to Next Unread Message" ),
+ i18n("Go To"), i18n("Do Not Go To"), // defaults
+ "AskNextFolder",
+ false)
+ == KMessageBox::No ) return true;
+ }
+ prepareItem( fti );
+ blockSignals( true );
+ doFolderSelected( fti );
+ blockSignals( false );
+ emit folderSelectedUnread( fti->folder() );
+ return true;
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::prevUnreadFolder()
+{
+ QListViewItemIterator it( currentItem() ? currentItem() : lastItem() );
+ if ( currentItem() )
+ --it; // don't find current item
+ for ( ; it.current() ; --it ) {
+ KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
+ if (checkUnreadFolder(fti,false)) return;
+ }
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::incCurrentFolder()
+{
+ QListViewItemIterator it( currentItem() );
+ ++it;
+ KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
+ if (fti) {
+ prepareItem( fti );
+ setFocus();
+ setCurrentItem( fti );
+ }
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::decCurrentFolder()
+{
+ QListViewItemIterator it( currentItem() );
+ --it;
+ KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
+ if (fti) {
+ prepareItem( fti );
+ setFocus();
+ setCurrentItem( fti );
+ }
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::selectCurrentFolder()
+{
+ KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>( currentItem() );
+ if (fti) {
+ prepareItem( fti );
+ doFolderSelected( fti );
+ }
+}
+
+//-----------------------------------------------------------------------------
+KMFolder *KMFolderTree::currentFolder() const
+{
+ KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>( currentItem() );
+ if (fti )
+ return fti->folder();
+ else
+ return 0;
+}
+
+QValueList<QGuardedPtr<KMFolder> > KMFolderTree::selectedFolders()
+{
+ QValueList<QGuardedPtr<KMFolder> > rv;
+ for ( QListViewItemIterator it( this ); it.current(); ++it ) {
+ if ( it.current()->isSelected() ) {
+ KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>( it.current() );
+ rv.append( fti->folder() );
+ }
+ }
+ return rv;
+}
+
+//-----------------------------------------------------------------------------
+// When not dragging and dropping a change in the selected item
+// indicates the user has changed the active folder emit a signal
+// so that the header list and reader window can be udpated.
+void KMFolderTree::doFolderSelected( QListViewItem* qlvi, bool keepSelection )
+{
+ if (!qlvi) return;
+ if ( mLastItem && mLastItem == qlvi && (keepSelection || selectedFolders().count() == 1) )
+ return;
+
+ KMFolderTreeItem* fti = static_cast< KMFolderTreeItem* >(qlvi);
+ KMFolder* folder = 0;
+ if (fti) folder = fti->folder();
+
+
+ if (mLastItem && mLastItem != fti && mLastItem->folder()
+ && (mLastItem->folder()->folderType() == KMFolderTypeImap))
+ {
+ KMFolderImap *imapFolder = static_cast<KMFolderImap*>(mLastItem->folder()->storage());
+ imapFolder->setSelected(false);
+ }
+ mLastItem = fti;
+
+ if ( !keepSelection )
+ clearSelection();
+ setCurrentItem( qlvi );
+ if ( !keepSelection )
+ setSelected( qlvi, true );
+ ensureItemVisible( qlvi );
+ if (!folder) {
+ emit folderSelected(0); // Root has been selected
+ }
+ else {
+ emit folderSelected(folder);
+ slotUpdateCounts(folder);
+ }
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::resizeEvent(QResizeEvent* e)
+{
+ KConfig* conf = KMKernel::config();
+
+ KConfigGroupSaver saver(conf, "Geometry");
+ conf->writeEntry(name(), size().width());
+
+ KListView::resizeEvent(e);
+}
+
+//-----------------------------------------------------------------------------
+// show context menu
+void KMFolderTree::slotContextMenuRequested( QListViewItem *lvi,
+ const QPoint &p )
+{
+ if (!lvi)
+ return;
+ setCurrentItem( lvi );
+
+ if (!mMainWidget) return; // safe bet
+
+ KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(lvi);
+ if ( !isSelected( fti ) )
+ doFolderSelected( fti );
+ else if ( fti != mLastItem )
+ doFolderSelected( fti, true );
+
+ if (!fti )
+ return;
+
+ KPopupMenu *folderMenu = new KPopupMenu;
+ bool multiFolder = selectedFolders().count() > 1;
+ if (fti->folder()) folderMenu->insertTitle(fti->folder()->label());
+
+ // outbox specific, but there it's the most used action
+ if ( (fti->folder() == kmkernel->outboxFolder()) && fti->folder()->count() )
+ mMainWidget->action("send_queued")->plug( folderMenu );
+ // Mark all as read is supposedly used often, therefor it is first
+ if ( fti->folder() && !fti->folder()->noContent() )
+ mMainWidget->action("mark_all_as_read")->plug( folderMenu );
+
+ /* Treat the special case of the root and account folders */
+ if ((!fti->folder() || (fti->folder()->noContent()
+ && !fti->parent())))
+ {
+ QString createChild = i18n("&New Subfolder...");
+ if (!fti->folder()) createChild = i18n("&New Folder...");
+
+ if (fti->folder() || (fti->text(0) != i18n("Searches")) && !multiFolder)
+ folderMenu->insertItem(SmallIconSet("folder_new"),
+ createChild, this,
+ SLOT(addChildFolder()));
+
+ if (!fti->folder()) {
+ mMainWidget->action("compact_all_folders")->plug(folderMenu);
+ mMainWidget->action("expire_all_folders")->plug(folderMenu);
+ } else if (fti->folder()->folderType() == KMFolderTypeImap) {
+ folderMenu->insertItem(SmallIconSet("mail_get"), i18n("Check &Mail"),
+ this,
+ SLOT(slotCheckMail()));
+ }
+ } else { // regular folders
+
+ folderMenu->insertSeparator();
+ if ( !fti->folder()->noChildren() && !multiFolder ) {
+ folderMenu->insertItem(SmallIconSet("folder_new"),
+ i18n("&New Subfolder..."), this,
+ SLOT(addChildFolder()));
+ }
+
+ // copy folder
+ QPopupMenu *copyMenu = new QPopupMenu( folderMenu );
+ folderToPopupMenu( CopyFolder, this, &mMenuToFolder, copyMenu );
+ folderMenu->insertItem( i18n("&Copy Folder To"), copyMenu );
+
+ if ( fti->folder()->isMoveable() )
+ {
+ QPopupMenu *moveMenu = new QPopupMenu( folderMenu );
+ folderToPopupMenu( MoveFolder, this, &mMenuToFolder, moveMenu );
+ folderMenu->insertItem( i18n("&Move Folder To"), moveMenu );
+ }
+
+ // Want to be able to display properties for ALL folders,
+ // so we can edit expiry properties.
+ // -- smp.
+ if (!fti->folder()->noContent())
+ {
+ if ( !multiFolder )
+ mMainWidget->action("search_messages")->plug(folderMenu);
+
+ mMainWidget->action("compact")->plug(folderMenu);
+
+ if ( GlobalSettings::self()->enableFavoriteFolderView() ) {
+ folderMenu->insertItem( SmallIconSet("bookmark_add"), i18n("Add to Favorite Folders"),
+ this, SLOT(slotAddToFavorites()) );
+ }
+
+ folderMenu->insertSeparator();
+ mMainWidget->action("empty")->plug(folderMenu);
+ if ( !fti->folder()->isSystemFolder() ) {
+ mMainWidget->action("delete_folder")->plug(folderMenu);
+ }
+ folderMenu->insertSeparator();
+ }
+ }
+
+ /* plug in IMAP and DIMAP specific things */
+ if (fti->folder() &&
+ (fti->folder()->folderType() == KMFolderTypeImap ||
+ fti->folder()->folderType() == KMFolderTypeCachedImap ))
+ {
+ folderMenu->insertItem(SmallIconSet("bookmark_folder"),
+ i18n("Subscription..."), mMainWidget,
+ SLOT(slotSubscriptionDialog()));
+ folderMenu->insertItem(SmallIcon("bookmark_folder"),
+ i18n("Local Subscription..."), mMainWidget,
+ SLOT(slotLocalSubscriptionDialog()));
+
+ if (!fti->folder()->noContent())
+ {
+ mMainWidget->action("refresh_folder")->plug(folderMenu);
+ if ( fti->folder()->folderType() == KMFolderTypeImap && !multiFolder ) {
+ folderMenu->insertItem(SmallIconSet("reload"), i18n("Refresh Folder List"), this,
+ SLOT(slotResetFolderList()));
+ }
+ }
+ if ( fti->folder()->folderType() == KMFolderTypeCachedImap && !multiFolder ) {
+ KMFolderCachedImap * folder = static_cast<KMFolderCachedImap*>( fti->folder()->storage() );
+ folderMenu->insertItem( SmallIconSet("wizard"),
+ i18n("&Troubleshoot IMAP Cache..."),
+ folder, SLOT(slotTroubleshoot()) );
+ }
+ folderMenu->insertSeparator();
+ }
+
+ if ( fti->folder() && fti->folder()->isMailingListEnabled() && !multiFolder ) {
+ mMainWidget->action("post_message")->plug(folderMenu);
+ }
+
+ if (fti->folder() && fti->parent() && !multiFolder)
+ {
+ folderMenu->insertItem(SmallIconSet("configure_shortcuts"),
+ i18n("&Assign Shortcut..."),
+ fti,
+ SLOT(assignShortcut()));
+
+ if ( !fti->folder()->noContent() ) {
+ folderMenu->insertItem( i18n("Expire..."), fti,
+ SLOT( slotShowExpiryProperties() ) );
+ }
+ mMainWidget->action("modify")->plug(folderMenu);
+ }
+
+
+ kmkernel->setContextMenuShown( true );
+ folderMenu->exec (p, 0);
+ kmkernel->setContextMenuShown( false );
+ triggerUpdate();
+ delete folderMenu;
+ folderMenu = 0;
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::contentsMousePressEvent(QMouseEvent * e)
+{
+ // KFolderTree messes around with the selection mode
+ KListView::contentsMousePressEvent( e );
+}
+
+// If middle button and folder holds mailing-list, create a message to that list
+void KMFolderTree::contentsMouseReleaseEvent(QMouseEvent* me)
+{
+ QListViewItem *lvi = currentItem(); // Needed for when branches are clicked on
+ ButtonState btn = me->button();
+ doFolderSelected(lvi, true);
+
+ // get underlying folder
+ KMFolderTreeItem* fti = dynamic_cast<KMFolderTreeItem*>(lvi);
+
+ if (!fti || !fti->folder()) {
+ KFolderTree::contentsMouseReleaseEvent(me);
+ return;
+ }
+
+ // react on middle-button only
+ if (btn != Qt::MidButton) {
+ KFolderTree::contentsMouseReleaseEvent(me);
+ return;
+ }
+
+ if ( fti->folder()->isMailingListEnabled() ) {
+ KMCommand *command = new KMMailingListPostCommand( this, fti->folder() );
+ command->start();
+ }
+
+ KFolderTree::contentsMouseReleaseEvent(me);
+}
+
+// little static helper
+static bool folderHasCreateRights( const KMFolder *folder )
+{
+ bool createRights = true; // we don't have acls for local folders yet
+ if ( folder && folder->folderType() == KMFolderTypeImap ) {
+ const KMFolderImap *imapFolder = static_cast<const KMFolderImap*>( folder->storage() );
+ createRights = imapFolder->userRights() == 0 || // hack, we should get the acls
+ ( imapFolder->userRights() > 0 && ( imapFolder->userRights() & KMail::ACLJobs::Create ) );
+ } else if ( folder && folder->folderType() == KMFolderTypeCachedImap ) {
+ const KMFolderCachedImap *dimapFolder = static_cast<const KMFolderCachedImap*>( folder->storage() );
+ createRights = dimapFolder->userRights() == 0 ||
+ ( dimapFolder->userRights() > 0 && ( dimapFolder->userRights() & KMail::ACLJobs::Create ) );
+ }
+ return createRights;
+}
+
+//-----------------------------------------------------------------------------
+// Create a subfolder.
+// Requires creating the appropriate subdirectory and show a dialog
+void KMFolderTree::addChildFolder( KMFolder *folder, QWidget * parent )
+{
+ KMFolder *aFolder = folder;
+ if ( !aFolder ) {
+ KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(currentItem());
+ if (!fti)
+ return;
+ aFolder = fti->folder();
+ }
+ if (aFolder) {
+ if (!aFolder->createChildFolder())
+ return;
+ if ( !folderHasCreateRights( aFolder ) ) {
+ // FIXME: change this message to "Cannot create folder under ..." or similar
+ const QString message = i18n( "<qt>Cannot create folder <b>%1</b> because of insufficient "
+ "permissions on the server. If you think you should be able to create "
+ "subfolders here, ask your administrator to grant you rights to do so."
+ "</qt> " ).arg(aFolder->label());
+ KMessageBox::error( this, message );
+ return;
+ }
+ }
+
+ if ( parent )
+ ( new KMail::NewFolderDialog( parent, aFolder ) )->exec();
+ else
+ ( new KMail::NewFolderDialog( this, aFolder ) )->show();
+ return;
+/*
+ KMFolderDir *dir = &(kmkernel->folderMgr()->dir());
+ if (aFolder)
+ dir = aFolder->child();
+
+ KMFolderDialog *d =
+ new KMFolderDialog(0, dir, this, i18n("Create Subfolder") );
+
+ if (d->exec()) { // fti may be deleted here
+ QListViewItem *qlvi = indexOfFolder( aFolder );
+ if (qlvi) {
+ qlvi->setOpen(true);
+ blockSignals( true );
+ setCurrentItem( qlvi );
+ blockSignals( false );
+ }
+ }
+ delete d;
+ // update if added to root Folder
+ if (!aFolder || aFolder->noContent()) {
+ doFolderListChanged();
+ }
+ */
+}
+
+//-----------------------------------------------------------------------------
+// Returns whether a folder directory should be open as specified in the
+// config file.
+bool KMFolderTree::readIsListViewItemOpen(KMFolderTreeItem *fti)
+{
+ KConfig* config = KMKernel::config();
+ KMFolder *folder = fti->folder();
+ QString name;
+ if (folder)
+ {
+ name = "Folder-" + folder->idString();
+ } else if (fti->type() == KFolderTreeItem::Root)
+ {
+ if (fti->protocol() == KFolderTreeItem::NONE) // local root
+ name = "Folder_local_root";
+ else if (fti->protocol() == KFolderTreeItem::Search)
+ name = "Folder_search";
+ else
+ return false;
+ } else {
+ return false;
+ }
+ KConfigGroupSaver saver(config, name);
+
+ return config->readBoolEntry("isOpen", false);
+}
+
+//-----------------------------------------------------------------------------
+// Saves open/closed state of a folder directory into the config file
+void KMFolderTree::writeIsListViewItemOpen(KMFolderTreeItem *fti)
+{
+ KConfig* config = KMKernel::config();
+ KMFolder *folder = fti->folder();
+ QString name;
+ if (folder && !folder->idString().isEmpty())
+ {
+ name = "Folder-" + folder->idString();
+ } else if (fti->type() == KFolderTreeItem::Root)
+ {
+ if (fti->protocol() == KFolderTreeItem::NONE) // local root
+ name = "Folder_local_root";
+ else if (fti->protocol() == KFolderTreeItem::Search)
+ name = "Folder_search";
+ else
+ return;
+ } else {
+ return;
+ }
+ KConfigGroupSaver saver(config, name);
+ config->writeEntry("isOpen", fti->isOpen() );
+}
+
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::cleanupConfigFile()
+{
+ if ( childCount() == 0 )
+ return; // just in case reload wasn't called before
+ KConfig* config = KMKernel::config();
+ QStringList existingFolders;
+ QListViewItemIterator fldIt(this);
+ QMap<QString,bool> folderMap;
+ KMFolderTreeItem *fti;
+ for (QListViewItemIterator fldIt(this); fldIt.current(); fldIt++)
+ {
+ fti = static_cast<KMFolderTreeItem*>(fldIt.current());
+ if (fti && fti->folder())
+ folderMap.insert(fti->folder()->idString(), true);
+ }
+ QStringList groupList = config->groupList();
+ QString name;
+ for (QStringList::Iterator grpIt = groupList.begin();
+ grpIt != groupList.end(); grpIt++)
+ {
+ if ((*grpIt).left(7) != "Folder-") continue;
+ name = (*grpIt).mid(7);
+ if (folderMap.find(name) == folderMap.end())
+ {
+ KMFolder* folder = kmkernel->findFolderById( name );
+ if ( folder ) {
+ if ( kmkernel->iCalIface().hideResourceFolder( folder )
+ || kmkernel->iCalIface().hideResourceAccountRoot( folder ) )
+ continue; // hidden IMAP resource folder, don't delete info
+ if ( folder->noContent() )
+ continue; // we hide nocontent folders if they have no child folders
+ if ( folder == kmkernel->inboxFolder() )
+ continue; // local inbox can be hidden as well
+ }
+
+ //KMessageBox::error( 0, "cleanupConfigFile: Deleting group " + *grpIt );
+ config->deleteGroup(*grpIt, true);
+ kdDebug(5006) << "Deleting information about folder " << name << endl;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::openFolder()
+{
+ autoopen_timer.stop();
+ if ( dropItem && !dropItem->isOpen() ) {
+ dropItem->setOpen( true );
+ dropItem->repaint();
+ }
+}
+
+static const int autoopenTime = 750;
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::contentsDragEnterEvent( QDragEnterEvent *e )
+{
+ oldCurrent = 0;
+ oldSelected = 0;
+
+ oldCurrent = currentItem();
+ for ( QListViewItemIterator it( this ) ; it.current() ; ++it )
+ if ( it.current()->isSelected() )
+ oldSelected = it.current();
+
+ setFocus();
+
+ QListViewItem *i = itemAt( contentsToViewport(e->pos()) );
+ if ( i ) {
+ dropItem = i;
+ autoopen_timer.start( autoopenTime );
+ }
+ else
+ dropItem = 0;
+
+ e->accept( acceptDrag(e) );
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::contentsDragMoveEvent( QDragMoveEvent *e )
+{
+ QPoint vp = contentsToViewport(e->pos());
+ QListViewItem *i = itemAt( vp );
+ if ( i ) {
+ bool dragAccepted = acceptDrag( e );
+ if ( dragAccepted ) {
+ setCurrentItem( i );
+ }
+
+ if ( i != dropItem ) {
+ autoopen_timer.stop();
+ dropItem = i;
+ autoopen_timer.start( autoopenTime );
+ }
+
+ if ( dragAccepted ) {
+ e->accept( itemRect(i) );
+
+ switch ( e->action() ) {
+ case QDropEvent::Copy:
+ break;
+ case QDropEvent::Move:
+ e->acceptAction();
+ break;
+ case QDropEvent::Link:
+ e->acceptAction();
+ break;
+ default:
+ ;
+ }
+ } else {
+ e->accept( false );
+ }
+ } else {
+ e->accept( false );
+ autoopen_timer.stop();
+ dropItem = 0;
+ }
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::contentsDragLeaveEvent( QDragLeaveEvent * )
+{
+ if (!oldCurrent) return;
+
+ autoopen_timer.stop();
+ dropItem = 0;
+
+ setCurrentItem( oldCurrent );
+ if ( oldSelected )
+ setSelected( oldSelected, true );
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::contentsDropEvent( QDropEvent *e )
+{
+ autoopen_timer.stop();
+
+ QListViewItem *item = itemAt( contentsToViewport(e->pos()) );
+ KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
+ // Check that each pointer is not null
+ for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it = mCopySourceFolders.constBegin();
+ it != mCopySourceFolders.constEnd(); ++it ) {
+ if ( ! (*it) ) {
+ fti = 0;
+ break;
+ }
+ }
+ if (fti && mCopySourceFolders.count() == 1)
+ {
+ KMFolder *source = mCopySourceFolders.first();
+ // if we are dragging to ourselves or to our parent, set fti to 0 so nothing is done
+ if (source == fti->folder() || source->parent()->owner() == fti->folder()) fti = 0;
+ }
+ if (fti && acceptDrag(e) && ( fti != oldSelected || e->source() != mMainWidget->headers()->viewport() ) )
+ {
+ if ( e->provides("application/x-qlistviewitem") ) {
+ int action = dndMode( true /* always ask */ );
+ if ( (action == DRAG_COPY || action == DRAG_MOVE) && !mCopySourceFolders.isEmpty() ) {
+ for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it = mCopySourceFolders.constBegin();
+ it != mCopySourceFolders.constEnd(); ++it ) {
+ if ( ! (*it)->isMoveable() )
+ action = DRAG_COPY;
+ }
+ moveOrCopyFolder( mCopySourceFolders, fti->folder(), (action == DRAG_MOVE) );
+ }
+ } else {
+ if ( e->source() == mMainWidget->headers()->viewport() ) {
+ int action;
+ if ( mMainWidget->headers()->folder() && mMainWidget->headers()->folder()->isReadOnly() )
+ action = DRAG_COPY;
+ else
+ action = dndMode();
+ // KMHeaders does copy/move itself
+ if ( action == DRAG_MOVE && fti->folder() )
+ emit folderDrop( fti->folder() );
+ else if ( action == DRAG_COPY && fti->folder() )
+ emit folderDropCopy( fti->folder() );
+ } else {
+ handleMailListDrop( e, fti->folder() );
+ }
+ }
+ e->accept( true );
+ } else
+ e->accept( false );
+
+ dropItem = 0;
+
+ setCurrentItem( oldCurrent );
+ if ( oldCurrent) mLastItem = static_cast<KMFolderTreeItem*>(oldCurrent);
+ if ( oldSelected )
+ {
+ clearSelection();
+ setSelected( oldSelected, true );
+ }
+
+ mCopySourceFolders.clear();
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::slotFolderExpanded( QListViewItem * item )
+{
+ KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
+ if ( !fti || !fti->folder() || !fti->folder()->storage() ) return;
+
+ fti->setFolderSize( fti->folder()->storage()->folderSize() );
+
+ if( fti->folder()->folderType() == KMFolderTypeImap )
+ {
+ KMFolderImap *folder = static_cast<KMFolderImap*>( fti->folder()->storage() );
+ // if we should list all folders we limit this to the root folder
+ if ( !folder->account() || ( !folder->account()->listOnlyOpenFolders() &&
+ fti->parent() ) )
+ return;
+ if ( folder->getSubfolderState() == KMFolderImap::imapNoInformation )
+ {
+ // check if all parents are expanded
+ QListViewItem *parent = item->parent();
+ while ( parent )
+ {
+ if ( !parent->isOpen() )
+ return;
+ parent = parent->parent();
+ }
+ // the tree will be reloaded after that
+ bool success = folder->listDirectory();
+ if (!success) fti->setOpen( false );
+ if ( fti->childCount() == 0 && fti->parent() )
+ fti->setExpandable( false );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::slotFolderCollapsed( QListViewItem * item )
+{
+ slotResetFolderList( item, false );
+ KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
+ if ( !fti || !fti->folder() || !fti->folder()->storage() ) return;
+
+ fti->setFolderSize( fti->folder()->storage()->folderSize() );
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::slotRenameFolder(QListViewItem *item, int col,
+ const QString &text)
+{
+
+ KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
+
+ if ((!fti) || (fti && fti->folder() && col != 0 && !currentFolder()->child()))
+ return;
+
+ QString fldName, oldFldName;
+
+ oldFldName = fti->name(0);
+
+ if (!text.isEmpty())
+ fldName = text;
+ else
+ fldName = oldFldName;
+
+ fldName.replace("/", "");
+ fldName.replace(QRegExp("^\\."), "");
+
+ if (fldName.isEmpty())
+ fldName = i18n("unnamed");
+
+ fti->setText(0, fldName);
+ fti->folder()->rename(fldName, &(kmkernel->folderMgr()->dir()));
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::slotUpdateCountsDelayed(KMFolder * folder)
+{
+// kdDebug(5006) << "KMFolderTree::slotUpdateCountsDelayed()" << endl;
+ if ( !mFolderToUpdateCount.contains( folder->idString() ) )
+ {
+// kdDebug( 5006 )<< "adding " << folder->idString() << " to updateCountList " << endl;
+ mFolderToUpdateCount.insert( folder->idString(),folder );
+ }
+ if ( !mUpdateCountTimer->isActive() )
+ mUpdateCountTimer->start( 500 );
+}
+
+
+void KMFolderTree::slotUpdateCountTimeout()
+{
+// kdDebug(5006) << "KMFolderTree::slotUpdateCountTimeout()" << endl;
+
+ QMap<QString,KMFolder*>::iterator it;
+ for ( it= mFolderToUpdateCount.begin();
+ it!=mFolderToUpdateCount.end();
+ ++it )
+ {
+ slotUpdateCounts( it.data() );
+ }
+ mFolderToUpdateCount.clear();
+ mUpdateCountTimer->stop();
+
+}
+
+void KMFolderTree::updatePopup() const
+{
+ mPopup->setItemChecked( mUnreadPop, isUnreadActive() );
+ mPopup->setItemChecked( mTotalPop, isTotalActive() );
+ mPopup->setItemChecked( mSizePop, isSizeActive() );
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::toggleColumn(int column, bool openFolders)
+{
+ if (column == unread)
+ {
+ // switch unread
+ if ( isUnreadActive() )
+ {
+ removeUnreadColumn();
+ reload();
+ } else {
+ addUnreadColumn( i18n("Unread"), 70 );
+ reload();
+ }
+ // toggle KPopupMenu
+ mPopup->setItemChecked( mUnreadPop, isUnreadActive() );
+
+ } else if (column == total) {
+ // switch total
+ if ( isTotalActive() )
+ {
+ removeTotalColumn();
+ reload();
+ } else {
+ addTotalColumn( i18n("Total"), 70 );
+ reload(openFolders);
+ }
+ mPopup->setItemChecked( mTotalPop, isTotalActive() );
+ } else if (column == foldersize) {
+ // switch total
+ if ( isSizeActive() )
+ {
+ removeSizeColumn();
+ reload();
+ } else {
+ addSizeColumn( i18n("Size"), 70 );
+ reload( openFolders );
+ }
+ // toggle KPopupMenu
+ mPopup->setItemChecked( mSizePop, isSizeActive() );
+
+ } else kdDebug(5006) << "unknown column:" << column << endl;
+
+ // toggles the switches of the mainwin
+ emit columnsChanged();
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::slotToggleUnreadColumn()
+{
+ toggleColumn(unread);
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::slotToggleTotalColumn()
+{
+ // activate the total-column and force the folders to be opened
+ toggleColumn(total, true);
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::slotToggleSizeColumn()
+{
+ // activate the size-column and force the folders to be opened
+ toggleColumn(foldersize, true);
+}
+
+
+//-----------------------------------------------------------------------------
+bool KMFolderTree::eventFilter( QObject *o, QEvent *e )
+{
+ if ( e->type() == QEvent::MouseButtonPress &&
+ static_cast<QMouseEvent*>(e)->button() == RightButton &&
+ o->isA("QHeader") )
+ {
+ mPopup->popup( static_cast<QMouseEvent*>(e)->globalPos() );
+ return true;
+ }
+ return KFolderTree::eventFilter(o, e);
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::slotCheckMail()
+{
+ if (!currentItem())
+ return;
+ KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(currentItem());
+ KMFolder* folder = fti->folder();
+ if (folder && folder->storage() ) {
+ if ( KMAccount* acct = folder->storage()->account() ) {
+ kmkernel->acctMgr()->singleCheckMail(acct, true);
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::slotNewMessageToMailingList()
+{
+ KMFolderTreeItem* fti = dynamic_cast<KMFolderTreeItem*>( currentItem() );
+ if ( !fti || !fti->folder() )
+ return;
+ KMCommand *command = new KMMailingListPostCommand( this, fti->folder() );
+ command->start();
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::createFolderList( QStringList *str,
+ QValueList<QGuardedPtr<KMFolder> > *folders,
+ bool localFolders,
+ bool imapFolders,
+ bool dimapFolders,
+ bool searchFolders,
+ bool includeNoContent,
+ bool includeNoChildren )
+{
+ for ( QListViewItemIterator it( this ) ; it.current() ; ++it )
+ {
+ KMFolderTreeItem * fti = static_cast<KMFolderTreeItem*>(it.current());
+ if (!fti || !fti->folder()) continue;
+ // type checks
+ KMFolder* folder = fti->folder();
+ if (!imapFolders && folder->folderType() == KMFolderTypeImap) continue;
+ if (!dimapFolders && folder->folderType() == KMFolderTypeCachedImap) continue;
+ if (!localFolders && (folder->folderType() == KMFolderTypeMbox ||
+ folder->folderType() == KMFolderTypeMaildir)) continue;
+ if (!searchFolders && folder->folderType() == KMFolderTypeSearch) continue;
+ if (!includeNoContent && folder->noContent()) continue;
+ if (!includeNoChildren && folder->noChildren()) continue;
+ QString prefix;
+ prefix.fill( ' ', 2 * fti->depth() );
+ str->append(prefix + fti->text(0));
+ folders->append(fti->folder());
+ }
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::slotResetFolderList( QListViewItem* item, bool startList )
+{
+ if ( !item )
+ item = currentItem();
+
+ KMFolderTreeItem* fti = dynamic_cast<KMFolderTreeItem*>( item );
+ if ( fti && fti->folder() &&
+ fti->folder()->folderType() == KMFolderTypeImap )
+ {
+ KMFolderImap *folder = static_cast<KMFolderImap*>( fti->folder()->storage() );
+ folder->setSubfolderState( KMFolderImap::imapNoInformation );
+ if ( startList )
+ folder->listDirectory();
+ }
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::showFolder( KMFolder* folder )
+{
+ if ( !folder ) return;
+ QListViewItem* item = indexOfFolder( folder );
+ if ( item )
+ {
+ doFolderSelected( item );
+ ensureItemVisible( item );
+ }
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::folderToPopupMenu( MenuAction action, QObject *receiver,
+ KMMenuToFolder *aMenuToFolder, QPopupMenu *menu, QListViewItem *item )
+{
+ while ( menu->count() )
+ {
+ QPopupMenu *popup = menu->findItem( menu->idAt( 0 ) )->popup();
+ if ( popup )
+ delete popup;
+ else
+ menu->removeItemAt( 0 );
+ }
+ // connect the signals
+ if ( action == MoveMessage || action == MoveFolder )
+ {
+ disconnect( menu, SIGNAL(activated(int)), receiver,
+ SLOT(moveSelectedToFolder(int)) );
+ connect( menu, SIGNAL(activated(int)), receiver,
+ SLOT(moveSelectedToFolder(int)) );
+ } else {
+ disconnect( menu, SIGNAL(activated(int)), receiver,
+ SLOT(copySelectedToFolder(int)) );
+ connect( menu, SIGNAL(activated(int)), receiver,
+ SLOT(copySelectedToFolder(int)) );
+ }
+ if ( !item ) {
+ item = firstChild();
+
+ // avoid a popup menu with the single entry 'Local Folders' if there
+ // are no IMAP accounts
+ if ( childCount() == 2 && action != MoveFolder ) { // only 'Local Folders' and 'Searches'
+ KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>( item );
+ if ( fti->protocol() == KFolderTreeItem::Search ) {
+ // skip 'Searches'
+ item = item->nextSibling();
+ fti = static_cast<KMFolderTreeItem*>( item );
+ }
+ folderToPopupMenu( action, receiver, aMenuToFolder, menu, fti->firstChild() );
+ return;
+ }
+ }
+
+ while ( item )
+ {
+ KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>( item );
+ if ( fti->protocol() == KFolderTreeItem::Search )
+ {
+ // skip search folders
+ item = item->nextSibling();
+ continue;
+ }
+ QString label = fti->text( 0 );
+ label.replace( "&","&&" );
+ if ( fti->firstChild() )
+ {
+ // new level
+ QPopupMenu* popup = new QPopupMenu( menu, "subMenu" );
+ folderToPopupMenu( action, receiver, aMenuToFolder, popup, fti->firstChild() );
+ bool subMenu = false;
+ if ( ( action == MoveMessage || action == CopyMessage ) &&
+ fti->folder() && !fti->folder()->noContent() )
+ subMenu = true;
+ if ( ( action == MoveFolder || action == CopyFolder )
+ && ( !fti->folder() || ( fti->folder() && !fti->folder()->noChildren() ) ) )
+ subMenu = true;
+
+ QString sourceFolderName;
+ KMFolderTreeItem* srcItem = dynamic_cast<KMFolderTreeItem*>( currentItem() );
+ if ( srcItem )
+ sourceFolderName = srcItem->text( 0 );
+
+ if ( (action == MoveFolder || action == CopyFolder)
+ && fti->folder() && fti->folder()->child()
+ && fti->folder()->child()->hasNamedFolder( sourceFolderName ) ) {
+ subMenu = false;
+ }
+
+ if ( subMenu )
+ {
+ int menuId;
+ if ( action == MoveMessage || action == MoveFolder )
+ menuId = popup->insertItem( i18n("Move to This Folder"), -1, 0 );
+ else
+ menuId = popup->insertItem( i18n("Copy to This Folder"), -1, 0 );
+ popup->insertSeparator( 1 );
+ aMenuToFolder->insert( menuId, fti->folder() );
+ }
+ menu->insertItem( label, popup );
+ } else
+ {
+ // insert an item
+ int menuId = menu->insertItem( label );
+ if ( fti->folder() )
+ aMenuToFolder->insert( menuId, fti->folder() );
+ bool enabled = (fti->folder() ? true : false);
+ if ( fti->folder() &&
+ ( fti->folder()->isReadOnly() || fti->folder()->noContent() ) )
+ enabled = false;
+ menu->setItemEnabled( menuId, enabled );
+ }
+
+ item = item->nextSibling();
+ }
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::moveSelectedToFolder( int menuId )
+{
+ moveOrCopyFolder( selectedFolders(), mMenuToFolder[ menuId ], true /*move*/ );
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::copySelectedToFolder( int menuId )
+{
+ moveOrCopyFolder( selectedFolders(), mMenuToFolder[ menuId ], false /*copy, don't move*/ );
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderTree::moveOrCopyFolder( QValueList<QGuardedPtr<KMFolder> > sources, KMFolder* destination, bool move )
+{
+ kdDebug(5006) << k_funcinfo << "source: " << sources << " destination: " << destination << " move: " << move << endl;
+
+ // Disable drag during copy operation since it prevents from many crashes
+ setDragEnabled( false );
+
+ KMFolderDir* parent = &(kmkernel->folderMgr()->dir());
+ if ( destination )
+ parent = destination->createChildFolder();
+
+ QStringList sourceFolderNames;
+
+ // check if move/copy is possible at all
+ for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it = sources.constBegin(); it != sources.constEnd(); ++it ) {
+ KMFolder* source = *it;
+
+ // check if folder with same name already exits
+ QString sourceFolderName;
+ if ( source )
+ sourceFolderName = source->label();
+
+ if ( parent->hasNamedFolder( sourceFolderName ) || sourceFolderNames.contains( sourceFolderName ) ) {
+ KMessageBox::error( this, i18n("<qt>Cannot move or copy folder <b>%1</b> here because a folder with the same name already exists.</qt>")
+ .arg( sourceFolderName ) );
+ return;
+ }
+ sourceFolderNames.append( sourceFolderName );
+
+ // don't move/copy a folder that's still not completely moved/copied
+ KMFolder *f = source;
+ while ( f ) {
+ if ( f->moveInProgress() ) {
+ KMessageBox::error( this, i18n("<qt>Cannot move or copy folder <b>%1</b> because it is not completely copied itself.</qt>")
+ .arg( sourceFolderName ) );
+ return;
+ }
+ if ( f->parent() )
+ f = f->parent()->owner();
+ }
+
+ QString message =
+ i18n( "<qt>Cannot move or copy folder <b>%1</b> into a subfolder below itself.</qt>" ).
+ arg( sourceFolderName );
+ KMFolderDir* folderDir = parent;
+ // check that the folder can be moved
+ if ( source && source->child() )
+ {
+ while ( folderDir && ( folderDir != &kmkernel->folderMgr()->dir() ) &&
+ ( folderDir != source->parent() ) )
+ {
+ if ( folderDir->findRef( source ) != -1 )
+ {
+ KMessageBox::error( this, message );
+ return;
+ }
+ folderDir = folderDir->parent();
+ }
+ }
+
+ if( source && source->child() && parent &&
+ ( parent->path().find( source->child()->path() + "/" ) == 0 ) ) {
+ KMessageBox::error( this, message );
+ return;
+ }
+
+ if( source && source->child()
+ && ( parent == source->child() ) ) {
+ KMessageBox::error( this, message );
+ return;
+ }
+ }
+
+ // check if the source folders are independent of each other
+ for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it = sources.constBegin(); move && it != sources.constEnd(); ++it ) {
+ KMFolderDir *parentDir = (*it)->child();
+ if ( !parentDir )
+ continue;
+ for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it2 = sources.constBegin(); it2 != sources.constEnd(); ++it2 ) {
+ if ( *it == *it2 )
+ continue;
+ KMFolderDir *childDir = (*it2)->parent();
+ do {
+ if ( parentDir == childDir || parentDir->findRef( childDir->owner() ) != -1 ) {
+ KMessageBox::error( this, i18n("Moving the selected folders is not possible") );
+ return;
+ }
+ childDir = childDir->parent();
+ }
+ while ( childDir && childDir != &kmkernel->folderMgr()->dir() );
+ }
+ }
+
+ // de-select moved source folders (can cause crash due to unGetMsg() in KMHeaders)
+ if ( move ) {
+ doFolderSelected( indexOfFolder( destination ), false );
+ oldCurrent = currentItem();
+ }
+
+ // do the actual move/copy
+ for ( QValueList<QGuardedPtr<KMFolder> >::ConstIterator it = sources.constBegin(); it != sources.constEnd(); ++it ) {
+ KMFolder* source = *it;
+ if ( move ) {
+ kdDebug(5006) << "move folder " << (source ? source->label(): "Unknown") << " to "
+ << ( destination ? destination->label() : "Local Folders" ) << endl;
+ kmkernel->folderMgr()->moveFolder( source, parent );
+ } else {
+ kmkernel->folderMgr()->copyFolder( source, parent );
+ }
+ }
+}
+
+QDragObject * KMFolderTree::dragObject()
+{
+ KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>
+ (itemAt(viewport()->mapFromGlobal(QCursor::pos())));
+ if ( !item || !item->parent() || !item->folder() ) // top-level items or something invalid
+ return 0;
+ mCopySourceFolders = selectedFolders();
+
+ QDragObject *drag = KFolderTree::dragObject();
+ if ( drag )
+ drag->setPixmap( SmallIcon("folder") );
+ return drag;
+}
+
+void KMFolderTree::copyFolder()
+{
+ KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( currentItem() );
+ if ( item ) {
+ mCopySourceFolders = selectedFolders();
+ mCutFolder = false;
+ }
+ updateCopyActions();
+}
+
+void KMFolderTree::cutFolder()
+{
+ KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( currentItem() );
+ if ( item ) {
+ mCopySourceFolders = selectedFolders();
+ mCutFolder = true;
+ }
+ updateCopyActions();
+}
+
+void KMFolderTree::pasteFolder()
+{
+ KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( currentItem() );
+ if ( !mCopySourceFolders.isEmpty() && item && !mCopySourceFolders.contains( item->folder() ) ) {
+ moveOrCopyFolder( mCopySourceFolders, item->folder(), mCutFolder );
+ if ( mCutFolder )
+ mCopySourceFolders.clear();
+ }
+ updateCopyActions();
+}
+
+void KMFolderTree::updateCopyActions()
+{
+ KAction *copy = mMainWidget->action("copy_folder");
+ KAction *cut = mMainWidget->action("cut_folder");
+ KAction *paste = mMainWidget->action("paste_folder");
+ KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( currentItem() );
+
+ if ( !item || !item->folder() ) {
+ copy->setEnabled( false );
+ cut->setEnabled( false );
+ } else {
+ copy->setEnabled( true );
+ cut->setEnabled( item->folder()->isMoveable() );
+ }
+
+ if ( mCopySourceFolders.isEmpty() )
+ paste->setEnabled( false );
+ else
+ paste->setEnabled( true );
+}
+
+void KMFolderTree::slotAddToFavorites()
+{
+ KMail::FavoriteFolderView *favView = mMainWidget->favoriteFolderView();
+ assert( favView );
+ for ( QListViewItemIterator it( this ); it.current(); ++it ) {
+ if ( it.current()->isSelected() )
+ favView->addFolder( static_cast<KMFolderTreeItem*>( it.current() ) );
+ }
+}
+
+void KMFolderTree::slotUnhideLocalInbox()
+{
+ disconnect( kmkernel->inboxFolder(), SIGNAL(msgAdded(KMFolder*,Q_UINT32)),
+ this, SLOT(slotUnhideLocalInbox()) );
+ reload();
+}
+
+#include "kmfoldertree.moc"