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 <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 
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 = "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 
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  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 
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() ), TQ_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 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
421 void 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 //-----------------------------------------------------------------------------
481 void 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
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, 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 //-----------------------------------------------------------------------------
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, 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
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(), 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
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  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
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  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 //-----------------------------------------------------------------------------
1211 void 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
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 != 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
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  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
1348 void 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 //-----------------------------------------------------------------------------
1373 void 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 //-----------------------------------------------------------------------------
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 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 //-----------------------------------------------------------------------------
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  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 //-----------------------------------------------------------------------------
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, 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 //-----------------------------------------------------------------------------
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  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 
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(), TQ_SIGNAL(msgAdded(KMFolder*,TQ_UINT32)),
2180  this, TQ_SLOT(slotUnhideLocalInbox()) );
2181  reload();
2182 }
2183 
2184 void 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.
virtual KMFolderNode * hasNamedFolder(const TQString &name)
Returns folder with given name or zero if it does not exist.
KMFolder * owner() const
Returns the folder whose children we are holding.
Definition: kmfolderdir.h:59
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
KMFolderDir * child() const
Returns the folder directory associated with this node or 0 if no such directory exists.
Definition: kmfolder.h:157
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
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