00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "ksubscription.h"
00014 #include "kaccount.h"
00015
00016 #include <qlayout.h>
00017 #include <qtimer.h>
00018 #include <qlabel.h>
00019 #include <qpushbutton.h>
00020 #include <qheader.h>
00021
00022 #include <kseparator.h>
00023 #include <kiconloader.h>
00024 #include <klocale.h>
00025 #include <kdebug.h>
00026 #include <klineedit.h>
00027
00028
00029
00030
00031 KGroupInfo::KGroupInfo(const QString &name, const QString &description,
00032 bool newGroup, bool subscribed,
00033 Status status, QString path)
00034 : name(name), description(description),
00035 newGroup(newGroup), subscribed(subscribed),
00036 status(status), path(path)
00037 {
00038 }
00039
00040
00041 bool KGroupInfo::operator== (const KGroupInfo &gi2)
00042 {
00043 return (name == gi2.name);
00044 }
00045
00046
00047 bool KGroupInfo::operator< (const KGroupInfo &gi2)
00048 {
00049 return (name < gi2.name);
00050 }
00051
00052
00053
00054 GroupItem::GroupItem( QListView *v, const KGroupInfo &gi, KSubscription* browser,
00055 bool isCheckItem )
00056 : QCheckListItem( v, gi.name, isCheckItem ? CheckBox : CheckBoxController ),
00057 mInfo( gi ), mBrowser( browser ), mIsCheckItem( isCheckItem ),
00058 mIgnoreStateChange( false )
00059 {
00060 if (listView()->columns() > 1)
00061 setDescription();
00062 }
00063
00064
00065 GroupItem::GroupItem( QListViewItem *i, const KGroupInfo &gi, KSubscription* browser,
00066 bool isCheckItem )
00067 : QCheckListItem( i, gi.name, isCheckItem ? CheckBox : CheckBoxController ),
00068 mInfo( gi ), mBrowser( browser ), mIsCheckItem( isCheckItem ),
00069 mIgnoreStateChange( false )
00070 {
00071 if (listView()->columns() > 1)
00072 setDescription();
00073 }
00074
00075
00076 void GroupItem::setInfo( KGroupInfo info )
00077 {
00078 mInfo = info;
00079 setText(0, mInfo.name);
00080 if (listView()->columns() > 1)
00081 setDescription();
00082 }
00083
00084
00085 void GroupItem::setDescription()
00086 {
00087 setText(1, mInfo.description);
00088 }
00089
00090
00091 void GroupItem::setOn( bool on )
00092 {
00093 if (mBrowser->isLoading())
00094 {
00095
00096
00097 mInfo.subscribed = on;
00098 }
00099 if (isCheckItem())
00100 QCheckListItem::setOn(on);
00101 }
00102
00103
00104 void GroupItem::stateChange( bool on )
00105 {
00106
00107 if ( !mIgnoreStateChange )
00108 mBrowser->changeItemState(this, on);
00109 }
00110
00111
00112 void GroupItem::setVisible( bool b )
00113 {
00114 if (b)
00115 {
00116 QListViewItem::setVisible(b);
00117 setEnabled(true);
00118 }
00119 else
00120 {
00121 if (isCheckItem())
00122 {
00123 bool setInvisible = true;
00124 for (QListViewItem * lvchild = firstChild(); lvchild != 0;
00125 lvchild = lvchild->nextSibling())
00126 {
00127 if (lvchild->isVisible())
00128 setInvisible = false;
00129 }
00130 if (setInvisible)
00131 QListViewItem::setVisible(b);
00132 else
00133 {
00134
00135 setOpen(true);
00136 setEnabled(false);
00137 }
00138 }
00139 else
00140 {
00141
00142 QPtrList<QListViewItem> moveItems;
00143
00144 for (QListViewItem * lvchild = firstChild(); lvchild != 0;
00145 lvchild = lvchild->nextSibling())
00146 {
00147 if (static_cast<GroupItem*>(lvchild)->isCheckItem())
00148 {
00149
00150 moveItems.append(lvchild);
00151 }
00152 }
00153 QPtrListIterator<QListViewItem> it( moveItems );
00154 for ( ; it.current(); ++it)
00155 {
00156
00157 QListViewItem* parent = it.current()->parent();
00158 if (parent) parent->takeItem(it.current());
00159 listView()->insertItem(it.current());
00160 }
00161 QListViewItem::setVisible(false);
00162 }
00163 }
00164 }
00165
00166
00167 void GroupItem::paintCell( QPainter * p, const QColorGroup & cg,
00168 int column, int width, int align )
00169 {
00170 if (mIsCheckItem)
00171 return QCheckListItem::paintCell( p, cg, column, width, align );
00172 else
00173 return QListViewItem::paintCell( p, cg, column, width, align );
00174 }
00175
00176
00177 void GroupItem::paintFocus( QPainter * p, const QColorGroup & cg,
00178 const QRect & r )
00179 {
00180 if (mIsCheckItem)
00181 QCheckListItem::paintFocus(p, cg, r);
00182 else
00183 QListViewItem::paintFocus(p, cg, r);
00184 }
00185
00186
00187 int GroupItem::width( const QFontMetrics& fm, const QListView* lv, int column) const
00188 {
00189 if (mIsCheckItem)
00190 return QCheckListItem::width(fm, lv, column);
00191 else
00192 return QListViewItem::width(fm, lv, column);
00193 }
00194
00195
00196 void GroupItem::setup()
00197 {
00198 if (mIsCheckItem)
00199 QCheckListItem::setup();
00200 else
00201 QListViewItem::setup();
00202 }
00203
00204
00205
00206
00207 KSubscription::KSubscription( QWidget *parent, const QString &caption,
00208 KAccount * acct, int buttons, const QString &user1, bool descriptionColumn )
00209 : KDialogBase( parent, 0, true, caption, buttons | Help | Ok | Cancel, Ok,
00210 true, i18n("Reload &List"), user1 ),
00211 mAcct( acct )
00212 {
00213 mLoading = true;
00214 setWFlags( getWFlags() | WDestructiveClose );
00215
00216
00217 page = new QWidget(this);
00218 setMainWidget(page);
00219
00220 filterEdit = new KLineEdit(page);
00221 QLabel *l = new QLabel(filterEdit,i18n("S&earch:"), page);
00222
00223
00224 noTreeCB = new QCheckBox(i18n("Disable &tree view"), page);
00225 noTreeCB->setChecked(false);
00226 subCB = new QCheckBox(i18n("&Subscribed only"), page);
00227 subCB->setChecked(false);
00228 newCB = new QCheckBox(i18n("&New only"), page);
00229 newCB->setChecked(false);
00230
00231 KSeparator *sep = new KSeparator(KSeparator::HLine, page);
00232
00233
00234 QFont fnt = font();
00235 fnt.setBold(true);
00236 leftLabel = new QLabel(i18n("Loading..."), page);
00237 rightLabel = new QLabel(i18n("Current changes:"), page);
00238 leftLabel->setFont(fnt);
00239 rightLabel->setFont(fnt);
00240
00241
00242 pmRight = BarIcon("forward");
00243 pmLeft = BarIcon("back");
00244
00245 arrowBtn1 = new QPushButton(page);
00246 arrowBtn1->setEnabled(false);
00247 arrowBtn2 = new QPushButton(page);
00248 arrowBtn2->setEnabled(false);
00249 arrowBtn1->setPixmap(pmRight);
00250 arrowBtn2->setPixmap(pmRight);
00251 arrowBtn1->setFixedSize(35,30);
00252 arrowBtn2->setFixedSize(35,30);
00253
00254
00255 groupView = new QListView(page);
00256 groupView->setRootIsDecorated(true);
00257 groupView->addColumn(i18n("Name"));
00258 groupView->setAllColumnsShowFocus(true);
00259 if (descriptionColumn)
00260 mDescrColumn = groupView->addColumn(i18n("Description"));
00261 else
00262 groupView->header()->setStretchEnabled(true, 0);
00263
00264
00265 QGridLayout *topL = new QGridLayout(page,3,1,0,5);
00266 QHBoxLayout *filterL = new QHBoxLayout(10);
00267 QVBoxLayout *arrL = new QVBoxLayout(10);
00268 listL = new QGridLayout(2, 3, 5);
00269
00270 topL->addLayout(filterL, 0,0);
00271 topL->addWidget(sep,1,0);
00272 topL->addLayout(listL, 2,0);
00273
00274 filterL->addWidget(l);
00275 filterL->addWidget(filterEdit, 1);
00276 filterL->addWidget(noTreeCB);
00277 filterL->addWidget(subCB);
00278 filterL->addWidget(newCB);
00279
00280 listL->addWidget(leftLabel, 0,0);
00281 listL->addWidget(rightLabel, 0,2);
00282 listL->addWidget(groupView, 1,0);
00283 listL->addLayout(arrL, 1,1);
00284 listL->setRowStretch(1,1);
00285 listL->setColStretch(0,5);
00286 listL->setColStretch(2,2);
00287
00288 arrL->addWidget(arrowBtn1, AlignCenter);
00289 arrL->addWidget(arrowBtn2, AlignCenter);
00290
00291
00292 subView = new QListView(page);
00293 subView->addColumn(i18n("Subscribe To"));
00294 subView->header()->setStretchEnabled(true, 0);
00295 unsubView = new QListView(page);
00296 unsubView->addColumn(i18n("Unsubscribe From"));
00297 unsubView->header()->setStretchEnabled(true, 0);
00298
00299 QVBoxLayout *protL = new QVBoxLayout(3);
00300 listL->addLayout(protL, 1,2);
00301 protL->addWidget(subView);
00302 protL->addWidget(unsubView);
00303
00304
00305 enableButton(User1, false);
00306 enableButton(User2, false);
00307 newCB->setEnabled(false);
00308 noTreeCB->setEnabled(false);
00309 subCB->setEnabled(false);
00310
00311 filterEdit->setFocus();
00312
00313
00314 connect(groupView, SIGNAL(clicked(QListViewItem *)),
00315 this, SLOT(slotChangeButtonState(QListViewItem*)));
00316 connect(subView, SIGNAL(clicked(QListViewItem *)),
00317 this, SLOT(slotChangeButtonState(QListViewItem*)));
00318 connect(unsubView, SIGNAL(clicked(QListViewItem *)),
00319 this, SLOT(slotChangeButtonState(QListViewItem*)));
00320
00321
00322 connect(arrowBtn1, SIGNAL(clicked()), SLOT(slotButton1()));
00323 connect(arrowBtn2, SIGNAL(clicked()), SLOT(slotButton2()));
00324 connect(this, SIGNAL(user1Clicked()), SLOT(slotLoadFolders()));
00325
00326
00327 connect(subCB, SIGNAL(clicked()), SLOT(slotCBToggled()));
00328 connect(newCB, SIGNAL(clicked()), SLOT(slotCBToggled()));
00329 connect(noTreeCB, SIGNAL(clicked()), SLOT(slotCBToggled()));
00330
00331
00332 connect(filterEdit, SIGNAL(textChanged(const QString&)),
00333 SLOT(slotFilterTextChanged(const QString&)));
00334
00335
00336 connect(this, SIGNAL(listChanged()), SLOT(slotUpdateStatusLabel()));
00337 }
00338
00339
00340 KSubscription::~KSubscription()
00341 {
00342 }
00343
00344
00345 void KSubscription::setStartItem( const KGroupInfo &info )
00346 {
00347 QListViewItemIterator it(groupView);
00348
00349 for ( ; it.current(); ++it)
00350 {
00351 if (static_cast<GroupItem*>(it.current())->info() == info)
00352 {
00353 it.current()->setSelected(true);
00354 it.current()->setOpen(true);
00355 }
00356 }
00357 }
00358
00359
00360 void KSubscription::removeListItem( QListView *view, const KGroupInfo &gi )
00361 {
00362 if(!view) return;
00363 QListViewItemIterator it(view);
00364
00365 for ( ; it.current(); ++it)
00366 {
00367 if (static_cast<GroupItem*>(it.current())->info() == gi)
00368 {
00369 delete it.current();
00370 break;
00371 }
00372 }
00373 if (view == groupView)
00374 emit listChanged();
00375 }
00376
00377
00378 QListViewItem* KSubscription::getListItem( QListView *view, const KGroupInfo &gi )
00379 {
00380 if(!view) return 0;
00381 QListViewItemIterator it(view);
00382
00383 for ( ; it.current(); ++it)
00384 {
00385 if (static_cast<GroupItem*>(it.current())->info() == gi)
00386 return (it.current());
00387 }
00388 return 0;
00389 }
00390
00391
00392 bool KSubscription::itemInListView( QListView *view, const KGroupInfo &gi )
00393 {
00394 if(!view) return false;
00395 QListViewItemIterator it(view);
00396
00397 for ( ; it.current(); ++it)
00398 if (static_cast<GroupItem*>(it.current())->info() == gi)
00399 return true;
00400
00401 return false;
00402 }
00403
00404
00405 void KSubscription::setDirectionButton1( Direction dir )
00406 {
00407 mDirButton1 = dir;
00408 if (dir == Left)
00409 arrowBtn1->setPixmap(pmLeft);
00410 else
00411 arrowBtn1->setPixmap(pmRight);
00412 }
00413
00414
00415 void KSubscription::setDirectionButton2( Direction dir )
00416 {
00417 mDirButton2 = dir;
00418 if (dir == Left)
00419 arrowBtn2->setPixmap(pmLeft);
00420 else
00421 arrowBtn2->setPixmap(pmRight);
00422 }
00423
00424
00425 void KSubscription::changeItemState( GroupItem* item, bool on )
00426 {
00427
00428 if (!item->isCheckItem()) return;
00429
00430
00431 if (mLoading) return;
00432 if (on)
00433 {
00434 if (!itemInListView(unsubView, item->info()))
00435 {
00436 QListViewItem *p = item->parent();
00437 while (p)
00438 {
00439
00440 GroupItem* pi = static_cast<GroupItem*>(p);
00441 if (pi->isCheckItem() && !pi->isOn())
00442 {
00443 pi->setIgnoreStateChange(true);
00444 pi->setOn(true);
00445 pi->setIgnoreStateChange(false);
00446 new GroupItem(subView, pi->info(), this);
00447 }
00448 p = p->parent();
00449 }
00450 new GroupItem(subView, item->info(), this);
00451 }
00452
00453 removeListItem(unsubView, item->info());
00454 }
00455 else {
00456 if (!itemInListView(subView, item->info()))
00457 {
00458 new GroupItem(unsubView, item->info(), this);
00459 }
00460
00461 removeListItem(subView, item->info());
00462 }
00463
00464 slotChangeButtonState(item);
00465 }
00466
00467
00468 void KSubscription::filterChanged( QListViewItem* item, const QString & text )
00469 {
00470 if ( !item && groupView )
00471 item = groupView->firstChild();
00472 if ( !item )
00473 return;
00474
00475 do
00476 {
00477 if ( item->firstChild() )
00478 filterChanged(item->firstChild(), text);
00479
00480 GroupItem* gr = static_cast<GroupItem*>(item);
00481 if (subCB->isChecked() || newCB->isChecked() || !text.isEmpty() ||
00482 noTreeCB->isChecked())
00483 {
00484
00485 if ( subCB->isChecked() &&
00486 (!gr->isCheckItem() ||
00487 (gr->isCheckItem() && !gr->info().subscribed)) )
00488 {
00489
00490 gr->setVisible(false);
00491 continue;
00492 }
00493 if ( newCB->isChecked() &&
00494 (!gr->isCheckItem() ||
00495 (gr->isCheckItem() && !gr->info().newGroup)) )
00496 {
00497
00498 gr->setVisible(false);
00499 continue;
00500 }
00501 if ( !text.isEmpty() &&
00502 gr->text(0).find(text, 0, false) == -1)
00503 {
00504
00505 gr->setVisible(false);
00506 continue;
00507 }
00508 if ( noTreeCB->isChecked() &&
00509 !gr->isCheckItem() )
00510 {
00511
00512 gr->setVisible(false);
00513 continue;
00514 }
00515
00516 gr->setVisible(true);
00517
00518 } else {
00519 gr->setVisible(true);
00520 }
00521
00522 } while ((item = item->nextSibling()));
00523
00524 }
00525
00526
00527 uint KSubscription::activeItemCount()
00528 {
00529 QListViewItemIterator it(groupView);
00530
00531 uint count = 0;
00532 for ( ; it.current(); ++it)
00533 {
00534 if (static_cast<GroupItem*>(it.current())->isCheckItem() &&
00535 it.current()->isVisible() && it.current()->isEnabled())
00536 count++;
00537 }
00538
00539 return count;
00540 }
00541
00542
00543 void KSubscription::restoreOriginalParent()
00544 {
00545 QPtrList<QListViewItem> move;
00546 QListViewItemIterator it(groupView);
00547 for ( ; it.current(); ++it)
00548 {
00549 QListViewItem* origParent = static_cast<GroupItem*>(it.current())->
00550 originalParent();
00551 if (origParent && origParent != it.current()->parent())
00552 {
00553
00554 move.append(it.current());
00555 }
00556 }
00557 QPtrListIterator<QListViewItem> it2( move );
00558 for ( ; it2.current(); ++it2)
00559 {
00560
00561 QListViewItem* origParent = static_cast<GroupItem*>(it2.current())->
00562 originalParent();
00563 groupView->takeItem(it2.current());
00564 origParent->insertItem(it2.current());
00565 }
00566 }
00567
00568
00569 void KSubscription::saveOpenStates()
00570 {
00571 QListViewItemIterator it(groupView);
00572
00573 for ( ; it.current(); ++it)
00574 {
00575 static_cast<GroupItem*>(it.current())->setLastOpenState(
00576 it.current()->isOpen() );
00577 }
00578 }
00579
00580
00581 void KSubscription::restoreOpenStates()
00582 {
00583 QListViewItemIterator it(groupView);
00584
00585 for ( ; it.current(); ++it)
00586 {
00587 it.current()->setOpen(
00588 static_cast<GroupItem*>(it.current())->lastOpenState() );
00589 }
00590 }
00591
00592
00593 void KSubscription::slotLoadingComplete()
00594 {
00595 mLoading = false;
00596
00597 enableButton(User1, true);
00598 enableButton(User2, true);
00599 newCB->setEnabled(true);
00600 noTreeCB->setEnabled(true);
00601 subCB->setEnabled(true);
00602
00603
00604 QListViewItemIterator it(groupView);
00605 for ( ; it.current(); ++it)
00606 {
00607 static_cast<GroupItem*>(it.current())->
00608 setOriginalParent( it.current()->parent() );
00609 }
00610
00611 emit listChanged();
00612 }
00613
00614
00615 void KSubscription::slotChangeButtonState( QListViewItem *item )
00616 {
00617 if (!item ||
00618 (item->listView() == groupView &&
00619 !static_cast<GroupItem*>(item)->isCheckItem()))
00620 {
00621
00622 arrowBtn1->setEnabled(false);
00623 arrowBtn2->setEnabled(false);
00624 return;
00625 }
00626
00627 QListView* currentView = item->listView();
00628 if (currentView == groupView)
00629 {
00630 setDirectionButton1(Right);
00631 setDirectionButton2(Right);
00632 if (static_cast<GroupItem*>(item)->isOn())
00633 {
00634
00635 arrowBtn1->setEnabled(false);
00636 arrowBtn2->setEnabled(true);
00637 } else {
00638
00639 arrowBtn1->setEnabled(true);
00640 arrowBtn2->setEnabled(false);
00641 }
00642 } else if (currentView == subView)
00643 {
00644
00645 setDirectionButton1(Left);
00646
00647 arrowBtn1->setEnabled(true);
00648 arrowBtn2->setEnabled(false);
00649 } else if (currentView == unsubView)
00650 {
00651
00652 setDirectionButton2(Left);
00653
00654 arrowBtn1->setEnabled(false);
00655 arrowBtn2->setEnabled(true);
00656 }
00657 }
00658
00659
00660 void KSubscription::slotButton1()
00661 {
00662 if (mDirButton1 == Right)
00663 {
00664 if (groupView->currentItem() &&
00665 static_cast<GroupItem*>(groupView->currentItem())->isCheckItem())
00666 {
00667
00668 GroupItem* item = static_cast<GroupItem*>(groupView->currentItem());
00669 item->setOn(true);
00670 }
00671 }
00672 else {
00673 if (subView->currentItem())
00674 {
00675 GroupItem* item = static_cast<GroupItem*>(subView->currentItem());
00676
00677 QListViewItem* listitem = getListItem(groupView, item->info());
00678 if (listitem)
00679 {
00680
00681 GroupItem* chk = static_cast<GroupItem*>(listitem);
00682 chk->setOn(false);
00683 }
00684 }
00685 }
00686 }
00687
00688
00689 void KSubscription::slotButton2()
00690 {
00691 if (mDirButton2 == Right)
00692 {
00693 if (groupView->currentItem() &&
00694 static_cast<GroupItem*>(groupView->currentItem())->isCheckItem())
00695 {
00696
00697 GroupItem* item = static_cast<GroupItem*>(groupView->currentItem());
00698 item->setOn(false);
00699 }
00700 }
00701 else {
00702 if (unsubView->currentItem())
00703 {
00704 GroupItem* item = static_cast<GroupItem*>(unsubView->currentItem());
00705
00706 QListViewItem* listitem = getListItem(groupView, item->info());
00707 if (listitem)
00708 {
00709
00710 GroupItem* chk = static_cast<GroupItem*>(listitem);
00711 chk->setOn(true);
00712 }
00713 }
00714 }
00715 }
00716
00717
00718 void KSubscription::slotCBToggled()
00719 {
00720 if (!noTreeCB->isChecked() && !newCB->isChecked() && !subCB->isChecked())
00721 {
00722 restoreOriginalParent();
00723 }
00724
00725 filterChanged(groupView->firstChild());
00726 emit listChanged();
00727 }
00728
00729
00730 void KSubscription::slotFilterTextChanged( const QString & text )
00731 {
00732
00733 if (mLastText.isEmpty())
00734 saveOpenStates();
00735
00736 if (!mLastText.isEmpty() && text.length() < mLastText.length())
00737 {
00738
00739 restoreOriginalParent();
00740 QListViewItemIterator it(groupView);
00741 for ( ; it.current(); ++it)
00742 {
00743 it.current()->setVisible(true);
00744 it.current()->setEnabled(true);
00745 }
00746 }
00747
00748 filterChanged(groupView->firstChild(), text);
00749
00750 if (text.isEmpty())
00751 restoreOpenStates();
00752
00753 emit listChanged();
00754 mLastText = text;
00755 }
00756
00757
00758 void KSubscription::slotUpdateStatusLabel()
00759 {
00760 QString text;
00761 if (mLoading)
00762 text = i18n("Loading... (1 matching)", "Loading... (%n matching)",
00763 activeItemCount());
00764 else
00765 text = i18n("%1: (1 matching)", "%1: (%n matching)", activeItemCount())
00766 .arg(account()->name());
00767
00768 leftLabel->setText(text);
00769 }
00770
00771
00772 void KSubscription::slotLoadFolders()
00773 {
00774 mLoading = true;
00775 subView->clear();
00776 unsubView->clear();
00777 groupView->clear();
00778 }
00779
00780 #include "ksubscription.moc"