kmail

kmfoldertree.cpp
1// kmfoldertree.cpp
2#ifdef HAVE_CONFIG_H
3#include <config.h>
4#endif
5
6#include "kmfoldertree.h"
7
8#include "kmfoldermgr.h"
9#include "kmfolder.h"
10#include "kmfolderimap.h"
11#include "kmfoldercachedimap.h"
12#include "kmfolderdia.h"
13#include "kmheaders.h"
14#include "kmmainwidget.h"
15#include "kmailicalifaceimpl.h"
16#include "accountmanager.h"
18#include "globalsettings.h"
19#include "kmcommands.h"
20#include "foldershortcutdialog.h"
21#include "expirypropertiesdialog.h"
22#include "newfolderdialog.h"
23#include "acljobs.h"
24#include "messagecopyhelper.h"
26#include "favoritefolderview.h"
27#include "folderviewtooltip.h"
28using KMail::FolderViewToolTip;
29
30#include <maillistdrag.h>
31using namespace KPIM;
32
33#include <tdeapplication.h>
34#include <tdeglobalsettings.h>
35#include <kiconloader.h>
36#include <tdemessagebox.h>
37#include <tdeconfig.h>
38#include <tdepopupmenu.h>
39#include <kdebug.h>
40
41#include <tqpainter.h>
42#include <tqcursor.h>
43#include <tqregexp.h>
44#include <tqpopupmenu.h>
45
46#include <unistd.h>
47#include <assert.h>
48
49#include <X11/Xlib.h>
50#include <fixx11h.h>
51
52//=============================================================================
53
54KMFolderTreeItem::KMFolderTreeItem( KFolderTree *parent, const TQString & name,
55 KFolderTreeItem::Protocol protocol )
56 : TQObject( parent, name.latin1() ),
57 KFolderTreeItem( parent, name, protocol, Root ),
58 mFolder( 0 ), mNeedsRepaint( true )
59{
60 init();
61 setPixmap( 0, normalIcon( iconSize() ) );
62}
63
64//-----------------------------------------------------------------------------
65KMFolderTreeItem::KMFolderTreeItem( KFolderTree *parent, const TQString & name,
66 KMFolder* folder )
67 : TQObject( parent, name.latin1() ),
68 KFolderTreeItem( parent, name ),
69 mFolder( folder ), mNeedsRepaint( true )
70{
71 init();
72 setPixmap( 0, normalIcon( iconSize() ) );
73}
74
75//-----------------------------------------------------------------------------
76KMFolderTreeItem::KMFolderTreeItem( KFolderTreeItem *parent, const TQString & name,
77 KMFolder* folder )
78 : TQObject( 0, name.latin1() ),
79 KFolderTreeItem( parent, name ),
80 mFolder( folder ), mNeedsRepaint( true )
81{
82 init();
83 setPixmap( 0, normalIcon( iconSize() ) );
84}
85
86KMFolderTreeItem::~KMFolderTreeItem()
87{
88}
89
90static KFolderTreeItem::Protocol protocolFor( KMFolderType t ) {
91 switch ( t ) {
92 case KMFolderTypeImap:
93 return KFolderTreeItem::Imap;
94 case KMFolderTypeCachedImap:
95 return KFolderTreeItem::CachedImap;
96 case KMFolderTypeMbox:
97 case KMFolderTypeMaildir:
98 return KFolderTreeItem::Local;
99 case KMFolderTypeSearch:
100 return KFolderTreeItem::Search;
101 default:
102 return KFolderTreeItem::NONE;
103 }
104}
105
106TQPixmap KMFolderTreeItem::normalIcon(int size) const
107{
108 TQString icon;
109 if ( (!mFolder && type() == Root) || useTopLevelIcon() ) {
110 switch ( protocol() ) {
111 case KFolderTreeItem::Imap:
112 case KFolderTreeItem::CachedImap:
113 case KFolderTreeItem::News:
114 icon = "server"; break;
115 case KFolderTreeItem::Search:
116 icon = "viewmag";break;
117 default:
118 icon = "folder";break;
119 }
120 } else {
121 // special folders
122 switch ( type() ) {
123 case Inbox: icon = "folder_inbox"; break;
124 case Outbox: icon = "folder_outbox"; break;
125 case SentMail: icon = "folder_sent_mail"; break;
126 case Trash: icon = "trashcan_empty"; break;
127 case Drafts: icon = "edit"; break;
128 case Templates: icon = "document-new"; break;
129 default:
130 {
131 //If not a resource folder don't try to use icalIface folder pixmap
132 if(kmkernel->iCalIface().isResourceFolder( mFolder ))
133 icon = kmkernel->iCalIface().folderPixmap( type() );
134 break;
135 }
136 }
137 // non-root search folders
138 if ( protocol() == KMFolderTreeItem::Search ) {
139 icon = "mail_find";
140 }
141 if ( mFolder && mFolder->noContent() ) {
142 icon = "folder_grey";
143 }
144 }
145
146 if ( icon.isEmpty() )
147 icon = "folder";
148
149 if (mFolder && mFolder->useCustomIcons() ) {
150 icon = mFolder->normalIconPath();
151 }
152 TDEIconLoader * il = TDEGlobal::instance()->iconLoader();
153 TQPixmap pm = il->loadIcon( icon, TDEIcon::Small, size,
154 TDEIcon::DefaultState, 0, true );
155 if ( mFolder && pm.isNull() ) {
156 pm = il->loadIcon( mFolder->normalIconPath(), TDEIcon::Small, size,
157 TDEIcon::DefaultState, 0, true );
158 }
159
160 return pm;
161}
162
163TQPixmap KMFolderTreeItem::unreadIcon(int size) const
164{
165 TQPixmap pm;
166
167 if ( !mFolder || useTopLevelIcon() || mFolder->isSystemFolder() ||
168 kmkernel->folderIsTrash( mFolder ) ||
169 kmkernel->folderIsTemplates( mFolder ) ||
170 kmkernel->folderIsDraftOrOutbox( mFolder ) )
171 pm = normalIcon( size );
172
173 TDEIconLoader * il = TDEGlobal::instance()->iconLoader();
174 if ( mFolder && mFolder->useCustomIcons() ) {
175 pm = il->loadIcon( mFolder->unreadIconPath(), TDEIcon::Small, size,
176 TDEIcon::DefaultState, 0, true );
177 if ( pm.isNull() )
178 pm = il->loadIcon( mFolder->normalIconPath(), TDEIcon::Small, size,
179 TDEIcon::DefaultState, 0, true );
180 }
181 if ( pm.isNull() ) {
182 if ( mFolder && mFolder->noContent() ) {
183 pm = il->loadIcon( "folder_grey_open", TDEIcon::Small, size,
184 TDEIcon::DefaultState, 0, true );
185 } else {
186 if( kmkernel->iCalIface().isResourceFolder( mFolder ) )
187 pm = il->loadIcon( kmkernel->iCalIface().folderPixmap( type() ),
188 TDEIcon::Small, size, TDEIcon::DefaultState, 0, true );
189 if ( pm.isNull() )
190 pm = il->loadIcon( "folder_open", TDEIcon::Small, size,
191 TDEIcon::DefaultState, 0, true );
192 }
193 }
194
195 return pm;
196}
197
198void KMFolderTreeItem::init()
199{
200 if ( !mFolder )
201 return;
202
203 setProtocol( protocolFor( mFolder->folderType() ) );
204
205 if ( useTopLevelIcon() )
206 setType(Root);
207 else {
208 if ( mFolder == kmkernel->inboxFolder() )
209 setType( Inbox );
210 else if ( kmkernel->folderIsDraftOrOutbox( mFolder ) ) {
211 if ( mFolder == kmkernel->outboxFolder() )
212 setType( Outbox );
213 else
214 setType( Drafts );
215 }
216 else if ( kmkernel->folderIsSentMailFolder( mFolder ) )
217 setType( SentMail );
218 else if ( kmkernel->folderIsTrash( mFolder ) )
219 setType( Trash );
220 else if ( kmkernel->folderIsTemplates( mFolder ) )
221 setType( Templates );
222 else if( kmkernel->iCalIface().isResourceFolder(mFolder) )
223 setType( kmkernel->iCalIface().folderType(mFolder) );
224 // System folders on dimap or imap which are not resource folders are
225 // inboxes. Urgs.
226 if ( mFolder->isSystemFolder() &&
227 !kmkernel->iCalIface().isResourceFolder( mFolder) &&
228 ( mFolder->folderType() == KMFolderTypeImap
229 || mFolder->folderType() == KMFolderTypeCachedImap ) )
230 setType( Inbox );
231 }
232 if ( !mFolder->isSystemFolder() )
233 setRenameEnabled( 0, false );
234
235 KMFolderTree* tree = dynamic_cast<KMFolderTree*>( listView() );
236 if ( tree )
237 tree->insertIntoFolderToItemMap( mFolder, this );
238}
239
240void KMFolderTreeItem::adjustUnreadCount( int newUnreadCount ) {
241 // adjust the icons if the folder is now newly unread or
242 // now newly not-unread
243 if ( newUnreadCount != 0 && unreadCount() == 0 )
244 setPixmap( 0, unreadIcon( iconSize() ) );
245 if ( unreadCount() != 0 && newUnreadCount == 0 )
246 setPixmap( 0, normalIcon( iconSize() ) );
247
248 setUnreadCount( newUnreadCount );
249}
250
251void KMFolderTreeItem::slotIconsChanged()
252{
253 kdDebug(5006) << k_funcinfo << endl;
254 // this is prone to change, so better check
255 KFolderTreeItem::Type newType = type();
256 if( kmkernel->iCalIface().isResourceFolder( mFolder ) )
257 newType = kmkernel->iCalIface().folderType(mFolder);
258
259 // reload the folder tree if the type changed, needed because of the
260 // various type-dependent folder hiding options
261 if ( type() != newType )
262 static_cast<KMFolderTree*>( listView() )->delayedReload();
263 setType( newType );
264
265 if ( unreadCount() > 0 )
266 setPixmap( 0, unreadIcon( iconSize() ) );
267 else
268 setPixmap( 0, normalIcon( iconSize() ) );
269 emit iconChanged( this );
270 repaint();
271}
272
273void KMFolderTreeItem::slotNameChanged()
274{
275 setText( 0, mFolder->label() );
276 emit nameChanged( this );
277 repaint();
278}
279
280void KMFolderTreeItem::slotNoContentChanged()
281{
282 // reload the folder tree if the no content state changed, needed because
283 // we hide no-content folders if their child nodes are hidden
284 TQTimer::singleShot( 0, static_cast<KMFolderTree*>( listView() ), TQ_SLOT(reload()) );
285}
286
287//-----------------------------------------------------------------------------
288bool KMFolderTreeItem::acceptDrag(TQDropEvent* e) const
289{
290 // Do not allow drags from the favorite folder view, as they don't really
291 // make sense and do not work.
292 KMMainWidget *mainWidget = static_cast<KMFolderTree*>( listView() )->mainWidget();
293 assert( mainWidget );
294 if ( mainWidget->favoriteFolderView() &&
295 e->source() == mainWidget->favoriteFolderView()->viewport() )
296 return false;
297
298 if ( protocol() == KFolderTreeItem::Search )
299 return false; // nothing can be dragged into search folders
300
301 if ( e->provides( KPIM::MailListDrag::format() ) ) {
302 if ( !mFolder || mFolder->moveInProgress() || mFolder->isReadOnly() ||
303 (mFolder->noContent() && childCount() == 0) ||
304 (mFolder->noContent() && isOpen()) ) {
305 return false;
306 }
307 else {
308 return true;
309 }
310 } else if ( e->provides("application/x-qlistviewitem") ) {
311 // wtf: protocol() is NONE instead of Local for the local root folder
312 if ( !mFolder && protocol() == KFolderTreeItem::NONE && type() == KFolderTreeItem::Root )
313 return true; // local top-level folder
314 if ( !mFolder || mFolder->isReadOnly() || mFolder->noContent() )
315 return false;
316 return true;
317 }
318 return false;
319}
320
321//-----------------------------------------------------------------------------
322void KMFolderTreeItem::slotShowExpiryProperties()
323{
324 if ( !mFolder )
325 return;
326
327 KMFolderTree* tree = static_cast<KMFolderTree*>( listView() );
328 KMail::ExpiryPropertiesDialog *dlg =
329 new KMail::ExpiryPropertiesDialog( tree, mFolder );
330 dlg->show();
331}
332
333
334//-----------------------------------------------------------------------------
335void KMFolderTreeItem::properties()
336{
337 if ( !mFolder )
338 return;
339
340 KMail::FolderTreeBase* tree = static_cast<KMail::FolderTreeBase*>( listView() );
341 tree->mainWidget()->modifyFolder( this );
342 //Nothing here the above may actually delete this KMFolderTreeItem
343}
344
345//-----------------------------------------------------------------------------
346void KMFolderTreeItem::assignShortcut()
347{
348 if ( !mFolder )
349 return;
350
351 KMail::FolderShortcutDialog *shorty =
352 new KMail::FolderShortcutDialog( mFolder,
353 kmkernel->getKMMainWidget(),
354 listView() );
355 shorty->exec();
356 delete shorty;
357}
358
359//-----------------------------------------------------------------------------
360void KMFolderTreeItem::updateCount()
361{
362 if ( !folder() ) {
363 setTotalCount( -1 );
364 return;
365 }
366 KMail::FolderTreeBase* tree = dynamic_cast<KMail::FolderTreeBase*>( listView() );
367 if ( !tree ) return;
368
369 tree->slotUpdateCounts( folder(), true /* force update */ );
370}
371
372
373//=============================================================================
374
375
376KMFolderTree::KMFolderTree( KMMainWidget *mainWidget, TQWidget *parent,
377 const char *name )
378 : KMail::FolderTreeBase( mainWidget, parent, name )
379 , mUpdateTimer( 0, "mUpdateTimer" )
380 , autoopen_timer( 0, "autoopen_timer" )
381{
382 oldSelected = 0;
383 oldCurrent = 0;
384 mLastItem = 0;
385 dropItem = 0;
386 mMainWidget = mainWidget;
387 mReloading = false;
388 mCutFolder = false;
389
390 mUpdateCountTimer= new TQTimer( this, "mUpdateCountTimer" );
391
392 setDragEnabled( true );
393 addAcceptableDropMimetype( "application/x-qlistviewitem", false );
394
395 setSelectionModeExt( Extended );
396
397 int namecol = addColumn( i18n("Folder"), 250 );
398 header()->setStretchEnabled( true, namecol );
399 setResizeMode( TQListView::NoColumn );
400 // connect
401 connectSignals();
402
403 // popup to switch columns
404 header()->setClickEnabled(true);
405 header()->installEventFilter(this);
406 mPopup = new TDEPopupMenu(this);
407 mPopup->insertTitle(i18n("View Columns"));
408 mPopup->setCheckable(true);
409 mUnreadPop = mPopup->insertItem(i18n("Unread Column"), this, TQ_SLOT(slotToggleUnreadColumn()));
410 mTotalPop = mPopup->insertItem(i18n("Total Column"), this, TQ_SLOT(slotToggleTotalColumn()));
411 mSizePop = mPopup->insertItem(i18n("Size Column"), this, TQ_SLOT(slotToggleSizeColumn()));
412
413 connect( this, TQ_SIGNAL( triggerRefresh() ),
414 this, TQ_SLOT( refresh() ) );
415
416 new FolderViewToolTip( this );
417}
418
419//-----------------------------------------------------------------------------
420// connects all needed signals to their slots
421void KMFolderTree::connectSignals()
422{
423 connect( mUpdateCountTimer, TQ_SIGNAL(timeout()),
424 this, TQ_SLOT(slotUpdateCountTimeout()) );
425
426 connect(&mUpdateTimer, TQ_SIGNAL(timeout()),
427 this, TQ_SLOT(delayedUpdate()));
428
429 connect(kmkernel->folderMgr(), TQ_SIGNAL(changed()),
430 this, TQ_SLOT(doFolderListChanged()));
431
432 connect(kmkernel->folderMgr(), TQ_SIGNAL(folderRemoved(KMFolder*)),
433 this, TQ_SLOT(slotFolderRemoved(KMFolder*)));
434
435 connect(kmkernel->folderMgr(), TQ_SIGNAL(folderMoveOrCopyOperationFinished()),
436 this, TQ_SLOT(slotFolderMoveOrCopyOperationFinished()));
437
438 connect(kmkernel->imapFolderMgr(), TQ_SIGNAL(changed()),
439 this, TQ_SLOT(doFolderListChanged()));
440
441 connect(kmkernel->imapFolderMgr(), TQ_SIGNAL(folderRemoved(KMFolder*)),
442 this, TQ_SLOT(slotFolderRemoved(KMFolder*)));
443
444 connect(kmkernel->dimapFolderMgr(), TQ_SIGNAL(changed()),
445 this, TQ_SLOT(doFolderListChanged()));
446
447 connect(kmkernel->dimapFolderMgr(), TQ_SIGNAL(folderRemoved(KMFolder*)),
448 this, TQ_SLOT(slotFolderRemoved(KMFolder*)));
449
450 connect(kmkernel->searchFolderMgr(), TQ_SIGNAL(changed()),
451 this, TQ_SLOT(doFolderListChanged()));
452
453 connect(kmkernel->acctMgr(), TQ_SIGNAL(accountRemoved(KMAccount*)),
454 this, TQ_SLOT(slotAccountRemoved(KMAccount*)));
455
456 connect(kmkernel->acctMgr(), TQ_SIGNAL(accountAdded(KMAccount*)),
457 this, TQ_SLOT(slotUnhideLocalInbox()));
458
459 connect(kmkernel->searchFolderMgr(), TQ_SIGNAL(folderRemoved(KMFolder*)),
460 this, TQ_SLOT(slotFolderRemoved(KMFolder*)));
461
462 connect( &autoopen_timer, TQ_SIGNAL( timeout() ),
463 this, TQ_SLOT( openFolder() ) );
464
465 connect( this, TQ_SIGNAL( contextMenuRequested( TQListViewItem*, const TQPoint &, int ) ),
466 this, TQ_SLOT( slotContextMenuRequested( TQListViewItem*, const TQPoint & ) ) );
467
468 connect( this, TQ_SIGNAL( expanded( TQListViewItem* ) ),
469 this, TQ_SLOT( slotFolderExpanded( TQListViewItem* ) ) );
470
471 connect( this, TQ_SIGNAL( collapsed( TQListViewItem* ) ),
472 this, TQ_SLOT( slotFolderCollapsed( TQListViewItem* ) ) );
473
474 connect( this, TQ_SIGNAL( itemRenamed( TQListViewItem*, int, const TQString &)),
475 this, TQ_SLOT( slotRenameFolder( TQListViewItem*, int, const TQString &)));
476
477 connect( this, TQ_SIGNAL(folderSelected(KMFolder*)), TQ_SLOT(updateCopyActions()) );
478}
479
480//-----------------------------------------------------------------------------
481void KMFolderTree::readConfig (void)
482{
483 TDEConfig* conf = KMKernel::config();
484
485 readColorConfig();
486
487 // Custom/Ssystem font support
488 {
489 TDEConfigGroupSaver saver(conf, "Fonts");
490 if (!conf->readBoolEntry("defaultFonts",true)) {
491 TQFont folderFont( TDEGlobalSettings::generalFont() );
492 setFont(conf->readFontEntry("folder-font", &folderFont));
493 }
494 else
495 setFont(TDEGlobalSettings::generalFont());
496 }
497
498 // restore the layout
499 restoreLayout(conf, "Geometry");
500}
501
502//-----------------------------------------------------------------------------
503// Save the configuration file
504void KMFolderTree::writeConfig()
505{
506 // save the current state of the folders
507 for ( TQListViewItemIterator it( this ) ; it.current() ; ++it ) {
508 KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
509 if (fti)
510 writeIsListViewItemOpen(fti);
511 }
512
513 // save the current layout
514 saveLayout(KMKernel::config(), "Geometry");
515}
516
517//-----------------------------------------------------------------------------
518// Updates the count of unread messages (count of unread messages
519// is now cached in KMails config file)
520void KMFolderTree::updateUnreadAll()
521{
522 bool upd = isUpdatesEnabled();
523 setUpdatesEnabled(false);
524
525 KMFolderDir* fdir;
526 KMFolderNode* folderNode;
527 KMFolder* folder;
528
529 fdir = &kmkernel->folderMgr()->dir();
530 for (folderNode = fdir->first();
531 folderNode != 0;
532 folderNode =fdir->next())
533 {
534 if (!folderNode->isDir()) {
535 folder = static_cast<KMFolder*>(folderNode);
536
537 folder->open("updateunread");
538 folder->countUnread();
539 folder->close("updateunread");
540 }
541 }
542
543 setUpdatesEnabled(upd);
544}
545
546//-----------------------------------------------------------------------------
547// Reload the tree of items in the list view
548void KMFolderTree::reload(bool openFolders)
549{
550 if ( mReloading ) {
551 // no parallel reloads are allowed
552 kdDebug(5006) << "KMFolderTree::reload - already reloading" << endl;
553 return;
554 }
555 mReloading = true;
556
557 int top = contentsY();
558 mLastItem = 0;
559 // invalidate selected drop item
560 oldSelected = 0;
561 // remember last
562 KMFolder* last = currentFolder();
563 KMFolder* selected = 0;
564 KMFolder* oldCurrentFolder =
565 ( oldCurrent ? static_cast<KMFolderTreeItem*>(oldCurrent)->folder(): 0 );
566 for ( TQListViewItemIterator it( this ) ; it.current() ; ++it ) {
567 KMFolderTreeItem * fti = static_cast<KMFolderTreeItem*>(it.current());
568 writeIsListViewItemOpen( fti );
569 if ( fti->isSelected() )
570 selected = fti->folder();
571 }
572 mFolderToItem.clear();
573 clear();
574
575 // construct the root of the local folders
576 KMFolderTreeItem * root = new KMFolderTreeItem( this, i18n("Local Folders") );
577 root->setOpen( readIsListViewItemOpen(root) );
578
579 KMFolderDir * fdir = &kmkernel->folderMgr()->dir();
580 addDirectory(fdir, root);
581
582 fdir = &kmkernel->imapFolderMgr()->dir();
583 // each imap-account creates it's own root
584 addDirectory(fdir, 0);
585
586 fdir = &kmkernel->dimapFolderMgr()->dir();
587 // each dimap-account creates it's own root
588 addDirectory(fdir, 0);
589
590 // construct the root of the search folder hierarchy:
591 root = new KMFolderTreeItem( this, i18n("Searches"), KFolderTreeItem::Search );
592 root->setOpen( readIsListViewItemOpen( root ) );
593
594 fdir = &kmkernel->searchFolderMgr()->dir();
595 addDirectory(fdir, root);
596
597 if (openFolders)
598 {
599 // we open all folders to update the count
600 mUpdateIterator = TQListViewItemIterator (this);
601 TQTimer::singleShot( 0, this, TQ_SLOT(slotUpdateOneCount()) );
602 }
603
604 for ( TQListViewItemIterator it( this ) ; it.current() ; ++it ) {
605 KMFolderTreeItem * fti = static_cast<KMFolderTreeItem*>(it.current());
606 if ( !fti || !fti->folder() )
607 continue;
608
609 disconnect(fti->folder(),TQ_SIGNAL(iconsChanged()),
610 fti,TQ_SLOT(slotIconsChanged()));
611 connect(fti->folder(),TQ_SIGNAL(iconsChanged()),
612 fti,TQ_SLOT(slotIconsChanged()));
613
614 disconnect(fti->folder(),TQ_SIGNAL(nameChanged()),
615 fti,TQ_SLOT(slotNameChanged()));
616 connect(fti->folder(),TQ_SIGNAL(nameChanged()),
617 fti,TQ_SLOT(slotNameChanged()));
618
619 disconnect( fti->folder(), TQ_SIGNAL(noContentChanged()),
620 fti, TQ_SLOT(slotNoContentChanged()) );
621 connect( fti->folder(), TQ_SIGNAL(noContentChanged()),
622 fti, TQ_SLOT(slotNoContentChanged()) );
623
624 disconnect( fti->folder(), TQ_SIGNAL(syncStateChanged()),
625 this, TQ_SLOT(slotSyncStateChanged()) );
626 connect( fti->folder(), TQ_SIGNAL(syncStateChanged()),
627 this, TQ_SLOT(slotSyncStateChanged()) );
628
629 // we want to be noticed of changes to update the unread/total columns
630 disconnect(fti->folder(), TQ_SIGNAL(msgAdded(KMFolder*,TQ_UINT32)),
631 this,TQ_SLOT(slotUpdateCountsDelayed(KMFolder*)));
632 connect(fti->folder(), TQ_SIGNAL(msgAdded(KMFolder*,TQ_UINT32)),
633 this,TQ_SLOT(slotUpdateCountsDelayed(KMFolder*)));
634 //}
635
636 disconnect(fti->folder(), TQ_SIGNAL(numUnreadMsgsChanged(KMFolder*)),
637 this,TQ_SLOT(slotUpdateCountsDelayed(KMFolder*)));
638 connect(fti->folder(), TQ_SIGNAL(numUnreadMsgsChanged(KMFolder*)),
639 this,TQ_SLOT(slotUpdateCountsDelayed(KMFolder*)));
640 disconnect(fti->folder(), TQ_SIGNAL(msgRemoved(KMFolder*)),
641 this,TQ_SLOT(slotUpdateCountsDelayed(KMFolder*)));
642 connect(fti->folder(), TQ_SIGNAL(msgRemoved(KMFolder*)),
643 this,TQ_SLOT(slotUpdateCountsDelayed(KMFolder*)));
644
645 disconnect(fti->folder(), TQ_SIGNAL(folderSizeChanged( KMFolder* )),
646 this,TQ_SLOT(slotUpdateCountsDelayed(KMFolder*)));
647 connect(fti->folder(), TQ_SIGNAL(folderSizeChanged( KMFolder* )),
648 this,TQ_SLOT(slotUpdateCountsDelayed(KMFolder*)));
649
650
651
652 disconnect(fti->folder(), TQ_SIGNAL(shortcutChanged(KMFolder*)),
653 mMainWidget, TQ_SLOT( slotShortcutChanged(KMFolder*)));
654 connect(fti->folder(), TQ_SIGNAL(shortcutChanged(KMFolder*)),
655 mMainWidget, TQ_SLOT( slotShortcutChanged(KMFolder*)));
656
657
658 if (!openFolders)
659 slotUpdateCounts(fti->folder());
660
661 // populate the size column
662 fti->setFolderSize( 0 );
663 fti->setFolderIsCloseToQuota( fti->folder()->storage()->isCloseToQuota() );
664
665 }
666 ensureVisible(0, top + visibleHeight(), 0, 0);
667 // if current and selected folder did not change set it again
668 for ( TQListViewItemIterator it( this ) ; it.current() ; ++it )
669 {
670 if ( last &&
671 static_cast<KMFolderTreeItem*>( it.current() )->folder() == last )
672 {
673 mLastItem = static_cast<KMFolderTreeItem*>( it.current() );
674 setCurrentItem( it.current() );
675 }
676 if ( selected &&
677 static_cast<KMFolderTreeItem*>( it.current() )->folder() == selected )
678 {
679 setSelected( it.current(), true );
680 }
681 if ( oldCurrentFolder &&
682 static_cast<KMFolderTreeItem*>( it.current() )->folder() == oldCurrentFolder )
683 {
684 oldCurrent = it.current();
685 }
686 }
687 refresh();
688 mReloading = false;
689}
690
691//-----------------------------------------------------------------------------
692void KMFolderTree::slotUpdateOneCount()
693{
694 if ( !mUpdateIterator.current() ) return;
695 KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(mUpdateIterator.current());
696 ++mUpdateIterator;
697 if ( !fti->folder() ) {
698 // next one please
699 TQTimer::singleShot( 0, this, TQ_SLOT(slotUpdateOneCount()) );
700 return;
701 }
702
703 // open the folder and update the count
704 bool open = fti->folder()->isOpened();
705 if (!open) fti->folder()->open("updatecount");
706 slotUpdateCounts(fti->folder());
707 // restore previous state
708 if (!open) fti->folder()->close("updatecount");
709
710 TQTimer::singleShot( 0, this, TQ_SLOT(slotUpdateOneCount()) );
711}
712
713//-----------------------------------------------------------------------------
714// Recursively add a directory of folders to the tree of folders
715void KMFolderTree::addDirectory( KMFolderDir *fdir, KMFolderTreeItem* parent )
716{
717 for ( KMFolderNode * node = fdir->first() ; node ; node = fdir->next() ) {
718 if ( node->isDir() )
719 continue;
720
721 KMFolder * folder = static_cast<KMFolder*>(node);
722 KMFolderTreeItem * fti = 0;
723 if (!parent)
724 {
725 // create new root-item, but only if this is not the root of a
726 // "groupware folders only" account
727 if ( kmkernel->iCalIface().hideResourceAccountRoot( folder ) )
728 continue;
729 // it needs a folder e.g. to save it's state (open/close)
730 fti = new KMFolderTreeItem( this, folder->label(), folder );
731 fti->setExpandable( true );
732
733 // add child-folders
734 if (folder && folder->child()) {
735 addDirectory( folder->child(), fti );
736 }
737 } else {
738 // hide local inbox if unused
739 if ( kmkernel->inboxFolder() == folder && hideLocalInbox() ) {
740 connect( kmkernel->inboxFolder(), TQ_SIGNAL(msgAdded(KMFolder*,TQ_UINT32)), TQ_SLOT(slotUnhideLocalInbox()) );
741 continue;
742 }
743
744 // create new child
745 fti = new KMFolderTreeItem( parent, folder->label(), folder );
746 // set folders explicitely to exandable when they have children
747 // this way we can do a listing for IMAP folders when the user expands them
748 // even when the child folders are not created yet
749 if ( folder->storage()->hasChildren() == FolderStorage::HasChildren ) {
750 fti->setExpandable( true );
751 } else {
752 fti->setExpandable( false );
753 }
754
755 // add child-folders
756 if (folder && folder->child()) {
757 addDirectory( folder->child(), fti );
758 }
759
760 // Check if this is an IMAP resource folder or a no-content parent only
761 // containing groupware folders
762 if ( (kmkernel->iCalIface().hideResourceFolder( folder ) || folder->noContent())
763 && fti->childCount() == 0 ) {
764 // It is
765 removeFromFolderToItemMap( folder );
766 delete fti;
767 // still, it might change in the future, so we better check the change signals
768 connect ( folder, TQ_SIGNAL(noContentChanged()), TQ_SLOT(delayedReload()) );
769 continue;
770 }
771
772 connect (fti, TQ_SIGNAL(iconChanged(KMFolderTreeItem*)),
773 this, TQ_SIGNAL(iconChanged(KMFolderTreeItem*)));
774 connect (fti, TQ_SIGNAL(nameChanged(KMFolderTreeItem*)),
775 this, TQ_SIGNAL(nameChanged(KMFolderTreeItem*)));
776 }
777 // restore last open-state
778 fti->setOpen( readIsListViewItemOpen(fti) );
779 } // for-end
780}
781
782//-----------------------------------------------------------------------------
783// Initiate a delayed refresh of the tree
784void KMFolderTree::refresh()
785{
786 mUpdateTimer.changeInterval(200);
787}
788
789//-----------------------------------------------------------------------------
790// Updates the pixmap and extendedLabel information for items
791void KMFolderTree::delayedUpdate()
792{
793 bool upd = isUpdatesEnabled();
794 if ( upd ) {
795 setUpdatesEnabled(false);
796
797 for ( TQListViewItemIterator it( this ) ; it.current() ; ++it ) {
798 KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
799 if (!fti || !fti->folder())
800 continue;
801
802 if ( fti->needsRepaint() ) {
803 fti->repaint();
804 fti->setNeedsRepaint( false );
805 }
806 }
807 setUpdatesEnabled(upd);
808 }
809 mUpdateTimer.stop();
810}
811
812//-----------------------------------------------------------------------------
813// Folders have been added/deleted update the tree of folders
814void KMFolderTree::doFolderListChanged()
815{
816 reload();
817}
818
819//-----------------------------------------------------------------------------
820void KMFolderTree::slotAccountRemoved(KMAccount *)
821{
822 doFolderSelected( firstChild() );
823}
824
825//-----------------------------------------------------------------------------
826void KMFolderTree::slotFolderMoveOrCopyOperationFinished()
827{
828 setDragEnabled( true );
829}
830//-----------------------------------------------------------------------------
831void KMFolderTree::slotFolderRemoved(KMFolder *aFolder)
832{
833 TQListViewItem *item = indexOfFolder(aFolder);
834 if (!item) return;
835 KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*> ( item );
836 if ( oldCurrent == fti )
837 oldCurrent = 0;
838 if ( oldSelected == fti )
839 oldSelected = 0;
840 if (!fti || !fti->folder()) return;
841 if (fti == currentItem())
842 {
843 TQListViewItem *qlvi = fti->itemAbove();
844 if (!qlvi) qlvi = fti->itemBelow();
845 doFolderSelected( qlvi );
846 }
847 removeFromFolderToItemMap( aFolder );
848
849 if ( dropItem == fti ) { // The removed item is the dropItem
850 dropItem = 0; // it becomes invalid
851 }
852
853 delete fti;
854 updateCopyActions();
855}
856
857//-----------------------------------------------------------------------------
858// Methods for navigating folders with the keyboard
859void KMFolderTree::prepareItem( KMFolderTreeItem* fti )
860{
861 for ( TQListViewItem * parent = fti->parent() ; parent ; parent = parent->parent() )
862 parent->setOpen( true );
863 ensureItemVisible( fti );
864}
865
866//-----------------------------------------------------------------------------
867void KMFolderTree::nextUnreadFolder()
868{
869 nextUnreadFolder( false );
870}
871
872//-----------------------------------------------------------------------------
873void KMFolderTree::nextUnreadFolder(bool confirm)
874{
875 TQListViewItemIterator it( currentItem() ? currentItem() : firstChild() );
876 if ( currentItem() )
877 ++it; // don't find current item
878 for ( ; it.current() ; ++it ) {
879 //check if folder is one to stop on
880 KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
881 if (checkUnreadFolder(fti,confirm)) return;
882 }
883 //Now if confirm is true we are doing "ReadOn"
884 //we have got to the bottom of the folder list
885 //so we have to start at the top
886 if (confirm) {
887 for ( it = firstChild() ; it.current() ; ++it ) {
888 //check if folder is one to stop on
889 KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
890 if (checkUnreadFolder(fti,confirm)) return;
891 }
892 }
893}
894
895//-----------------------------------------------------------------------------
896bool KMFolderTree::checkUnreadFolder (KMFolderTreeItem* fti, bool confirm)
897{
898 if ( fti && fti->folder() && !fti->folder()->ignoreNewMail() &&
899 ( fti->folder()->countUnread() > 0 ) ) {
900
901 // Don't change into the trash or outbox folders.
902 if (fti->type() == KFolderTreeItem::Trash ||
903 fti->type() == KFolderTreeItem::Outbox )
904 return false;
905
906 if (confirm) {
907 // Skip drafts, sent mail and templates as well, when reading mail with
908 // the space bar but not when changing into the next folder with unread
909 // mail via ctrl+ or ctrl- so we do this only if (confirm == true),
910 // which means we are doing readOn.
911 if ( fti->type() == KFolderTreeItem::Drafts ||
912 fti->type() == KFolderTreeItem::Templates ||
913 fti->type() == KFolderTreeItem::SentMail )
914 return false;
915
916 // warn user that going to next folder - but keep track of
917 // whether he wishes to be notified again in "AskNextFolder"
918 // parameter (kept in the config file for kmail)
919 if ( KMessageBox::questionYesNo( this,
920 i18n( "<qt>Go to the next unread message in folder <b>%1</b>?</qt>" )
921 .arg( fti->folder()->label() ),
922 i18n( "Go to Next Unread Message" ),
923 i18n("Go To"), i18n("Do Not Go To"), // defaults
924 "AskNextFolder",
925 false)
926 == KMessageBox::No ) return true;
927 }
928 prepareItem( fti );
929 blockSignals( true );
930 doFolderSelected( fti );
931 blockSignals( false );
932 emit folderSelectedUnread( fti->folder() );
933 return true;
934 }
935 return false;
936}
937
938//-----------------------------------------------------------------------------
939void KMFolderTree::prevUnreadFolder()
940{
941 TQListViewItemIterator it( currentItem() ? currentItem() : lastItem() );
942 if ( currentItem() )
943 --it; // don't find current item
944 for ( ; it.current() ; --it ) {
945 KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
946 if (checkUnreadFolder(fti,false)) return;
947 }
948}
949
950//-----------------------------------------------------------------------------
951void KMFolderTree::incCurrentFolder()
952{
953 TQListViewItemIterator it( currentItem() );
954 ++it;
955 KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
956 if (fti) {
957 prepareItem( fti );
958 setFocus();
959 setCurrentItem( fti );
960 }
961}
962
963//-----------------------------------------------------------------------------
964void KMFolderTree::decCurrentFolder()
965{
966 TQListViewItemIterator it( currentItem() );
967 --it;
968 KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current());
969 if (fti) {
970 prepareItem( fti );
971 setFocus();
972 setCurrentItem( fti );
973 }
974}
975
976//-----------------------------------------------------------------------------
977void KMFolderTree::selectCurrentFolder()
978{
979 KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>( currentItem() );
980 if (fti) {
981 prepareItem( fti );
982 doFolderSelected( fti );
983 }
984}
985
986//-----------------------------------------------------------------------------
987KMFolder *KMFolderTree::currentFolder() const
988{
989 KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>( currentItem() );
990 if (fti )
991 return fti->folder();
992 else
993 return 0;
994}
995
996TQValueList<TQGuardedPtr<KMFolder> > KMFolderTree::selectedFolders()
997{
998 TQValueList<TQGuardedPtr<KMFolder> > rv;
999 for ( TQListViewItemIterator it( this ); it.current(); ++it ) {
1000 if ( it.current()->isSelected() ) {
1001 KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>( it.current() );
1002 rv.append( fti->folder() );
1003 }
1004 }
1005 return rv;
1006}
1007
1008//-----------------------------------------------------------------------------
1009// When not dragging and dropping a change in the selected item
1010// indicates the user has changed the active folder emit a signal
1011// so that the header list and reader window can be udpated.
1012void KMFolderTree::doFolderSelected( TQListViewItem* qlvi, bool keepSelection )
1013{
1014 if (!qlvi) return;
1015 if ( mLastItem && mLastItem == qlvi && (keepSelection || selectedFolders().count() == 1) )
1016 return;
1017
1018 KMFolderTreeItem* fti = static_cast< KMFolderTreeItem* >(qlvi);
1019 KMFolder* folder = 0;
1020 if (fti) folder = fti->folder();
1021
1022 if (mLastItem && mLastItem != fti && mLastItem->folder()
1023 && (mLastItem->folder()->folderType() == KMFolderTypeImap))
1024 {
1025 KMFolderImap *imapFolder = static_cast<KMFolderImap*>(mLastItem->folder()->storage());
1026 imapFolder->setSelected(false);
1027 }
1028 mLastItem = fti;
1029
1030 if ( !keepSelection )
1031 clearSelection();
1032 setCurrentItem( qlvi );
1033 if ( !keepSelection )
1034 setSelected( qlvi, true );
1035 ensureItemVisible( qlvi );
1036 if (!folder) {
1037 emit folderSelected(0); // Root has been selected
1038 }
1039 else {
1040 emit folderSelected(folder);
1041 slotUpdateCounts(folder);
1042 }
1043}
1044
1045//-----------------------------------------------------------------------------
1046void KMFolderTree::resizeEvent(TQResizeEvent* e)
1047{
1048 TDEConfig* conf = KMKernel::config();
1049
1050 TDEConfigGroupSaver saver(conf, "Geometry");
1051 conf->writeEntry(name(), size().width());
1052
1053 TDEListView::resizeEvent(e);
1054}
1055
1056//-----------------------------------------------------------------------------
1057// show context menu
1058void KMFolderTree::slotContextMenuRequested( TQListViewItem *lvi,
1059 const TQPoint &p )
1060{
1061 if (!lvi)
1062 return;
1063 setCurrentItem( lvi );
1064
1065 if (!mMainWidget) return; // safe bet
1066
1067 KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(lvi);
1068 if ( !isSelected( fti ) )
1069 doFolderSelected( fti );
1070 else if ( fti != mLastItem )
1071 doFolderSelected( fti, true );
1072
1073 if (!fti )
1074 return;
1075
1076 TDEPopupMenu *folderMenu = new TDEPopupMenu;
1077 bool multiFolder = selectedFolders().count() > 1;
1078 if (fti->folder()) folderMenu->insertTitle(fti->folder()->label());
1079
1080 // outbox specific, but there it's the most used action
1081 if ( (fti->folder() == kmkernel->outboxFolder()) && fti->folder()->count() )
1082 mMainWidget->action("send_queued")->plug( folderMenu );
1083 // Mark all as read is supposedly used often, therefor it is first
1084 if ( fti->folder() && !fti->folder()->noContent() )
1085 mMainWidget->action("mark_all_as_read")->plug( folderMenu );
1086
1087 /* Treat the special case of the root and account folders */
1088 if ((!fti->folder() || (fti->folder()->noContent()
1089 && !fti->parent())))
1090 {
1091 TQString createChild = i18n("&New Subfolder...");
1092 if (!fti->folder()) createChild = i18n("&New Folder...");
1093
1094 if ( ( fti->folder() || (fti->text(0) != i18n("Searches")) ) && !multiFolder)
1095 folderMenu->insertItem(SmallIconSet("folder-new"),
1096 createChild, this,
1097 TQ_SLOT(addChildFolder()));
1098
1099 if (!fti->folder()) {
1100 mMainWidget->action("compact_all_folders")->plug(folderMenu);
1101 mMainWidget->action("expire_all_folders")->plug(folderMenu);
1102 } else if (fti->folder()->folderType() == KMFolderTypeImap) {
1103 folderMenu->insertItem(SmallIconSet("mail_get"), i18n("Check &Mail"),
1104 this,
1105 TQ_SLOT(slotCheckMail()));
1106 }
1107 } else { // regular folders
1108
1109 folderMenu->insertSeparator();
1110 if ( !fti->folder()->noChildren() && !multiFolder ) {
1111 folderMenu->insertItem(SmallIconSet("folder-new"),
1112 i18n("&New Subfolder..."), this,
1113 TQ_SLOT(addChildFolder()));
1114 }
1115
1116 // copy folder
1117 TQPopupMenu *copyMenu = new TQPopupMenu( folderMenu );
1118 folderToPopupMenu( CopyFolder, this, &mMenuToFolder, copyMenu );
1119 folderMenu->insertItem( i18n("&Copy Folder To"), copyMenu );
1120
1121 if ( fti->folder()->isMoveable() && fti->folder()->canDeleteMessages() )
1122 {
1123 TQPopupMenu *moveMenu = new TQPopupMenu( folderMenu );
1124 folderToPopupMenu( MoveFolder, this, &mMenuToFolder, moveMenu );
1125 folderMenu->insertItem( i18n("&Move Folder To"), moveMenu );
1126 }
1127
1128 // Want to be able to display properties for ALL folders,
1129 // so we can edit expiry properties.
1130 // -- smp.
1131 if (!fti->folder()->noContent())
1132 {
1133 if ( !multiFolder )
1134 mMainWidget->action("search_messages")->plug(folderMenu);
1135
1136 mMainWidget->action( "archive_folder" )->plug( folderMenu );
1137
1138 mMainWidget->action("compact")->plug(folderMenu);
1139
1140 if ( GlobalSettings::self()->enableFavoriteFolderView() ) {
1141 folderMenu->insertItem( SmallIconSet("bookmark_add"), i18n("Add to Favorite Folders"),
1142 this, TQ_SLOT(slotAddToFavorites()) );
1143 }
1144
1145 folderMenu->insertSeparator();
1146 mMainWidget->action("empty")->plug(folderMenu);
1147 if ( !fti->folder()->isSystemFolder() ) {
1148 mMainWidget->action("delete_folder")->plug(folderMenu);
1149 }
1150 folderMenu->insertSeparator();
1151 }
1152 }
1153
1154 /* plug in IMAP and DIMAP specific things */
1155 if (fti->folder() &&
1156 (fti->folder()->folderType() == KMFolderTypeImap ||
1157 fti->folder()->folderType() == KMFolderTypeCachedImap ))
1158 {
1159 folderMenu->insertItem(SmallIconSet("bookmark_folder"),
1160 i18n("Serverside Subscription..."), mMainWidget,
1161 TQ_SLOT(slotSubscriptionDialog()));
1162 folderMenu->insertItem(SmallIcon("bookmark_folder"),
1163 i18n("Local Subscription..."), mMainWidget,
1164 TQ_SLOT(slotLocalSubscriptionDialog()));
1165
1166 if (!fti->folder()->noContent())
1167 {
1168 mMainWidget->action("refresh_folder")->plug(folderMenu);
1169 if ( fti->folder()->folderType() == KMFolderTypeImap && !multiFolder ) {
1170 folderMenu->insertItem(SmallIconSet("reload"), i18n("Refresh Folder List"), this,
1171 TQ_SLOT(slotResetFolderList()));
1172 }
1173 }
1174 if ( fti->folder()->folderType() == KMFolderTypeCachedImap && !multiFolder ) {
1175 KMFolderCachedImap * folder = static_cast<KMFolderCachedImap*>( fti->folder()->storage() );
1176 folderMenu->insertItem( SmallIconSet("wizard"),
1177 i18n("&Troubleshoot IMAP Cache..."),
1178 folder, TQ_SLOT(slotTroubleshoot()) );
1179 }
1180 folderMenu->insertSeparator();
1181 }
1182
1183 if ( fti->folder() && fti->folder()->isMailingListEnabled() && !multiFolder ) {
1184 mMainWidget->action("post_message")->plug(folderMenu);
1185 }
1186
1187 if (fti->folder() && fti->parent() && !multiFolder)
1188 {
1189 folderMenu->insertItem(SmallIconSet("configure_shortcuts"),
1190 i18n("&Assign Shortcut..."),
1191 fti,
1192 TQ_SLOT(assignShortcut()));
1193
1194 if ( !fti->folder()->noContent() && fti->folder()->canDeleteMessages() ) {
1195 folderMenu->insertItem( i18n("Expire..."), fti,
1196 TQ_SLOT( slotShowExpiryProperties() ) );
1197 }
1198 mMainWidget->action("modify")->plug(folderMenu);
1199 }
1200
1201
1202 kmkernel->setContextMenuShown( true );
1203 folderMenu->exec (p, 0);
1204 kmkernel->setContextMenuShown( false );
1205 triggerUpdate();
1206 delete folderMenu;
1207 folderMenu = 0;
1208}
1209
1210//-----------------------------------------------------------------------------
1211void KMFolderTree::contentsMousePressEvent(TQMouseEvent * e)
1212{
1213 // KFolderTree messes around with the selection mode
1214 TDEListView::contentsMousePressEvent( e );
1215}
1216
1217// If middle button and folder holds mailing-list, create a message to that list
1218void KMFolderTree::contentsMouseReleaseEvent(TQMouseEvent* me)
1219{
1220 TQListViewItem *lvi = currentItem(); // Needed for when branches are clicked on
1221 ButtonState btn = me->button();
1222 doFolderSelected(lvi, true);
1223
1224 // get underlying folder
1225 KMFolderTreeItem* fti = dynamic_cast<KMFolderTreeItem*>(lvi);
1226
1227 if (!fti || !fti->folder()) {
1228 KFolderTree::contentsMouseReleaseEvent(me);
1229 return;
1230 }
1231
1232 // react on middle-button only
1233 if (btn != TQt::MidButton) {
1234 KFolderTree::contentsMouseReleaseEvent(me);
1235 return;
1236 }
1237
1238 if ( fti->folder()->isMailingListEnabled() ) {
1239 KMCommand *command = new KMMailingListPostCommand( this, fti->folder() );
1240 command->start();
1241 }
1242
1243 KFolderTree::contentsMouseReleaseEvent(me);
1244}
1245
1246// little static helper
1247static bool folderHasCreateRights( const KMFolder *folder )
1248{
1249 bool createRights = true; // we don't have acls for local folders yet
1250 if ( folder && folder->folderType() == KMFolderTypeImap ) {
1251 const KMFolderImap *imapFolder = static_cast<const KMFolderImap*>( folder->storage() );
1252 createRights = imapFolder->userRightsState() != KMail::ACLJobs::Ok || // hack, we should get the acls
1253 ( imapFolder->userRightsState() == KMail::ACLJobs::Ok &&
1254 ( imapFolder->userRights() & KMail::ACLJobs::Create ) );
1255 } else if ( folder && folder->folderType() == KMFolderTypeCachedImap ) {
1256 const KMFolderCachedImap *dimapFolder = static_cast<const KMFolderCachedImap*>( folder->storage() );
1257 createRights = dimapFolder->userRightsState() != KMail::ACLJobs::Ok ||
1258 ( dimapFolder->userRightsState() == KMail::ACLJobs::Ok &&
1259 ( dimapFolder->userRights() & KMail::ACLJobs::Create ) );
1260 }
1261 return createRights;
1262}
1263
1264//-----------------------------------------------------------------------------
1265// Create a subfolder.
1266// Requires creating the appropriate subdirectory and show a dialog
1267void KMFolderTree::addChildFolder( KMFolder *folder, TQWidget * parent )
1268{
1269 KMFolder *aFolder = folder;
1270 if ( !aFolder ) {
1271 KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(currentItem());
1272 if (!fti)
1273 return;
1274 aFolder = fti->folder();
1275 }
1276 if (aFolder) {
1277 if (!aFolder->createChildFolder())
1278 return;
1279 if ( !folderHasCreateRights( aFolder ) ) {
1280 const TQString message = i18n( "<qt>Cannot create folder under <b>%1</b> because of insufficient "
1281 "permissions on the server. If you think you should be able to create "
1282 "subfolders here, ask your administrator to grant you rights to do so."
1283 "</qt> " ).arg(aFolder->label());
1284 KMessageBox::error( this, message );
1285 return;
1286 }
1287 }
1288
1289 if ( parent )
1290 ( new KMail::NewFolderDialog( parent, aFolder ) )->exec();
1291 else
1292 ( new KMail::NewFolderDialog( this, aFolder ) )->show();
1293 return;
1294/*
1295 KMFolderDir *dir = &(kmkernel->folderMgr()->dir());
1296 if (aFolder)
1297 dir = aFolder->child();
1298
1299 KMFolderDialog *d =
1300 new KMFolderDialog(0, dir, this, i18n("Create Subfolder") );
1301
1302 if (d->exec()) { // fti may be deleted here
1303 TQListViewItem *qlvi = indexOfFolder( aFolder );
1304 if (qlvi) {
1305 qlvi->setOpen(true);
1306 blockSignals( true );
1307 setCurrentItem( qlvi );
1308 blockSignals( false );
1309 }
1310 }
1311 delete d;
1312 // update if added to root Folder
1313 if (!aFolder || aFolder->noContent()) {
1314 doFolderListChanged();
1315 }
1316 */
1317}
1318
1319//-----------------------------------------------------------------------------
1320// Returns whether a folder directory should be open as specified in the
1321// config file.
1322bool KMFolderTree::readIsListViewItemOpen(KMFolderTreeItem *fti)
1323{
1324 TDEConfig* config = KMKernel::config();
1325 KMFolder *folder = fti->folder();
1326 TQString name;
1327 if (folder)
1328 {
1329 name = "Folder-" + folder->idString();
1330 } else if (fti->type() == KFolderTreeItem::Root)
1331 {
1332 if (fti->protocol() == KFolderTreeItem::NONE) // local root
1333 name = "Folder_local_root";
1334 else if (fti->protocol() == KFolderTreeItem::Search)
1335 name = "Folder_search";
1336 else
1337 return false;
1338 } else {
1339 return false;
1340 }
1341 TDEConfigGroupSaver saver(config, name);
1342
1343 return config->readBoolEntry("isOpen", false);
1344}
1345
1346//-----------------------------------------------------------------------------
1347// Saves open/closed state of a folder directory into the config file
1348void KMFolderTree::writeIsListViewItemOpen(KMFolderTreeItem *fti)
1349{
1350 TDEConfig* config = KMKernel::config();
1351 KMFolder *folder = fti->folder();
1352 TQString name;
1353 if (folder && !folder->idString().isEmpty())
1354 {
1355 name = "Folder-" + folder->idString();
1356 } else if (fti->type() == KFolderTreeItem::Root)
1357 {
1358 if (fti->protocol() == KFolderTreeItem::NONE) // local root
1359 name = "Folder_local_root";
1360 else if (fti->protocol() == KFolderTreeItem::Search)
1361 name = "Folder_search";
1362 else
1363 return;
1364 } else {
1365 return;
1366 }
1367 TDEConfigGroupSaver saver(config, name);
1368 config->writeEntry("isOpen", fti->isOpen() );
1369}
1370
1371
1372//-----------------------------------------------------------------------------
1373void KMFolderTree::cleanupConfigFile()
1374{
1375 if ( childCount() == 0 )
1376 return; // just in case reload wasn't called before
1377 TDEConfig* config = KMKernel::config();
1378 TQStringList existingFolders;
1379 TQListViewItemIterator fldIt(this);
1380 TQMap<TQString,bool> folderMap;
1381 KMFolderTreeItem *fti;
1382 for (TQListViewItemIterator fldIt(this); fldIt.current(); fldIt++)
1383 {
1384 fti = static_cast<KMFolderTreeItem*>(fldIt.current());
1385 if (fti && fti->folder())
1386 folderMap.insert(fti->folder()->idString(), true);
1387 }
1388 TQStringList groupList = config->groupList();
1389 TQString name;
1390 for (TQStringList::Iterator grpIt = groupList.begin();
1391 grpIt != groupList.end(); grpIt++)
1392 {
1393 if ((*grpIt).left(7) != "Folder-") continue;
1394 name = (*grpIt).mid(7);
1395 if (folderMap.find(name) == folderMap.end())
1396 {
1397 KMFolder* folder = kmkernel->findFolderById( name );
1398 if ( folder ) {
1399 if ( kmkernel->iCalIface().hideResourceFolder( folder )
1400 || kmkernel->iCalIface().hideResourceAccountRoot( folder ) )
1401 continue; // hidden IMAP resource folder, don't delete info
1402 if ( folder->noContent() )
1403 continue; // we hide nocontent folders if they have no child folders
1404 if ( folder == kmkernel->inboxFolder() )
1405 continue; // local inbox can be hidden as well
1406 }
1407
1408 //KMessageBox::error( 0, "cleanupConfigFile: Deleting group " + *grpIt );
1409 config->deleteGroup(*grpIt, true);
1410 kdDebug(5006) << "Deleting information about folder " << name << endl;
1411 }
1412 }
1413}
1414
1415
1416//-----------------------------------------------------------------------------
1417void KMFolderTree::openFolder()
1418{
1419 autoopen_timer.stop();
1420 if ( dropItem && !dropItem->isOpen() ) {
1421 dropItem->setOpen( true );
1422 dropItem->repaint();
1423 }
1424}
1425
1426static const int autoopenTime = 750;
1427
1428//-----------------------------------------------------------------------------
1429void KMFolderTree::contentsDragEnterEvent( TQDragEnterEvent *e )
1430{
1431 oldCurrent = 0;
1432 oldSelected = 0;
1433
1434 oldCurrent = currentItem();
1435 for ( TQListViewItemIterator it( this ) ; it.current() ; ++it )
1436 if ( it.current()->isSelected() )
1437 oldSelected = it.current();
1438
1439 setFocus();
1440
1441 TQListViewItem *i = itemAt( contentsToViewport(e->pos()) );
1442 if ( i ) {
1443 dropItem = i;
1444 autoopen_timer.start( autoopenTime );
1445 }
1446 else
1447 dropItem = 0;
1448
1449 e->accept( acceptDrag(e) );
1450}
1451
1452//-----------------------------------------------------------------------------
1453void KMFolderTree::contentsDragMoveEvent( TQDragMoveEvent *e )
1454{
1455 TQPoint vp = contentsToViewport(e->pos());
1456 TQListViewItem *i = itemAt( vp );
1457 if ( i ) {
1458 bool dragAccepted = acceptDrag( e );
1459 if ( dragAccepted ) {
1460 setCurrentItem( i );
1461 }
1462
1463 if ( i != dropItem ) {
1464 autoopen_timer.stop();
1465 dropItem = i;
1466 autoopen_timer.start( autoopenTime );
1467 }
1468
1469 if ( dragAccepted ) {
1470 e->accept( itemRect(i) );
1471
1472 switch ( e->action() ) {
1473 case TQDropEvent::Copy:
1474 break;
1475 case TQDropEvent::Move:
1476 e->acceptAction();
1477 break;
1478 case TQDropEvent::Link:
1479 e->acceptAction();
1480 break;
1481 default:
1482 ;
1483 }
1484 } else {
1485 e->accept( false );
1486 }
1487 } else {
1488 e->accept( false );
1489 autoopen_timer.stop();
1490 dropItem = 0;
1491 }
1492}
1493
1494//-----------------------------------------------------------------------------
1495void KMFolderTree::contentsDragLeaveEvent( TQDragLeaveEvent * )
1496{
1497 if (!oldCurrent) return;
1498
1499 autoopen_timer.stop();
1500 dropItem = 0;
1501
1502 setCurrentItem( oldCurrent );
1503 if ( oldSelected )
1504 setSelected( oldSelected, true );
1505}
1506
1507//-----------------------------------------------------------------------------
1508void KMFolderTree::contentsDropEvent( TQDropEvent *e )
1509{
1510 autoopen_timer.stop();
1511
1512 TQListViewItem *item = itemAt( contentsToViewport(e->pos()) );
1513 KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
1514 // Check that each pointer is not null
1515 for ( TQValueList<TQGuardedPtr<KMFolder> >::ConstIterator it = mCopySourceFolders.constBegin();
1516 it != mCopySourceFolders.constEnd(); ++it ) {
1517 if ( ! (*it) ) {
1518 fti = 0;
1519 break;
1520 }
1521 }
1522 if (fti && mCopySourceFolders.count() == 1)
1523 {
1524 KMFolder *source = mCopySourceFolders.first();
1525 // if we are dragging to ourselves or to our parent, set fti to 0 so nothing is done
1526 if (source == fti->folder() || source->parent()->owner() == fti->folder()) fti = 0;
1527 }
1528 if (fti && acceptDrag(e) && ( fti != oldSelected || e->source() != mMainWidget->headers()->viewport() ) )
1529 {
1530 if ( e->provides("application/x-qlistviewitem") ) {
1531 int action = dndMode( true /* always ask */ );
1532 if ( (action == DRAG_COPY || action == DRAG_MOVE) && !mCopySourceFolders.isEmpty() ) {
1533 for ( TQValueList<TQGuardedPtr<KMFolder> >::ConstIterator it = mCopySourceFolders.constBegin();
1534 it != mCopySourceFolders.constEnd(); ++it ) {
1535 if ( ! (*it)->isMoveable() )
1536 action = DRAG_COPY;
1537 }
1538 moveOrCopyFolder( mCopySourceFolders, fti->folder(), (action == DRAG_MOVE) );
1539 }
1540 } else {
1541 if ( e->source() == mMainWidget->headers()->viewport() ) {
1542 int action;
1543 if ( mMainWidget->headers()->folder() && mMainWidget->headers()->folder()->isReadOnly() )
1544 action = DRAG_COPY;
1545 else
1546 action = dndMode();
1547 // KMHeaders does copy/move itself
1548 if ( action == DRAG_MOVE && fti->folder() )
1549 emit folderDrop( fti->folder() );
1550 else if ( action == DRAG_COPY && fti->folder() )
1551 emit folderDropCopy( fti->folder() );
1552 } else {
1553 handleMailListDrop( e, fti->folder() );
1554 }
1555 }
1556 e->accept( true );
1557 } else
1558 e->accept( false );
1559
1560 dropItem = 0;
1561
1562 setCurrentItem( oldCurrent );
1563 if ( oldCurrent) mLastItem = static_cast<KMFolderTreeItem*>(oldCurrent);
1564 if ( oldSelected )
1565 {
1566 clearSelection();
1567 setSelected( oldSelected, true );
1568 }
1569
1570 mCopySourceFolders.clear();
1571}
1572
1573//-----------------------------------------------------------------------------
1574void KMFolderTree::slotFolderExpanded( TQListViewItem * item )
1575{
1576 KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
1577 if ( !fti || !fti->folder() || !fti->folder()->storage() ) return;
1578
1579 fti->setFolderSize( fti->folder()->storage()->folderSize() );
1580
1581 if( fti->folder()->folderType() == KMFolderTypeImap )
1582 {
1583 KMFolderImap *folder = static_cast<KMFolderImap*>( fti->folder()->storage() );
1584 // if we should list all folders we limit this to the root folder
1585 if ( !folder->account() || ( !folder->account()->listOnlyOpenFolders() &&
1586 fti->parent() ) )
1587 return;
1588 if ( folder->getSubfolderState() == KMFolderImap::imapNoInformation )
1589 {
1590 // check if all parents are expanded
1591 TQListViewItem *parent = item->parent();
1592 while ( parent )
1593 {
1594 if ( !parent->isOpen() )
1595 return;
1596 parent = parent->parent();
1597 }
1598 // the tree will be reloaded after that
1599 bool success = folder->listDirectory();
1600 if (!success) fti->setOpen( false );
1601 if ( fti->childCount() == 0 && fti->parent() )
1602 fti->setExpandable( false );
1603 }
1604 }
1605}
1606
1607
1608//-----------------------------------------------------------------------------
1609void KMFolderTree::slotFolderCollapsed( TQListViewItem * item )
1610{
1611 slotResetFolderList( item, false );
1612 KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
1613 if ( !fti || !fti->folder() || !fti->folder()->storage() ) return;
1614
1615 fti->setFolderSize( fti->folder()->storage()->folderSize() );
1616}
1617
1618//-----------------------------------------------------------------------------
1619void KMFolderTree::slotRenameFolder(TQListViewItem *item, int col,
1620 const TQString &text)
1621{
1622
1623 KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item);
1624
1625 if ((!fti) || (fti && fti->folder() && col != 0 && !currentFolder()->child()))
1626 return;
1627
1628 TQString fldName, oldFldName;
1629
1630 oldFldName = fti->name(0);
1631
1632 if (!text.isEmpty())
1633 fldName = text;
1634 else
1635 fldName = oldFldName;
1636
1637 fldName.replace("/", "");
1638 fldName.replace(TQRegExp("^\\."), "");
1639
1640 if (fldName.isEmpty())
1641 fldName = i18n("unnamed");
1642
1643 fti->setText(0, fldName);
1644 fti->folder()->rename(fldName, &(kmkernel->folderMgr()->dir()));
1645}
1646
1647//-----------------------------------------------------------------------------
1648void KMFolderTree::slotUpdateCountsDelayed(KMFolder * folder)
1649{
1650// kdDebug(5006) << "KMFolderTree::slotUpdateCountsDelayed()" << endl;
1651 if ( !mFolderToUpdateCount.contains( folder->idString() ) )
1652 {
1653// kdDebug( 5006 )<< "adding " << folder->idString() << " to updateCountList " << endl;
1654 mFolderToUpdateCount.insert( folder->idString(),folder );
1655 }
1656 if ( !mUpdateCountTimer->isActive() )
1657 mUpdateCountTimer->start( 500 );
1658}
1659
1660
1661void KMFolderTree::slotUpdateCountTimeout()
1662{
1663// kdDebug(5006) << "KMFolderTree::slotUpdateCountTimeout()" << endl;
1664
1665 TQMap<TQString,KMFolder*>::iterator it;
1666 for ( it= mFolderToUpdateCount.begin();
1667 it!=mFolderToUpdateCount.end();
1668 ++it )
1669 {
1670 slotUpdateCounts( it.data() );
1671 }
1672 mFolderToUpdateCount.clear();
1673 mUpdateCountTimer->stop();
1674
1675}
1676
1677void KMFolderTree::updatePopup() const
1678{
1679 mPopup->setItemChecked( mUnreadPop, isUnreadActive() );
1680 mPopup->setItemChecked( mTotalPop, isTotalActive() );
1681 mPopup->setItemChecked( mSizePop, isSizeActive() );
1682}
1683
1684//-----------------------------------------------------------------------------
1685void KMFolderTree::toggleColumn(int column, bool openFolders)
1686{
1687 if (column == unread)
1688 {
1689 // switch unread
1690 if ( isUnreadActive() )
1691 {
1692 removeUnreadColumn();
1693 reload();
1694 } else {
1695 addUnreadColumn( i18n("Unread"), 70 );
1696 reload();
1697 }
1698 // toggle TDEPopupMenu
1699 mPopup->setItemChecked( mUnreadPop, isUnreadActive() );
1700
1701 } else if (column == total) {
1702 // switch total
1703 if ( isTotalActive() )
1704 {
1705 removeTotalColumn();
1706 reload();
1707 } else {
1708 addTotalColumn( i18n("Total"), 70 );
1709 reload(openFolders);
1710 }
1711 mPopup->setItemChecked( mTotalPop, isTotalActive() );
1712 } else if (column == foldersize) {
1713 // switch total
1714 if ( isSizeActive() )
1715 {
1716 removeSizeColumn();
1717 reload();
1718 } else {
1719 addSizeColumn( i18n("Size"), 70 );
1720 reload( openFolders );
1721 }
1722 // toggle TDEPopupMenu
1723 mPopup->setItemChecked( mSizePop, isSizeActive() );
1724
1725 } else kdDebug(5006) << "unknown column:" << column << endl;
1726
1727 // toggles the switches of the mainwin
1728 emit columnsChanged();
1729}
1730
1731//-----------------------------------------------------------------------------
1732void KMFolderTree::slotToggleUnreadColumn()
1733{
1734 toggleColumn(unread);
1735}
1736
1737//-----------------------------------------------------------------------------
1738void KMFolderTree::slotToggleTotalColumn()
1739{
1740 // activate the total-column and force the folders to be opened
1741 toggleColumn(total, true);
1742}
1743
1744//-----------------------------------------------------------------------------
1745void KMFolderTree::slotToggleSizeColumn()
1746{
1747 // activate the size-column and force the folders to be opened
1748 toggleColumn(foldersize, true);
1749}
1750
1751
1752//-----------------------------------------------------------------------------
1753bool KMFolderTree::eventFilter( TQObject *o, TQEvent *e )
1754{
1755 if ( e->type() == TQEvent::MouseButtonPress &&
1756 static_cast<TQMouseEvent*>(e)->button() == TQt::RightButton &&
1757 o->isA("TQHeader") )
1758 {
1759 mPopup->popup( static_cast<TQMouseEvent*>(e)->globalPos() );
1760 return true;
1761 }
1762 return KFolderTree::eventFilter(o, e);
1763}
1764
1765//-----------------------------------------------------------------------------
1766void KMFolderTree::slotCheckMail()
1767{
1768 if (!currentItem())
1769 return;
1770 KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(currentItem());
1771 KMFolder* folder = fti->folder();
1772 if (folder && folder->storage() ) {
1773 if ( KMAccount* acct = folder->storage()->account() ) {
1774 kmkernel->acctMgr()->singleCheckMail(acct, true);
1775 }
1776 }
1777}
1778
1779//-----------------------------------------------------------------------------
1780void KMFolderTree::slotNewMessageToMailingList()
1781{
1782 KMFolderTreeItem* fti = dynamic_cast<KMFolderTreeItem*>( currentItem() );
1783 if ( !fti || !fti->folder() )
1784 return;
1785 KMCommand *command = new KMMailingListPostCommand( this, fti->folder() );
1786 command->start();
1787}
1788
1789//-----------------------------------------------------------------------------
1790void KMFolderTree::createFolderList( TQStringList *str,
1791 TQValueList<TQGuardedPtr<KMFolder> > *folders,
1792 bool localFolders,
1793 bool imapFolders,
1794 bool dimapFolders,
1795 bool searchFolders,
1796 bool includeNoContent,
1797 bool includeNoChildren )
1798{
1799 for ( TQListViewItemIterator it( this ) ; it.current() ; ++it )
1800 {
1801 KMFolderTreeItem * fti = static_cast<KMFolderTreeItem*>(it.current());
1802 if (!fti || !fti->folder()) continue;
1803 // type checks
1804 KMFolder* folder = fti->folder();
1805 if (!imapFolders && folder->folderType() == KMFolderTypeImap) continue;
1806 if (!dimapFolders && folder->folderType() == KMFolderTypeCachedImap) continue;
1807 if (!localFolders && (folder->folderType() == KMFolderTypeMbox ||
1808 folder->folderType() == KMFolderTypeMaildir)) continue;
1809 if (!searchFolders && folder->folderType() == KMFolderTypeSearch) continue;
1810 if (!includeNoContent && folder->noContent()) continue;
1811 if (!includeNoChildren && folder->noChildren()) continue;
1812 TQString prefix;
1813 prefix.fill( ' ', 2 * fti->depth() );
1814 str->append(prefix + fti->text(0));
1815 folders->append(fti->folder());
1816 }
1817}
1818
1819//-----------------------------------------------------------------------------
1820void KMFolderTree::slotResetFolderList( TQListViewItem* item, bool startList )
1821{
1822 if ( !item )
1823 item = currentItem();
1824
1825 KMFolderTreeItem* fti = dynamic_cast<KMFolderTreeItem*>( item );
1826 if ( fti && fti->folder() &&
1827 fti->folder()->folderType() == KMFolderTypeImap )
1828 {
1829 KMFolderImap *folder = static_cast<KMFolderImap*>( fti->folder()->storage() );
1830 folder->setSubfolderState( KMFolderImap::imapNoInformation );
1831 if ( startList )
1832 folder->listDirectory();
1833 }
1834}
1835
1836//-----------------------------------------------------------------------------
1837void KMFolderTree::showFolder( KMFolder* folder )
1838{
1839 if ( !folder ) return;
1840 TQListViewItem* item = indexOfFolder( folder );
1841 if ( item )
1842 {
1843 doFolderSelected( item );
1844 ensureItemVisible( item );
1845 }
1846}
1847
1848//-----------------------------------------------------------------------------
1849void KMFolderTree::folderToPopupMenu( MenuAction action, TQObject *receiver,
1850 KMMenuToFolder *aMenuToFolder, TQPopupMenu *menu, TQListViewItem *item )
1851{
1852 while ( menu->count() )
1853 {
1854 TQPopupMenu *popup = menu->findItem( menu->idAt( 0 ) )->popup();
1855 if ( popup )
1856 delete popup;
1857 else
1858 menu->removeItemAt( 0 );
1859 }
1860 // connect the signals
1861 if ( action == MoveMessage || action == MoveFolder )
1862 {
1863 disconnect( menu, TQ_SIGNAL(activated(int)), receiver,
1864 TQ_SLOT(moveSelectedToFolder(int)) );
1865 connect( menu, TQ_SIGNAL(activated(int)), receiver,
1866 TQ_SLOT(moveSelectedToFolder(int)) );
1867 } else {
1868 disconnect( menu, TQ_SIGNAL(activated(int)), receiver,
1869 TQ_SLOT(copySelectedToFolder(int)) );
1870 connect( menu, TQ_SIGNAL(activated(int)), receiver,
1871 TQ_SLOT(copySelectedToFolder(int)) );
1872 }
1873 if ( !item ) {
1874 item = firstChild();
1875
1876 // avoid a popup menu with the single entry 'Local Folders' if there
1877 // are no IMAP accounts
1878 if ( childCount() == 2 && action != MoveFolder ) { // only 'Local Folders' and 'Searches'
1879 KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>( item );
1880 if ( fti->protocol() == KFolderTreeItem::Search ) {
1881 // skip 'Searches'
1882 item = item->nextSibling();
1883 fti = static_cast<KMFolderTreeItem*>( item );
1884 }
1885 folderToPopupMenu( action, receiver, aMenuToFolder, menu, fti->firstChild() );
1886 return;
1887 }
1888 }
1889
1890 while ( item )
1891 {
1892 KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>( item );
1893 if ( fti->protocol() == KFolderTreeItem::Search )
1894 {
1895 // skip search folders
1896 item = item->nextSibling();
1897 continue;
1898 }
1899 TQString label = fti->text( 0 );
1900 label.replace( "&","&&" );
1901 if ( fti->firstChild() )
1902 {
1903 // new level
1904 TQPopupMenu* popup = new TQPopupMenu( menu, "subMenu" );
1905 folderToPopupMenu( action, receiver, aMenuToFolder, popup, fti->firstChild() );
1906 bool subMenu = false;
1907 if ( ( action == MoveMessage || action == CopyMessage ) &&
1908 fti->folder() && !fti->folder()->noContent() )
1909 subMenu = true;
1910 if ( ( action == MoveFolder || action == CopyFolder )
1911 && ( !fti->folder() || ( fti->folder() && !fti->folder()->noChildren() ) ) )
1912 subMenu = true;
1913
1914 TQString sourceFolderName;
1915 KMFolderTreeItem* srcItem = dynamic_cast<KMFolderTreeItem*>( currentItem() );
1916 if ( srcItem )
1917 sourceFolderName = srcItem->text( 0 );
1918
1919 if ( (action == MoveFolder || action == CopyFolder)
1920 && fti->folder() && fti->folder()->child()
1921 && fti->folder()->child()->hasNamedFolder( sourceFolderName ) ) {
1922 subMenu = false;
1923 }
1924
1925 if ( subMenu )
1926 {
1927 int menuId;
1928 if ( action == MoveMessage || action == MoveFolder )
1929 menuId = popup->insertItem( i18n("Move to This Folder"), -1, 0 );
1930 else
1931 menuId = popup->insertItem( i18n("Copy to This Folder"), -1, 0 );
1932 popup->insertSeparator( 1 );
1933 aMenuToFolder->insert( menuId, fti->folder() );
1934 }
1935 menu->insertItem( label, popup );
1936 } else
1937 {
1938 // insert an item
1939 int menuId = menu->insertItem( label );
1940 if ( fti->folder() )
1941 aMenuToFolder->insert( menuId, fti->folder() );
1942 bool enabled = (fti->folder() ? true : false);
1943 if ( fti->folder() &&
1944 ( fti->folder()->isReadOnly() || fti->folder()->noContent() ) )
1945 enabled = false;
1946 menu->setItemEnabled( menuId, enabled );
1947 }
1948
1949 item = item->nextSibling();
1950 }
1951}
1952
1953//-----------------------------------------------------------------------------
1954void KMFolderTree::moveSelectedToFolder( int menuId )
1955{
1956 moveOrCopyFolder( selectedFolders(), mMenuToFolder[ menuId ], true /*move*/ );
1957}
1958
1959//-----------------------------------------------------------------------------
1960void KMFolderTree::copySelectedToFolder( int menuId )
1961{
1962 moveOrCopyFolder( selectedFolders(), mMenuToFolder[ menuId ], false /*copy, don't move*/ );
1963}
1964
1965//-----------------------------------------------------------------------------
1966void KMFolderTree::moveOrCopyFolder( TQValueList<TQGuardedPtr<KMFolder> > sources, KMFolder* destination, bool move )
1967{
1968 kdDebug(5006) << k_funcinfo << "source: " << sources << " destination: " << destination << " move: " << move << endl;
1969
1970 // Disable drag during copy operation since it prevents from many crashes
1971 setDragEnabled( false );
1972
1973 KMFolderDir* parent = &(kmkernel->folderMgr()->dir());
1974 if ( destination )
1975 parent = destination->createChildFolder();
1976
1977 TQStringList sourceFolderNames;
1978
1979 // check if move/copy is possible at all
1980 for ( TQValueList<TQGuardedPtr<KMFolder> >::ConstIterator it = sources.constBegin(); it != sources.constEnd(); ++it ) {
1981 KMFolder* source = *it;
1982
1983 // check if folder with same name already exits
1984 TQString sourceFolderName;
1985 if ( source )
1986 sourceFolderName = source->label();
1987
1988 if ( parent->hasNamedFolder( sourceFolderName ) || sourceFolderNames.contains( sourceFolderName ) ) {
1989 KMessageBox::error( this, i18n("<qt>Cannot move or copy folder <b>%1</b> here because a folder with the same name already exists.</qt>")
1990 .arg( sourceFolderName ) );
1991 setDragEnabled( true );
1992 return;
1993 }
1994 sourceFolderNames.append( sourceFolderName );
1995
1996 // don't move/copy a folder that's still not completely moved/copied
1997 KMFolder *f = source;
1998 while ( f ) {
1999 if ( f->moveInProgress() ) {
2000 KMessageBox::error( this, i18n("<qt>Cannot move or copy folder <b>%1</b> because it is not completely copied itself.</qt>")
2001 .arg( sourceFolderName ) );
2002 setDragEnabled( true );
2003 return;
2004 }
2005 if ( f->parent() )
2006 f = f->parent()->owner();
2007 }
2008
2009 TQString message =
2010 i18n( "<qt>Cannot move or copy folder <b>%1</b> into a subfolder below itself.</qt>" ).
2011 arg( sourceFolderName );
2012 KMFolderDir* folderDir = parent;
2013 // check that the folder can be moved
2014 if ( source && source->child() )
2015 {
2016 while ( folderDir && ( folderDir != &kmkernel->folderMgr()->dir() ) &&
2017 ( folderDir != source->parent() ) )
2018 {
2019 if ( folderDir->findRef( source ) != -1 )
2020 {
2021 KMessageBox::error( this, message );
2022 setDragEnabled( true );
2023 return;
2024 }
2025 folderDir = folderDir->parent();
2026 }
2027 }
2028
2029 if( source && source->child() && parent &&
2030 ( parent->path().find( source->child()->path() + "/" ) == 0 ) ) {
2031 KMessageBox::error( this, message );
2032 setDragEnabled( true );
2033 return;
2034 }
2035
2036 if( source && source->child()
2037 && ( parent == source->child() ) ) {
2038 KMessageBox::error( this, message );
2039 setDragEnabled( true );
2040 return;
2041 }
2042 }
2043
2044 // check if the source folders are independent of each other
2045 for ( TQValueList<TQGuardedPtr<KMFolder> >::ConstIterator it = sources.constBegin(); move && it != sources.constEnd(); ++it ) {
2046 KMFolderDir *parentDir = (*it)->child();
2047 if ( !parentDir )
2048 continue;
2049 for ( TQValueList<TQGuardedPtr<KMFolder> >::ConstIterator it2 = sources.constBegin(); it2 != sources.constEnd(); ++it2 ) {
2050 if ( *it == *it2 )
2051 continue;
2052 KMFolderDir *childDir = (*it2)->parent();
2053 do {
2054 if ( parentDir == childDir || parentDir->findRef( childDir->owner() ) != -1 ) {
2055 KMessageBox::error( this, i18n("Moving the selected folders is not possible") );
2056 setDragEnabled( true );
2057 return;
2058 }
2059 childDir = childDir->parent();
2060 }
2061 while ( childDir && childDir != &kmkernel->folderMgr()->dir() );
2062 }
2063 }
2064
2065 // de-select moved source folders (can cause crash due to unGetMsg() in KMHeaders)
2066 if ( move ) {
2067 doFolderSelected( indexOfFolder( destination ), false );
2068 oldCurrent = currentItem();
2069 }
2070
2071 // do the actual move/copy
2072 for ( TQValueList<TQGuardedPtr<KMFolder> >::ConstIterator it = sources.constBegin(); it != sources.constEnd(); ++it ) {
2073 KMFolder* source = *it;
2074 if ( move ) {
2075 kdDebug(5006) << "move folder " << (source ? source->label(): "Unknown") << " to "
2076 << ( destination ? destination->label() : "Local Folders" ) << endl;
2077 kmkernel->folderMgr()->moveFolder( source, parent );
2078 } else {
2079 kmkernel->folderMgr()->copyFolder( source, parent );
2080 }
2081 }
2082}
2083
2084TQDragObject * KMFolderTree::dragObject()
2085{
2086 KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>
2087 (itemAt(viewport()->mapFromGlobal(TQCursor::pos())));
2088 if ( !item || !item->parent() || !item->folder() ) // top-level items or something invalid
2089 return 0;
2090 mCopySourceFolders = selectedFolders();
2091
2092 TQDragObject *drag = KFolderTree::dragObject();
2093 if ( drag )
2094 drag->setPixmap( SmallIcon("folder") );
2095 return drag;
2096}
2097
2098void KMFolderTree::copyFolder()
2099{
2100 KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( currentItem() );
2101 if ( item ) {
2102 mCopySourceFolders = selectedFolders();
2103 mCutFolder = false;
2104 }
2105 updateCopyActions();
2106}
2107
2108void KMFolderTree::cutFolder()
2109{
2110 KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( currentItem() );
2111 if ( item ) {
2112 mCopySourceFolders = selectedFolders();
2113 mCutFolder = true;
2114 }
2115 updateCopyActions();
2116}
2117
2118void KMFolderTree::pasteFolder()
2119{
2120 KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( currentItem() );
2121 if ( !mCopySourceFolders.isEmpty() && item && !mCopySourceFolders.contains( item->folder() ) ) {
2122 moveOrCopyFolder( mCopySourceFolders, item->folder(), mCutFolder );
2123 if ( mCutFolder )
2124 mCopySourceFolders.clear();
2125 }
2126 updateCopyActions();
2127}
2128
2129void KMFolderTree::updateCopyActions()
2130{
2131 TDEAction *copy = mMainWidget->action("copy_folder");
2132 TDEAction *cut = mMainWidget->action("cut_folder");
2133 TDEAction *paste = mMainWidget->action("paste_folder");
2134 KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( currentItem() );
2135
2136 if ( !item || !item->folder() ) {
2137 copy->setEnabled( false );
2138 cut->setEnabled( false );
2139 } else {
2140 copy->setEnabled( true );
2141 cut->setEnabled( item->folder()->isMoveable() );
2142 }
2143
2144 if ( mCopySourceFolders.isEmpty() )
2145 paste->setEnabled( false );
2146 else
2147 paste->setEnabled( true );
2148}
2149
2150void KMFolderTree::slotSyncStateChanged()
2151{
2152 // Only emit the signal when a selected folder changes, otherwise the folder menu is updated
2153 // too often
2154 TQValueList< TQGuardedPtr<KMFolder> > folders = selectedFolders();
2155 TQValueList< TQGuardedPtr<KMFolder> >::const_iterator it = folders.constBegin();
2156 TQValueList< TQGuardedPtr<KMFolder> >::const_iterator end = folders.constEnd();
2157 while ( it != end ) {
2158 TQGuardedPtr<KMFolder> folder = *it;
2159 if ( folder == sender() ) {
2160 emit syncStateChanged();
2161 break;
2162 }
2163 ++it;
2164 }
2165}
2166
2167void KMFolderTree::slotAddToFavorites()
2168{
2169 KMail::FavoriteFolderView *favView = mMainWidget->favoriteFolderView();
2170 assert( favView );
2171 for ( TQListViewItemIterator it( this ); it.current(); ++it ) {
2172 if ( it.current()->isSelected() )
2173 favView->addFolder( static_cast<KMFolderTreeItem*>( it.current() ) );
2174 }
2175}
2176
2177void KMFolderTree::slotUnhideLocalInbox()
2178{
2179 disconnect( kmkernel->inboxFolder(), TQ_SIGNAL(msgAdded(KMFolder*,TQ_UINT32)),
2180 this, TQ_SLOT(slotUnhideLocalInbox()) );
2181 reload();
2182}
2183
2184void KMFolderTree::delayedReload()
2185{
2186 TQTimer::singleShot( 0, this, TQ_SLOT(reload()) );
2187}
2188
2189#include "kmfoldertree.moc"
virtual ChildrenState hasChildren() const
Returns if the folder has children, has no children or we don't know.
KMail list that manages the contents of one directory that may contain folders and/or other directori...
Definition: kmfolderdir.h:16
virtual TQString path() const
Return full pathname of this directory.
KMFolder * owner() const
Returns the folder whose children we are holding.
Definition: kmfolderdir.h:59
virtual KMFolderNode * hasNamedFolder(const TQString &name)
Returns folder with given name or zero if it does not exist.
Mail folder.
Definition: kmfolder.h:69
int countUnread()
Number of new or unread messages in this folder.
Definition: kmfolder.cpp:450
TQString idString() const
Returns a string that can be used to identify this folder.
Definition: kmfolder.cpp:705
bool moveInProgress() const
Returns true if there is currently a move or copy operation going on with this folder as target.
Definition: kmfolder.h:538
virtual TQString label() const
Returns the label of the folder for visualization.
Definition: kmfolder.cpp:581
bool noChildren() const
Returns, if the folder can't have children.
Definition: kmfolder.cpp:311
void close(const char *owner, bool force=false)
Close folder.
Definition: kmfolder.cpp:489
KMFolderDir * createChildFolder()
Create a child folder directory and associates it with this folder.
Definition: kmfolder.cpp:264
KMFolderType folderType() const
Returns the type of this folder.
Definition: kmfolder.cpp:233
int open(const char *owner)
Open folder for access.
Definition: kmfolder.cpp:479
bool noContent() const
Returns, if the folder can't contain mails, but only subfolder.
Definition: kmfolder.cpp:301
KMFolderDir * child() const
Returns the folder directory associated with this node or 0 if no such directory exists.
Definition: kmfolder.h:157
The account manager is responsible for creating accounts of various types via the factory method crea...
Helper class to copy/move a set of messages defined by their serial numbers from arbitrary folders in...
@ Ok
The user rights/ACL have been fetched from the server sucessfully.
Definition: acljobs.h:66
folderdiaquotatab.h
Definition: aboutdata.cpp:40