libtdepim

ksubscription.cpp
1 /*
2  ksubscription.cpp
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8  You should have received a copy of the GNU General Public License
9  along with this program; if not, write to the Free Software Foundation,
10  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
11 */
12 
13 #include "ksubscription.h"
14 #include "kaccount.h"
15 
16 #include <tqlayout.h>
17 #include <tqtimer.h>
18 #include <tqlabel.h>
19 #include <tqpushbutton.h>
20 #include <tqheader.h>
21 #include <tqtoolbutton.h>
22 
23 #include <kseparator.h>
24 #include <tdeapplication.h>
25 #include <kiconloader.h>
26 #include <tdelocale.h>
27 #include <kdebug.h>
28 #include <klineedit.h>
29 
30 
31 //=============================================================================
32 
33 KGroupInfo::KGroupInfo(const TQString &name, const TQString &description,
34  bool newGroup, bool subscribed,
35  Status status, TQString path)
36  : name(name), description(description),
37  newGroup(newGroup), subscribed(subscribed),
38  status(status), path(path)
39 {
40 }
41 
42 //-----------------------------------------------------------------------------
43 bool KGroupInfo::operator== (const KGroupInfo &gi2)
44 {
45  return (name == gi2.name);
46 }
47 
48 //-----------------------------------------------------------------------------
49 bool KGroupInfo::operator< (const KGroupInfo &gi2)
50 {
51  return (name < gi2.name);
52 }
53 
54 //=============================================================================
55 
56 GroupItem::GroupItem( TQListView *v, const KGroupInfo &gi, KSubscription* browser,
57  bool isCheckItem )
58  : TQCheckListItem( v, gi.name, isCheckItem ? CheckBox : CheckBoxController ),
59  mInfo( gi ), mBrowser( browser ), mIsCheckItem( isCheckItem ),
60  mIgnoreStateChange( false )
61 {
62  if (listView()->columns() > 1)
63  setDescription();
64 }
65 
66 //-----------------------------------------------------------------------------
67 GroupItem::GroupItem( TQListViewItem *i, const KGroupInfo &gi, KSubscription* browser,
68  bool isCheckItem )
69  : TQCheckListItem( i, gi.name, isCheckItem ? CheckBox : CheckBoxController ),
70  mInfo( gi ), mBrowser( browser ), mIsCheckItem( isCheckItem ),
71  mIgnoreStateChange( false )
72 {
73  if (listView()->columns() > 1)
74  setDescription();
75 }
76 
77 //-----------------------------------------------------------------------------
78 void GroupItem::setInfo( KGroupInfo info )
79 {
80  mInfo = info;
81  setText(0, mInfo.name);
82  if (listView()->columns() > 1)
84 }
85 
86 //-----------------------------------------------------------------------------
88 {
89  setText(1, mInfo.description);
90 }
91 
92 //-----------------------------------------------------------------------------
93 void GroupItem::setOn( bool on )
94 {
95  if (mBrowser->isLoading())
96  {
97  // set this only if we're loading/creating items
98  // otherwise changes are only permanent when the dialog is saved
99  mInfo.subscribed = on;
100  }
101  if (isCheckItem())
102  TQCheckListItem::setOn(on);
103 }
104 
105 //------------------------------------------------------------------------------
106 void GroupItem::stateChange( bool on )
107 {
108  // delegate to parent
109  if ( !mIgnoreStateChange )
110  mBrowser->changeItemState(this, on);
111 }
112 
113 //------------------------------------------------------------------------------
114 void GroupItem::setVisible( bool b )
115 {
116  if (b)
117  {
119  setEnabled(true);
120  }
121  else
122  {
123  if (isCheckItem())
124  {
125  bool setInvisible = true;
126  for (TQListViewItem * lvchild = firstChild(); lvchild != 0;
127  lvchild = lvchild->nextSibling())
128  {
129  if (lvchild->isVisible()) // item has a visible child
130  setInvisible = false;
131  }
132  if (setInvisible)
134  else
135  {
136  // leave it visible so that children remain visible
137  setOpen(true);
138  setEnabled(false);
139  }
140  }
141  else
142  {
143  // non-checkable item
144  TQPtrList<TQListViewItem> moveItems;
145 
146  for (TQListViewItem * lvchild = firstChild(); lvchild != 0;
147  lvchild = lvchild->nextSibling())
148  {
149  if (static_cast<GroupItem*>(lvchild)->isCheckItem())
150  {
151  // remember the items
152  moveItems.append(lvchild);
153  }
154  }
155  TQPtrListIterator<TQListViewItem> it( moveItems );
156  for ( ; it.current(); ++it)
157  {
158  // move the checkitem to top
159  TQListViewItem* parent = it.current()->parent();
160  if (parent) parent->takeItem(it.current());
161  listView()->insertItem(it.current());
162  }
164  }
165  }
166 }
167 
168 //-----------------------------------------------------------------------------
169 void GroupItem::paintCell( TQPainter * p, const TQColorGroup & cg,
170  int column, int width, int align )
171 {
172  if (mIsCheckItem)
173  return TQCheckListItem::paintCell( p, cg, column, width, align );
174  else
175  return TQListViewItem::paintCell( p, cg, column, width, align );
176 }
177 
178 //-----------------------------------------------------------------------------
179 void GroupItem::paintFocus( TQPainter * p, const TQColorGroup & cg,
180  const TQRect & r )
181 {
182  if (mIsCheckItem)
183  TQCheckListItem::paintFocus(p, cg, r);
184  else
185  TQListViewItem::paintFocus(p, cg, r);
186 }
187 
188 //-----------------------------------------------------------------------------
189 int GroupItem::width( const TQFontMetrics& fm, const TQListView* lv, int column) const
190 {
191  if (mIsCheckItem)
192  return TQCheckListItem::width(fm, lv, column);
193  else
194  return TQListViewItem::width(fm, lv, column);
195 }
196 
197 //-----------------------------------------------------------------------------
199 {
200  if (mIsCheckItem)
202  else
204 }
205 
206 
207 //=============================================================================
208 
209 KSubscription::KSubscription( TQWidget *parent, const TQString &caption,
210  KAccount * acct, int buttons, const TQString &user1, bool descriptionColumn )
211  : KDialogBase( parent, 0, true, caption, buttons | Help | Ok | Cancel, Ok,
212  true, i18n("Reload &List"), user1 ),
213  mAcct( acct )
214 {
215  mLoading = true;
216  setWFlags( getWFlags() | WDestructiveClose );
217 
218  // create Widgets
219  page = new TQWidget(this);
220  setMainWidget(page);
221 
222  TQLabel *comment = new TQLabel("<p>"+
223  i18n("Manage which mail folders you want to see in your folder view") + "</p>", page);
224 
225  TQToolButton *clearButton = new TQToolButton( page );
226  clearButton->setIconSet( TDEGlobal::iconLoader()->loadIconSet(
227  TDEApplication::reverseLayout() ? "clear_left":"locationbar_erase", TDEIcon::Small, 0 ) );
228  filterEdit = new KLineEdit(page);
229  TQLabel *l = new TQLabel(filterEdit,i18n("S&earch:"), page);
230  connect( clearButton, TQT_SIGNAL( clicked() ), filterEdit, TQT_SLOT( clear() ) );
231 
232  // checkboxes
233  noTreeCB = new TQCheckBox(i18n("Disable &tree view"), page);
234  noTreeCB->setChecked(false);
235  subCB = new TQCheckBox(i18n("&Subscribed only"), page);
236  subCB->setChecked(false);
237  newCB = new TQCheckBox(i18n("&New only"), page);
238  newCB->setChecked(false);
239 
240 
241  KSeparator *sep = new KSeparator(KSeparator::HLine, page);
242 
243  // init the labels
244  TQFont fnt = font();
245  fnt.setBold(true);
246  leftLabel = new TQLabel(i18n("Loading..."), page);
247  rightLabel = new TQLabel(i18n("Current changes:"), page);
248  leftLabel->setFont(fnt);
249  rightLabel->setFont(fnt);
250 
251  // icons
252  pmRight = BarIconSet("forward");
253  pmLeft = BarIconSet("back");
254 
255  arrowBtn1 = new TQPushButton(page);
256  arrowBtn1->setEnabled(false);
257  arrowBtn2 = new TQPushButton(page);
258  arrowBtn2->setEnabled(false);
259  arrowBtn1->setIconSet(pmRight);
260  arrowBtn2->setIconSet(pmRight);
261  arrowBtn1->setFixedSize(35,30);
262  arrowBtn2->setFixedSize(35,30);
263 
264  // the main listview
265  groupView = new TQListView(page);
266  groupView->setRootIsDecorated(true);
267  groupView->addColumn(i18n("Name"));
268  groupView->setAllColumnsShowFocus(true);
269  if (descriptionColumn)
270  mDescrColumn = groupView->addColumn(i18n("Description"));
271  else
272  groupView->header()->setStretchEnabled(true, 0);
273 
274  // layout
275  TQGridLayout *topL = new TQGridLayout(page,4,1,0, KDialog::spacingHint());
276  TQHBoxLayout *filterL = new TQHBoxLayout(KDialog::spacingHint());
277  TQVBoxLayout *arrL = new TQVBoxLayout(KDialog::spacingHint());
278  listL = new TQGridLayout(2, 3, KDialog::spacingHint());
279 
280  topL->addWidget(comment, 0,0);
281  topL->addLayout(filterL, 1,0);
282  topL->addWidget(sep,2,0);
283  topL->addLayout(listL, 3,0);
284 
285  filterL->addWidget(clearButton);
286  filterL->addWidget(l);
287  filterL->addWidget(filterEdit, 1);
288  filterL->addWidget(noTreeCB);
289  filterL->addWidget(subCB);
290  filterL->addWidget(newCB);
291 
292  listL->addWidget(leftLabel, 0,0);
293  listL->addWidget(rightLabel, 0,2);
294  listL->addWidget(groupView, 1,0);
295  listL->addLayout(arrL, 1,1);
296  listL->setRowStretch(1,1);
297  listL->setColStretch(0,5);
298  listL->setColStretch(2,2);
299 
300  arrL->addWidget(arrowBtn1, AlignCenter);
301  arrL->addWidget(arrowBtn2, AlignCenter);
302 
303  // listviews
304  subView = new TQListView(page);
305  subView->addColumn(i18n("Subscribe To"));
306  subView->header()->setStretchEnabled(true, 0);
307  unsubView = new TQListView(page);
308  unsubView->addColumn(i18n("Unsubscribe From"));
309  unsubView->header()->setStretchEnabled(true, 0);
310 
311  TQVBoxLayout *protL = new TQVBoxLayout(3);
312  listL->addLayout(protL, 1,2);
313  protL->addWidget(subView);
314  protL->addWidget(unsubView);
315 
316  // disable some widgets as long we're loading
317  enableButton(User1, false);
318  enableButton(User2, false);
319  newCB->setEnabled(false);
320  noTreeCB->setEnabled(false);
321  subCB->setEnabled(false);
322 
323  filterEdit->setFocus();
324 
325  // items clicked
326  connect(groupView, TQT_SIGNAL(clicked(TQListViewItem *)),
327  this, TQT_SLOT(slotChangeButtonState(TQListViewItem*)));
328  connect(subView, TQT_SIGNAL(clicked(TQListViewItem *)),
329  this, TQT_SLOT(slotChangeButtonState(TQListViewItem*)));
330  connect(unsubView, TQT_SIGNAL(clicked(TQListViewItem *)),
331  this, TQT_SLOT(slotChangeButtonState(TQListViewItem*)));
332 
333  // connect buttons
334  connect(arrowBtn1, TQT_SIGNAL(clicked()), TQT_SLOT(slotButton1()));
335  connect(arrowBtn2, TQT_SIGNAL(clicked()), TQT_SLOT(slotButton2()));
336  connect(this, TQT_SIGNAL(user1Clicked()), TQT_SLOT(slotLoadFolders()));
337 
338  // connect checkboxes
339  connect(subCB, TQT_SIGNAL(clicked()), TQT_SLOT(slotCBToggled()));
340  connect(newCB, TQT_SIGNAL(clicked()), TQT_SLOT(slotCBToggled()));
341  connect(noTreeCB, TQT_SIGNAL(clicked()), TQT_SLOT(slotCBToggled()));
342 
343  // connect textfield
344  connect(filterEdit, TQT_SIGNAL(textChanged(const TQString&)),
345  TQT_SLOT(slotFilterTextChanged(const TQString&)));
346 
347  // update status
348  connect(this, TQT_SIGNAL(listChanged()), TQT_SLOT(slotUpdateStatusLabel()));
349 }
350 
351 //-----------------------------------------------------------------------------
352 KSubscription::~KSubscription()
353 {
354 }
355 
356 //-----------------------------------------------------------------------------
357 void KSubscription::setStartItem( const KGroupInfo &info )
358 {
359  TQListViewItemIterator it(groupView);
360 
361  for ( ; it.current(); ++it)
362  {
363  if (static_cast<GroupItem*>(it.current())->info() == info)
364  {
365  it.current()->setSelected(true);
366  it.current()->setOpen(true);
367  }
368  }
369 }
370 
371 //-----------------------------------------------------------------------------
372 void KSubscription::removeListItem( TQListView *view, const KGroupInfo &gi )
373 {
374  if(!view) return;
375  TQListViewItemIterator it(view);
376 
377  for ( ; it.current(); ++it)
378  {
379  if (static_cast<GroupItem*>(it.current())->info() == gi)
380  {
381  delete it.current();
382  break;
383  }
384  }
385  if (view == groupView)
386  emit listChanged();
387 }
388 
389 //-----------------------------------------------------------------------------
390 TQListViewItem* KSubscription::getListItem( TQListView *view, const KGroupInfo &gi )
391 {
392  if(!view) return 0;
393  TQListViewItemIterator it(view);
394 
395  for ( ; it.current(); ++it)
396  {
397  if (static_cast<GroupItem*>(it.current())->info() == gi)
398  return (it.current());
399  }
400  return 0;
401 }
402 
403 //-----------------------------------------------------------------------------
404 bool KSubscription::itemInListView( TQListView *view, const KGroupInfo &gi )
405 {
406  if(!view) return false;
407  TQListViewItemIterator it(view);
408 
409  for ( ; it.current(); ++it)
410  if (static_cast<GroupItem*>(it.current())->info() == gi)
411  return true;
412 
413  return false;
414 }
415 
416 //------------------------------------------------------------------------------
417 void KSubscription::setDirectionButton1( Direction dir )
418 {
419  mDirButton1 = dir;
420  if (dir == Left)
421  arrowBtn1->setIconSet(pmLeft);
422  else
423  arrowBtn1->setIconSet(pmRight);
424 }
425 
426 //------------------------------------------------------------------------------
427 void KSubscription::setDirectionButton2( Direction dir )
428 {
429  mDirButton2 = dir;
430  if (dir == Left)
431  arrowBtn2->setIconSet(pmLeft);
432  else
433  arrowBtn2->setIconSet(pmRight);
434 }
435 
436 //------------------------------------------------------------------------------
438 {
439  // is this a checkable item
440  if (!item->isCheckItem()) return;
441 
442  // if we're currently loading the items ignore changes
443  if (mLoading) return;
444  if (on)
445  {
446  if (!itemInListView(unsubView, item->info()))
447  {
448  TQListViewItem *p = item->parent();
449  while (p)
450  {
451  // make sure all parents are subscribed
452  GroupItem* pi = static_cast<GroupItem*>(p);
453  if (pi->isCheckItem() && !pi->isOn())
454  {
455  pi->setIgnoreStateChange(true);
456  pi->setOn(true);
457  pi->setIgnoreStateChange(false);
458  new GroupItem(subView, pi->info(), this);
459  }
460  p = p->parent();
461  }
462  new GroupItem(subView, item->info(), this);
463  }
464  // eventually remove it from the other listview
465  removeListItem(unsubView, item->info());
466  }
467  else {
468  if (!itemInListView(subView, item->info()))
469  {
470  new GroupItem(unsubView, item->info(), this);
471  }
472  // eventually remove it from the other listview
473  removeListItem(subView, item->info());
474  }
475  // update the buttons
476  slotChangeButtonState(item);
477 }
478 
479 //------------------------------------------------------------------------------
480 void KSubscription::filterChanged( TQListViewItem* item, const TQString & text )
481 {
482  if ( !item && groupView )
483  item = groupView->firstChild();
484  if ( !item )
485  return;
486 
487  do
488  {
489  if ( item->firstChild() ) // recursive descend
490  filterChanged(item->firstChild(), text);
491 
492  GroupItem* gr = static_cast<GroupItem*>(item);
493  if (subCB->isChecked() || newCB->isChecked() || !text.isEmpty() ||
494  noTreeCB->isChecked())
495  {
496  // set it invisible
497  if ( subCB->isChecked() &&
498  (!gr->isCheckItem() ||
499  (gr->isCheckItem() && !gr->info().subscribed)) )
500  {
501  // only subscribed
502  gr->setVisible(false);
503  continue;
504  }
505  if ( newCB->isChecked() &&
506  (!gr->isCheckItem() ||
507  (gr->isCheckItem() && !gr->info().newGroup)) )
508  {
509  // only new
510  gr->setVisible(false);
511  continue;
512  }
513  if ( !text.isEmpty() &&
514  gr->text(0).find(text, 0, false) == -1)
515  {
516  // searchfield
517  gr->setVisible(false);
518  continue;
519  }
520  if ( noTreeCB->isChecked() &&
521  !gr->isCheckItem() )
522  {
523  // disable treeview
524  gr->setVisible(false);
525  continue;
526  }
527 
528  gr->setVisible(true);
529 
530  } else {
531  gr->setVisible(true);
532  }
533 
534  } while ((item = item->nextSibling()));
535 
536 }
537 
538 //------------------------------------------------------------------------------
540 {
541  TQListViewItemIterator it(groupView);
542 
543  uint count = 0;
544  for ( ; it.current(); ++it)
545  {
546  if (static_cast<GroupItem*>(it.current())->isCheckItem() &&
547  it.current()->isVisible() && it.current()->isEnabled())
548  count++;
549  }
550 
551  return count;
552 }
553 
554 //------------------------------------------------------------------------------
556 {
557  TQPtrList<TQListViewItem> move;
558  TQListViewItemIterator it(groupView);
559  for ( ; it.current(); ++it)
560  {
561  TQListViewItem* origParent = static_cast<GroupItem*>(it.current())->
562  originalParent();
563  if (origParent && origParent != it.current()->parent())
564  {
565  // remember this to avoid messing up the iterator
566  move.append(it.current());
567  }
568  }
569  TQPtrListIterator<TQListViewItem> it2( move );
570  for ( ; it2.current(); ++it2)
571  {
572  // restore the original parent
573  TQListViewItem* origParent = static_cast<GroupItem*>(it2.current())->
574  originalParent();
575  groupView->takeItem(it2.current());
576  origParent->insertItem(it2.current());
577  }
578 }
579 
580 //-----------------------------------------------------------------------------
582 {
583  TQListViewItemIterator it(groupView);
584 
585  for ( ; it.current(); ++it)
586  {
587  static_cast<GroupItem*>(it.current())->setLastOpenState(
588  it.current()->isOpen() );
589  }
590 }
591 
592 //-----------------------------------------------------------------------------
594 {
595  TQListViewItemIterator it(groupView);
596 
597  for ( ; it.current(); ++it)
598  {
599  it.current()->setOpen(
600  static_cast<GroupItem*>(it.current())->lastOpenState() );
601  }
602 }
603 
604 //-----------------------------------------------------------------------------
606 {
607  mLoading = false;
608 
609  enableButton(User1, true);
610  enableButton(User2, true);
611  newCB->setEnabled(true);
612  noTreeCB->setEnabled(true);
613  subCB->setEnabled(true);
614 
615  // remember the correct parent
616  TQListViewItemIterator it(groupView);
617  for ( ; it.current(); ++it)
618  {
619  static_cast<GroupItem*>(it.current())->
620  setOriginalParent( it.current()->parent() );
621  }
622 
623  emit listChanged();
624 }
625 
626 //------------------------------------------------------------------------------
627 void KSubscription::slotChangeButtonState( TQListViewItem *item )
628 {
629  if (!item ||
630  (item->listView() == groupView &&
631  !static_cast<GroupItem*>(item)->isCheckItem()))
632  {
633  // disable and return
634  arrowBtn1->setEnabled(false);
635  arrowBtn2->setEnabled(false);
636  return;
637  }
638  // set the direction of the buttons and enable/disable them
639  TQListView* currentView = item->listView();
640  if (currentView == groupView)
641  {
642  setDirectionButton1(Right);
643  setDirectionButton2(Right);
644  if (static_cast<GroupItem*>(item)->isOn())
645  {
646  // already subscribed
647  arrowBtn1->setEnabled(false);
648  arrowBtn2->setEnabled(true);
649  } else {
650  // unsubscribed
651  arrowBtn1->setEnabled(true);
652  arrowBtn2->setEnabled(false);
653  }
654  } else if (currentView == subView)
655  {
656  // undo possible
657  setDirectionButton1(Left);
658 
659  arrowBtn1->setEnabled(true);
660  arrowBtn2->setEnabled(false);
661  } else if (currentView == unsubView)
662  {
663  // undo possible
664  setDirectionButton2(Left);
665 
666  arrowBtn1->setEnabled(false);
667  arrowBtn2->setEnabled(true);
668  }
669 }
670 
671 //------------------------------------------------------------------------------
673 {
674  if (mDirButton1 == Right)
675  {
676  if (groupView->currentItem() &&
677  static_cast<GroupItem*>(groupView->currentItem())->isCheckItem())
678  {
679  // activate
680  GroupItem* item = static_cast<GroupItem*>(groupView->currentItem());
681  item->setOn(true);
682  }
683  }
684  else {
685  if (subView->currentItem())
686  {
687  GroupItem* item = static_cast<GroupItem*>(subView->currentItem());
688  // get the corresponding item from the groupView
689  TQListViewItem* listitem = getListItem(groupView, item->info());
690  if (listitem)
691  {
692  // deactivate
693  GroupItem* chk = static_cast<GroupItem*>(listitem);
694  chk->setOn(false);
695  }
696  }
697  }
698 }
699 
700 //------------------------------------------------------------------------------
701 void KSubscription::slotButton2()
702 {
703  if (mDirButton2 == Right)
704  {
705  if (groupView->currentItem() &&
706  static_cast<GroupItem*>(groupView->currentItem())->isCheckItem())
707  {
708  // deactivate
709  GroupItem* item = static_cast<GroupItem*>(groupView->currentItem());
710  item->setOn(false);
711  }
712  }
713  else {
714  if (unsubView->currentItem())
715  {
716  GroupItem* item = static_cast<GroupItem*>(unsubView->currentItem());
717  // get the corresponding item from the groupView
718  TQListViewItem* listitem = getListItem(groupView, item->info());
719  if (listitem)
720  {
721  // activate
722  GroupItem* chk = static_cast<GroupItem*>(listitem);
723  chk->setOn(true);
724  }
725  }
726  }
727 }
728 
729 //------------------------------------------------------------------------------
731 {
732  if (!noTreeCB->isChecked() && !newCB->isChecked() && !subCB->isChecked())
733  {
735  }
736  // set items {in}visible
737  filterChanged(groupView->firstChild());
738  emit listChanged();
739 }
740 
741 //------------------------------------------------------------------------------
742 void KSubscription::slotFilterTextChanged( const TQString & text )
743 {
744  // remember is the items are open
745  if (mLastText.isEmpty())
746  saveOpenStates();
747 
748  if (!mLastText.isEmpty() && text.length() < mLastText.length())
749  {
750  // reset
752  TQListViewItemIterator it(groupView);
753  for ( ; it.current(); ++it)
754  {
755  it.current()->setVisible(true);
756  it.current()->setEnabled(true);
757  }
758  }
759  // set items {in}visible
760  filterChanged(groupView->firstChild(), text);
761  // restore the open-states
762  if (text.isEmpty())
764 
765  emit listChanged();
766  mLastText = text;
767 }
768 
769 //------------------------------------------------------------------------------
771 {
772  TQString text;
773  if (mLoading)
774  text = i18n("Loading... (1 matching)", "Loading... (%n matching)",
775  activeItemCount());
776  else
777  text = i18n("%1: (1 matching)", "%1: (%n matching)", activeItemCount())
778  .arg(account()->name());
779 
780  leftLabel->setText(text);
781 }
782 
783 //------------------------------------------------------------------------------
785 {
786  enableButton(User1, false);
787  mLoading = true;
788  subView->clear();
789  unsubView->clear();
790  groupView->clear();
791 }
792 
793 #include "ksubscription.moc"