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"
28 using KMail::FolderViewToolTip;
29 
30 #include <maillistdrag.h>
31 using namespace KPIM;
32 
33 #include <kapplication.h>
34 #include <kglobalsettings.h>
35 #include <kiconloader.h>
36 #include <kmessagebox.h>
37 #include <kconfig.h>
38 #include <kpopupmenu.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 
54 KMFolderTreeItem::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 //-----------------------------------------------------------------------------
65 KMFolderTreeItem::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 //-----------------------------------------------------------------------------
76 KMFolderTreeItem::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 
86 KMFolderTreeItem::~KMFolderTreeItem()
87 {
88 }
89 
90 static 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 
106 TQPixmap 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 = "filenew"; 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  KIconLoader * il = KGlobal::instance()->iconLoader();
153  TQPixmap pm = il->loadIcon( icon, KIcon::Small, size,
154  KIcon::DefaultState, 0, true );
155  if ( mFolder && pm.isNull() ) {
156  pm = il->loadIcon( mFolder->normalIconPath(), KIcon::Small, size,
157  KIcon::DefaultState, 0, true );
158  }
159 
160  return pm;
161 }
162 
163 TQPixmap 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  KIconLoader * il = KGlobal::instance()->iconLoader();
174  if ( mFolder && mFolder->useCustomIcons() ) {
175  pm = il->loadIcon( mFolder->unreadIconPath(), KIcon::Small, size,
176  KIcon::DefaultState, 0, true );
177  if ( pm.isNull() )
178  pm = il->loadIcon( mFolder->normalIconPath(), KIcon::Small, size,
179  KIcon::DefaultState, 0, true );
180  }
181  if ( pm.isNull() ) {
182  if ( mFolder && mFolder->noContent() ) {
183  pm = il->loadIcon( "folder_grey_open", KIcon::Small, size,
184  KIcon::DefaultState, 0, true );
185  } else {
186  if( kmkernel->iCalIface().isResourceFolder( mFolder ) )
187  pm = il->loadIcon( kmkernel->iCalIface().folderPixmap( type() ),
188  KIcon::Small, size, KIcon::DefaultState, 0, true );
189  if ( pm.isNull() )
190  pm = il->loadIcon( "folder_open", KIcon::Small, size,
191  KIcon::DefaultState, 0, true );
192  }
193  }
194 
195  return pm;
196 }
197 
198 void 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 
240 void 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 
251 void 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 
273 void KMFolderTreeItem::slotNameChanged()
274 {
275  setText( 0, mFolder->label() );
276  emit nameChanged( this );
277  repaint();
278 }
279 
280 void 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() ), TQT_SLOT(reload()) );
285 }
286 
287 //-----------------------------------------------------------------------------
288 bool 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 //-----------------------------------------------------------------------------
322 void 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 //-----------------------------------------------------------------------------
335 void 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 //-----------------------------------------------------------------------------
346 void 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 //-----------------------------------------------------------------------------
360 void 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 
376 KMFolderTree::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 KPopupMenu(this);
407  mPopup->insertTitle(i18n("View Columns"));
408  mPopup->setCheckable(true);
409  mUnreadPop = mPopup->insertItem(i18n("Unread Column"), this, TQT_SLOT(slotToggleUnreadColumn()));
410  mTotalPop = mPopup->insertItem(i18n("Total Column"), this, TQT_SLOT(slotToggleTotalColumn()));
411  mSizePop = mPopup->insertItem(i18n("Size Column"), this, TQT_SLOT(slotToggleSizeColumn()));
412 
413  connect( this, TQT_SIGNAL( triggerRefresh() ),
414  this, TQT_SLOT( refresh() ) );
415 
416  new FolderViewToolTip( this );
417 }
418 
419 //-----------------------------------------------------------------------------
420 // connects all needed signals to their slots
421 void KMFolderTree::connectSignals()
422 {
423  connect( mUpdateCountTimer, TQT_SIGNAL(timeout()),
424  this, TQT_SLOT(slotUpdateCountTimeout()) );
425 
426  connect(&mUpdateTimer, TQT_SIGNAL(timeout()),
427  this, TQT_SLOT(delayedUpdate()));
428 
429  connect(kmkernel->folderMgr(), TQT_SIGNAL(changed()),
430  this, TQT_SLOT(doFolderListChanged()));
431 
432  connect(kmkernel->folderMgr(), TQT_SIGNAL(folderRemoved(KMFolder*)),
433  this, TQT_SLOT(slotFolderRemoved(KMFolder*)));
434 
435  connect(kmkernel->folderMgr(), TQT_SIGNAL(folderMoveOrCopyOperationFinished()),
436  this, TQT_SLOT(slotFolderMoveOrCopyOperationFinished()));
437 
438  connect(kmkernel->imapFolderMgr(), TQT_SIGNAL(changed()),
439  this, TQT_SLOT(doFolderListChanged()));
440 
441  connect(kmkernel->imapFolderMgr(), TQT_SIGNAL(folderRemoved(KMFolder*)),
442  this, TQT_SLOT(slotFolderRemoved(KMFolder*)));
443 
444  connect(kmkernel->dimapFolderMgr(), TQT_SIGNAL(changed()),
445  this, TQT_SLOT(doFolderListChanged()));
446 
447  connect(kmkernel->dimapFolderMgr(), TQT_SIGNAL(folderRemoved(KMFolder*)),
448  this, TQT_SLOT(slotFolderRemoved(KMFolder*)));
449 
450  connect(kmkernel->searchFolderMgr(), TQT_SIGNAL(changed()),
451  this, TQT_SLOT(doFolderListChanged()));
452 
453  connect(kmkernel->acctMgr(), TQT_SIGNAL(accountRemoved(KMAccount*)),
454  this, TQT_SLOT(slotAccountRemoved(KMAccount*)));
455 
456  connect(kmkernel->acctMgr(), TQT_SIGNAL(accountAdded(KMAccount*)),
457  this, TQT_SLOT(slotUnhideLocalInbox()));
458 
459  connect(kmkernel->searchFolderMgr(), TQT_SIGNAL(folderRemoved(KMFolder*)),
460  this, TQT_SLOT(slotFolderRemoved(KMFolder*)));
461 
462  connect( &autoopen_timer, TQT_SIGNAL( timeout() ),
463  this, TQT_SLOT( openFolder() ) );
464 
465  connect( this, TQT_SIGNAL( contextMenuRequested( TQListViewItem*, const TQPoint &, int ) ),
466  this, TQT_SLOT( slotContextMenuRequested( TQListViewItem*, const TQPoint & ) ) );
467 
468  connect( this, TQT_SIGNAL( expanded( TQListViewItem* ) ),
469  this, TQT_SLOT( slotFolderExpanded( TQListViewItem* ) ) );
470 
471  connect( this, TQT_SIGNAL( collapsed( TQListViewItem* ) ),
472  this, TQT_SLOT( slotFolderCollapsed( TQListViewItem* ) ) );
473 
474  connect( this, TQT_SIGNAL( itemRenamed( TQListViewItem*, int, const TQString &)),
475  this, TQT_SLOT( slotRenameFolder( TQListViewItem*, int, const TQString &)));
476 
477  connect( this, TQT_SIGNAL(folderSelected(KMFolder*)), TQT_SLOT(updateCopyActions()) );
478 }
479 
480 //-----------------------------------------------------------------------------
481 void KMFolderTree::readConfig (void)
482 {
483  KConfig* conf = KMKernel::config();
484 
485  readColorConfig();
486 
487  // Custom/Ssystem font support
488  {
489  KConfigGroupSaver saver(conf, "Fonts");
490  if (!conf->readBoolEntry("defaultFonts",true)) {
491  TQFont folderFont( KGlobalSettings::generalFont() );
492  setFont(conf->readFontEntry("folder-font", &folderFont));
493  }
494  else
495  setFont(KGlobalSettings::generalFont());
496  }
497 
498  // restore the layout
499  restoreLayout(conf, "Geometry");
500 }
501 
502 //-----------------------------------------------------------------------------
503 // Save the configuration file
504 void 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)
520 void 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
548 void 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, TQT_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(),TQT_SIGNAL(iconsChanged()),
610  fti,TQT_SLOT(slotIconsChanged()));
611  connect(fti->folder(),TQT_SIGNAL(iconsChanged()),
612  fti,TQT_SLOT(slotIconsChanged()));
613 
614  disconnect(fti->folder(),TQT_SIGNAL(nameChanged()),
615  fti,TQT_SLOT(slotNameChanged()));
616  connect(fti->folder(),TQT_SIGNAL(nameChanged()),
617  fti,TQT_SLOT(slotNameChanged()));
618 
619  disconnect( fti->folder(), TQT_SIGNAL(noContentChanged()),
620  fti, TQT_SLOT(slotNoContentChanged()) );
621  connect( fti->folder(), TQT_SIGNAL(noContentChanged()),
622  fti, TQT_SLOT(slotNoContentChanged()) );
623 
624  disconnect( fti->folder(), TQT_SIGNAL(syncStateChanged()),
625  this, TQT_SLOT(slotSyncStateChanged()) );
626  connect( fti->folder(), TQT_SIGNAL(syncStateChanged()),
627  this, TQT_SLOT(slotSyncStateChanged()) );
628 
629  // we want to be noticed of changes to update the unread/total columns
630  disconnect(fti->folder(), TQT_SIGNAL(msgAdded(KMFolder*,TQ_UINT32)),
631  this,TQT_SLOT(slotUpdateCountsDelayed(KMFolder*)));
632  connect(fti->folder(), TQT_SIGNAL(msgAdded(KMFolder*,TQ_UINT32)),
633  this,TQT_SLOT(slotUpdateCountsDelayed(KMFolder*)));
634  //}
635 
636  disconnect(fti->folder(), TQT_SIGNAL(numUnreadMsgsChanged(KMFolder*)),
637  this,TQT_SLOT(slotUpdateCountsDelayed(KMFolder*)));
638  connect(fti->folder(), TQT_SIGNAL(numUnreadMsgsChanged(KMFolder*)),
639  this,TQT_SLOT(slotUpdateCountsDelayed(KMFolder*)));
640  disconnect(fti->folder(), TQT_SIGNAL(msgRemoved(KMFolder*)),
641  this,TQT_SLOT(slotUpdateCountsDelayed(KMFolder*)));
642  connect(fti->folder(), TQT_SIGNAL(msgRemoved(KMFolder*)),
643  this,TQT_SLOT(slotUpdateCountsDelayed(KMFolder*)));
644 
645  disconnect(fti->folder(), TQT_SIGNAL(folderSizeChanged( KMFolder* )),
646  this,TQT_SLOT(slotUpdateCountsDelayed(KMFolder*)));
647  connect(fti->folder(), TQT_SIGNAL(folderSizeChanged( KMFolder* )),
648  this,TQT_SLOT(slotUpdateCountsDelayed(KMFolder*)));
649 
650 
651 
652  disconnect(fti->folder(), TQT_SIGNAL(shortcutChanged(KMFolder*)),
653  mMainWidget, TQT_SLOT( slotShortcutChanged(KMFolder*)));
654  connect(fti->folder(), TQT_SIGNAL(shortcutChanged(KMFolder*)),
655  mMainWidget, TQT_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 //-----------------------------------------------------------------------------
692 void 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, TQT_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, TQT_SLOT(slotUpdateOneCount()) );
711 }
712 
713 //-----------------------------------------------------------------------------
714 // Recursively add a directory of folders to the tree of folders
715 void 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(), TQT_SIGNAL(msgAdded(KMFolder*,TQ_UINT32)), TQT_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, TQT_SIGNAL(noContentChanged()), TQT_SLOT(delayedReload()) );
769  continue;
770  }
771 
772  connect (fti, TQT_SIGNAL(iconChanged(KMFolderTreeItem*)),
773  this, TQT_SIGNAL(iconChanged(KMFolderTreeItem*)));
774  connect (fti, TQT_SIGNAL(nameChanged(KMFolderTreeItem*)),
775  this, TQT_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
784 void KMFolderTree::refresh()
785 {
786  mUpdateTimer.changeInterval(200);
787 }
788 
789 //-----------------------------------------------------------------------------
790 // Updates the pixmap and extendedLabel information for items
791 void 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
814 void KMFolderTree::doFolderListChanged()
815 {
816  reload();
817 }
818 
819 //-----------------------------------------------------------------------------
820 void KMFolderTree::slotAccountRemoved(KMAccount *)
821 {
822  doFolderSelected( firstChild() );
823 }
824 
825 //-----------------------------------------------------------------------------
826 void KMFolderTree::slotFolderMoveOrCopyOperationFinished()
827 {
828  setDragEnabled( true );
829 }
830 //-----------------------------------------------------------------------------
831 void 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
859 void 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 //-----------------------------------------------------------------------------
867 void KMFolderTree::nextUnreadFolder()
868 {
869  nextUnreadFolder( false );
870 }
871 
872 //-----------------------------------------------------------------------------
873 void 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 //-----------------------------------------------------------------------------
896 bool 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 //-----------------------------------------------------------------------------
939 void 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 //-----------------------------------------------------------------------------
951 void 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 //-----------------------------------------------------------------------------
964 void 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 //-----------------------------------------------------------------------------
977 void KMFolderTree::selectCurrentFolder()
978 {
979  KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>( currentItem() );
980  if (fti) {
981  prepareItem( fti );
982  doFolderSelected( fti );
983  }
984 }
985 
986 //-----------------------------------------------------------------------------
987 KMFolder *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 
996 TQValueList<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.
1012 void 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 //-----------------------------------------------------------------------------
1046 void KMFolderTree::resizeEvent(TQResizeEvent* e)
1047 {
1048  KConfig* conf = KMKernel::config();
1049 
1050  KConfigGroupSaver saver(conf, "Geometry");
1051  conf->writeEntry(name(), size().width());
1052 
1053  KListView::resizeEvent(e);
1054 }
1055 
1056 //-----------------------------------------------------------------------------
1057 // show context menu
1058 void 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  KPopupMenu *folderMenu = new KPopupMenu;
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  TQT_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  TQT_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  TQT_SLOT(addChildFolder()));
1114  }
1115 
1116  // copy folder
1117  TQPopupMenu *copyMenu = new TQPopupMenu( folderMenu );
1118  folderToPopupMenu( CopyFolder, TQT_TQOBJECT(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, TQT_TQOBJECT(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, TQT_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  TQT_SLOT(slotSubscriptionDialog()));
1162  folderMenu->insertItem(SmallIcon("bookmark_folder"),
1163  i18n("Local Subscription..."), mMainWidget,
1164  TQT_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  TQT_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, TQT_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  TQT_SLOT(assignShortcut()));
1193 
1194  if ( !fti->folder()->noContent() && fti->folder()->canDeleteMessages() ) {
1195  folderMenu->insertItem( i18n("Expire..."), fti,
1196  TQT_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 //-----------------------------------------------------------------------------
1211 void KMFolderTree::contentsMousePressEvent(TQMouseEvent * e)
1212 {
1213  // KFolderTree messes around with the selection mode
1214  KListView::contentsMousePressEvent( e );
1215 }
1216 
1217 // If middle button and folder holds mailing-list, create a message to that list
1218 void 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 != Qt::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
1247 static 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
1267 void 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.
1322 bool KMFolderTree::readIsListViewItemOpen(KMFolderTreeItem *fti)
1323 {
1324  KConfig* 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  KConfigGroupSaver 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
1348 void KMFolderTree::writeIsListViewItemOpen(KMFolderTreeItem *fti)
1349 {
1350  KConfig* 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  KConfigGroupSaver saver(config, name);
1368  config->writeEntry("isOpen", fti->isOpen() );
1369 }
1370 
1371 
1372 //-----------------------------------------------------------------------------
1373 void KMFolderTree::cleanupConfigFile()
1374 {
1375  if ( childCount() == 0 )
1376  return; // just in case reload wasn't called before
1377  KConfig* 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 //-----------------------------------------------------------------------------
1417 void KMFolderTree::openFolder()
1418 {
1419  autoopen_timer.stop();
1420  if ( dropItem && !dropItem->isOpen() ) {
1421  dropItem->setOpen( true );
1422  dropItem->repaint();
1423  }
1424 }
1425 
1426 static const int autoopenTime = 750;
1427 
1428 //-----------------------------------------------------------------------------
1429 void 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 //-----------------------------------------------------------------------------
1453 void 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 //-----------------------------------------------------------------------------
1495 void 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 //-----------------------------------------------------------------------------
1508 void 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 //-----------------------------------------------------------------------------
1574 void 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 //-----------------------------------------------------------------------------
1609 void 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 //-----------------------------------------------------------------------------
1619 void 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 //-----------------------------------------------------------------------------
1648 void 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 
1661 void 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 
1677 void KMFolderTree::updatePopup() const
1678 {
1679  mPopup->setItemChecked( mUnreadPop, isUnreadActive() );
1680  mPopup->setItemChecked( mTotalPop, isTotalActive() );
1681  mPopup->setItemChecked( mSizePop, isSizeActive() );
1682 }
1683 
1684 //-----------------------------------------------------------------------------
1685 void 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 KPopupMenu
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 KPopupMenu
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 //-----------------------------------------------------------------------------
1732 void KMFolderTree::slotToggleUnreadColumn()
1733 {
1734  toggleColumn(unread);
1735 }
1736 
1737 //-----------------------------------------------------------------------------
1738 void KMFolderTree::slotToggleTotalColumn()
1739 {
1740  // activate the total-column and force the folders to be opened
1741  toggleColumn(total, true);
1742 }
1743 
1744 //-----------------------------------------------------------------------------
1745 void KMFolderTree::slotToggleSizeColumn()
1746 {
1747  // activate the size-column and force the folders to be opened
1748  toggleColumn(foldersize, true);
1749 }
1750 
1751 
1752 //-----------------------------------------------------------------------------
1753 bool KMFolderTree::eventFilter( TQObject *o, TQEvent *e )
1754 {
1755  if ( e->type() == TQEvent::MouseButtonPress &&
1756  TQT_TQMOUSEEVENT(e)->button() == Qt::RightButton &&
1757  o->isA(TQHEADER_OBJECT_NAME_STRING) )
1758  {
1759  mPopup->popup( TQT_TQMOUSEEVENT(e)->globalPos() );
1760  return true;
1761  }
1762  return KFolderTree::eventFilter(o, e);
1763 }
1764 
1765 //-----------------------------------------------------------------------------
1766 void 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 //-----------------------------------------------------------------------------
1780 void 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 //-----------------------------------------------------------------------------
1790 void 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 //-----------------------------------------------------------------------------
1820 void 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 //-----------------------------------------------------------------------------
1837 void 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 //-----------------------------------------------------------------------------
1849 void 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, TQT_SIGNAL(activated(int)), receiver,
1864  TQT_SLOT(moveSelectedToFolder(int)) );
1865  connect( menu, TQT_SIGNAL(activated(int)), receiver,
1866  TQT_SLOT(moveSelectedToFolder(int)) );
1867  } else {
1868  disconnect( menu, TQT_SIGNAL(activated(int)), receiver,
1869  TQT_SLOT(copySelectedToFolder(int)) );
1870  connect( menu, TQT_SIGNAL(activated(int)), receiver,
1871  TQT_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 //-----------------------------------------------------------------------------
1954 void KMFolderTree::moveSelectedToFolder( int menuId )
1955 {
1956  moveOrCopyFolder( selectedFolders(), mMenuToFolder[ menuId ], true /*move*/ );
1957 }
1958 
1959 //-----------------------------------------------------------------------------
1960 void KMFolderTree::copySelectedToFolder( int menuId )
1961 {
1962  moveOrCopyFolder( selectedFolders(), mMenuToFolder[ menuId ], false /*copy, don't move*/ );
1963 }
1964 
1965 //-----------------------------------------------------------------------------
1966 void 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 
2084 TQDragObject * 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 
2098 void KMFolderTree::copyFolder()
2099 {
2100  KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( currentItem() );
2101  if ( item ) {
2102  mCopySourceFolders = selectedFolders();
2103  mCutFolder = false;
2104  }
2105  updateCopyActions();
2106 }
2107 
2108 void KMFolderTree::cutFolder()
2109 {
2110  KMFolderTreeItem *item = static_cast<KMFolderTreeItem*>( currentItem() );
2111  if ( item ) {
2112  mCopySourceFolders = selectedFolders();
2113  mCutFolder = true;
2114  }
2115  updateCopyActions();
2116 }
2117 
2118 void 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 
2129 void KMFolderTree::updateCopyActions()
2130 {
2131  KAction *copy = mMainWidget->action("copy_folder");
2132  KAction *cut = mMainWidget->action("cut_folder");
2133  KAction *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 
2150 void 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 
2167 void 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 
2177 void KMFolderTree::slotUnhideLocalInbox()
2178 {
2179  disconnect( kmkernel->inboxFolder(), TQT_SIGNAL(msgAdded(KMFolder*,TQ_UINT32)),
2180  this, TQT_SLOT(slotUnhideLocalInbox()) );
2181  reload();
2182 }
2183 
2184 void KMFolderTree::delayedReload()
2185 {
2186  TQTimer::singleShot( 0, this, TQT_SLOT(reload()) );
2187 }
2188 
2189 #include "kmfoldertree.moc"