/* ksubscription.cpp This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US */ #include "ksubscription.h" #include "kaccount.h" #include #include #include #include #include #include #include #include #include #include #include #include //============================================================================= KGroupInfo::KGroupInfo(const TQString &name, const TQString &description, bool newGroup, bool subscribed, Status status, TQString path) : name(name), description(description), newGroup(newGroup), subscribed(subscribed), status(status), path(path) { } //----------------------------------------------------------------------------- bool KGroupInfo::operator== (const KGroupInfo &gi2) { return (name == gi2.name); } //----------------------------------------------------------------------------- bool KGroupInfo::operator< (const KGroupInfo &gi2) { return (name < gi2.name); } //============================================================================= GroupItem::GroupItem( TQListView *v, const KGroupInfo &gi, KSubscription* browser, bool isCheckItem ) : TQCheckListItem( v, gi.name, isCheckItem ? CheckBox : CheckBoxController ), mInfo( gi ), mBrowser( browser ), mIsCheckItem( isCheckItem ), mIgnoreStateChange( false ) { if (listView()->columns() > 1) setDescription(); } //----------------------------------------------------------------------------- GroupItem::GroupItem( TQListViewItem *i, const KGroupInfo &gi, KSubscription* browser, bool isCheckItem ) : TQCheckListItem( i, gi.name, isCheckItem ? CheckBox : CheckBoxController ), mInfo( gi ), mBrowser( browser ), mIsCheckItem( isCheckItem ), mIgnoreStateChange( false ) { if (listView()->columns() > 1) setDescription(); } //----------------------------------------------------------------------------- void GroupItem::setInfo( KGroupInfo info ) { mInfo = info; setText(0, mInfo.name); if (listView()->columns() > 1) setDescription(); } //----------------------------------------------------------------------------- void GroupItem::setDescription() { setText(1, mInfo.description); } //----------------------------------------------------------------------------- void GroupItem::setOn( bool on ) { if (mBrowser->isLoading()) { // set this only if we're loading/creating items // otherwise changes are only permanent when the dialog is saved mInfo.subscribed = on; } if (isCheckItem()) TQCheckListItem::setOn(on); } //------------------------------------------------------------------------------ void GroupItem::stateChange( bool on ) { // delegate to parent if ( !mIgnoreStateChange ) mBrowser->changeItemState(this, on); } //------------------------------------------------------------------------------ void GroupItem::setVisible( bool b ) { if (b) { TQListViewItem::setVisible(b); setEnabled(true); } else { if (isCheckItem()) { bool setInvisible = true; for (TQListViewItem * lvchild = firstChild(); lvchild != 0; lvchild = lvchild->nextSibling()) { if (lvchild->isVisible()) // item has a visible child setInvisible = false; } if (setInvisible) TQListViewItem::setVisible(b); else { // leave it visible so that children remain visible setOpen(true); setEnabled(false); } } else { // non-checkable item TQPtrList moveItems; for (TQListViewItem * lvchild = firstChild(); lvchild != 0; lvchild = lvchild->nextSibling()) { if (static_cast(lvchild)->isCheckItem()) { // remember the items moveItems.append(lvchild); } } TQPtrListIterator it( moveItems ); for ( ; it.current(); ++it) { // move the checkitem to top TQListViewItem* parent = it.current()->parent(); if (parent) parent->takeItem(it.current()); listView()->insertItem(it.current()); } TQListViewItem::setVisible(false); } } } //----------------------------------------------------------------------------- void GroupItem::paintCell( TQPainter * p, const TQColorGroup & cg, int column, int width, int align ) { if (mIsCheckItem) return TQCheckListItem::paintCell( p, cg, column, width, align ); else return TQListViewItem::paintCell( p, cg, column, width, align ); } //----------------------------------------------------------------------------- void GroupItem::paintFocus( TQPainter * p, const TQColorGroup & cg, const TQRect & r ) { if (mIsCheckItem) TQCheckListItem::paintFocus(p, cg, r); else TQListViewItem::paintFocus(p, cg, r); } //----------------------------------------------------------------------------- int GroupItem::width( const TQFontMetrics& fm, const TQListView* lv, int column) const { if (mIsCheckItem) return TQCheckListItem::width(fm, lv, column); else return TQListViewItem::width(fm, lv, column); } //----------------------------------------------------------------------------- void GroupItem::setup() { if (mIsCheckItem) TQCheckListItem::setup(); else TQListViewItem::setup(); } //============================================================================= KSubscription::KSubscription( TQWidget *parent, const TQString &caption, KAccount * acct, int buttons, const TQString &user1, bool descriptionColumn ) : KDialogBase( parent, 0, true, caption, buttons | Help | Ok | Cancel, Ok, true, i18n("Reload &List"), user1 ), mAcct( acct ) { mLoading = true; setWFlags( getWFlags() | WDestructiveClose ); // create Widgets page = new TQWidget(this); setMainWidget(page); TQLabel *comment = new TQLabel("

"+ i18n("Manage which mail folders you want to see in your folder view") + "

", page); TQToolButton *clearButton = new TQToolButton( page ); clearButton->setIconSet( TDEGlobal::iconLoader()->loadIconSet( TDEApplication::reverseLayout() ? "clear_left":"locationbar_erase", TDEIcon::Small, 0 ) ); filterEdit = new KLineEdit(page); TQLabel *l = new TQLabel(filterEdit,i18n("S&earch:"), page); connect( clearButton, TQT_SIGNAL( clicked() ), filterEdit, TQT_SLOT( clear() ) ); // checkboxes noTreeCB = new TQCheckBox(i18n("Disable &tree view"), page); noTreeCB->setChecked(false); subCB = new TQCheckBox(i18n("&Subscribed only"), page); subCB->setChecked(false); newCB = new TQCheckBox(i18n("&New only"), page); newCB->setChecked(false); KSeparator *sep = new KSeparator(KSeparator::HLine, page); // init the labels TQFont fnt = font(); fnt.setBold(true); leftLabel = new TQLabel(i18n("Loading..."), page); rightLabel = new TQLabel(i18n("Current changes:"), page); leftLabel->setFont(fnt); rightLabel->setFont(fnt); // icons pmRight = BarIconSet("forward"); pmLeft = BarIconSet("back"); arrowBtn1 = new TQPushButton(page); arrowBtn1->setEnabled(false); arrowBtn2 = new TQPushButton(page); arrowBtn2->setEnabled(false); arrowBtn1->setIconSet(pmRight); arrowBtn2->setIconSet(pmRight); arrowBtn1->setFixedSize(35,30); arrowBtn2->setFixedSize(35,30); // the main listview groupView = new TQListView(page); groupView->setRootIsDecorated(true); groupView->addColumn(i18n("Name")); groupView->setAllColumnsShowFocus(true); if (descriptionColumn) mDescrColumn = groupView->addColumn(i18n("Description")); else groupView->header()->setStretchEnabled(true, 0); // layout TQGridLayout *topL = new TQGridLayout(page,4,1,0, KDialog::spacingHint()); TQHBoxLayout *filterL = new TQHBoxLayout(KDialog::spacingHint()); TQVBoxLayout *arrL = new TQVBoxLayout(KDialog::spacingHint()); listL = new TQGridLayout(2, 3, KDialog::spacingHint()); topL->addWidget(comment, 0,0); topL->addLayout(filterL, 1,0); topL->addWidget(sep,2,0); topL->addLayout(listL, 3,0); filterL->addWidget(clearButton); filterL->addWidget(l); filterL->addWidget(filterEdit, 1); filterL->addWidget(noTreeCB); filterL->addWidget(subCB); filterL->addWidget(newCB); listL->addWidget(leftLabel, 0,0); listL->addWidget(rightLabel, 0,2); listL->addWidget(groupView, 1,0); listL->addLayout(arrL, 1,1); listL->setRowStretch(1,1); listL->setColStretch(0,5); listL->setColStretch(2,2); arrL->addWidget(arrowBtn1, AlignCenter); arrL->addWidget(arrowBtn2, AlignCenter); // listviews subView = new TQListView(page); subView->addColumn(i18n("Subscribe To")); subView->header()->setStretchEnabled(true, 0); unsubView = new TQListView(page); unsubView->addColumn(i18n("Unsubscribe From")); unsubView->header()->setStretchEnabled(true, 0); TQVBoxLayout *protL = new TQVBoxLayout(3); listL->addLayout(protL, 1,2); protL->addWidget(subView); protL->addWidget(unsubView); // disable some widgets as long we're loading enableButton(User1, false); enableButton(User2, false); newCB->setEnabled(false); noTreeCB->setEnabled(false); subCB->setEnabled(false); filterEdit->setFocus(); // items clicked connect(groupView, TQT_SIGNAL(clicked(TQListViewItem *)), this, TQT_SLOT(slotChangeButtonState(TQListViewItem*))); connect(subView, TQT_SIGNAL(clicked(TQListViewItem *)), this, TQT_SLOT(slotChangeButtonState(TQListViewItem*))); connect(unsubView, TQT_SIGNAL(clicked(TQListViewItem *)), this, TQT_SLOT(slotChangeButtonState(TQListViewItem*))); // connect buttons connect(arrowBtn1, TQT_SIGNAL(clicked()), TQT_SLOT(slotButton1())); connect(arrowBtn2, TQT_SIGNAL(clicked()), TQT_SLOT(slotButton2())); connect(this, TQT_SIGNAL(user1Clicked()), TQT_SLOT(slotLoadFolders())); // connect checkboxes connect(subCB, TQT_SIGNAL(clicked()), TQT_SLOT(slotCBToggled())); connect(newCB, TQT_SIGNAL(clicked()), TQT_SLOT(slotCBToggled())); connect(noTreeCB, TQT_SIGNAL(clicked()), TQT_SLOT(slotCBToggled())); // connect textfield connect(filterEdit, TQT_SIGNAL(textChanged(const TQString&)), TQT_SLOT(slotFilterTextChanged(const TQString&))); // update status connect(this, TQT_SIGNAL(listChanged()), TQT_SLOT(slotUpdateStatusLabel())); } //----------------------------------------------------------------------------- KSubscription::~KSubscription() { } //----------------------------------------------------------------------------- void KSubscription::setStartItem( const KGroupInfo &info ) { TQListViewItemIterator it(groupView); for ( ; it.current(); ++it) { if (static_cast(it.current())->info() == info) { it.current()->setSelected(true); it.current()->setOpen(true); } } } //----------------------------------------------------------------------------- void KSubscription::removeListItem( TQListView *view, const KGroupInfo &gi ) { if(!view) return; TQListViewItemIterator it(view); for ( ; it.current(); ++it) { if (static_cast(it.current())->info() == gi) { delete it.current(); break; } } if (view == groupView) emit listChanged(); } //----------------------------------------------------------------------------- TQListViewItem* KSubscription::getListItem( TQListView *view, const KGroupInfo &gi ) { if(!view) return 0; TQListViewItemIterator it(view); for ( ; it.current(); ++it) { if (static_cast(it.current())->info() == gi) return (it.current()); } return 0; } //----------------------------------------------------------------------------- bool KSubscription::itemInListView( TQListView *view, const KGroupInfo &gi ) { if(!view) return false; TQListViewItemIterator it(view); for ( ; it.current(); ++it) if (static_cast(it.current())->info() == gi) return true; return false; } //------------------------------------------------------------------------------ void KSubscription::setDirectionButton1( Direction dir ) { mDirButton1 = dir; if (dir == Left) arrowBtn1->setIconSet(pmLeft); else arrowBtn1->setIconSet(pmRight); } //------------------------------------------------------------------------------ void KSubscription::setDirectionButton2( Direction dir ) { mDirButton2 = dir; if (dir == Left) arrowBtn2->setIconSet(pmLeft); else arrowBtn2->setIconSet(pmRight); } //------------------------------------------------------------------------------ void KSubscription::changeItemState( GroupItem* item, bool on ) { // is this a checkable item if (!item->isCheckItem()) return; // if we're currently loading the items ignore changes if (mLoading) return; if (on) { if (!itemInListView(unsubView, item->info())) { TQListViewItem *p = item->parent(); while (p) { // make sure all parents are subscribed GroupItem* pi = static_cast(p); if (pi->isCheckItem() && !pi->isOn()) { pi->setIgnoreStateChange(true); pi->setOn(true); pi->setIgnoreStateChange(false); new GroupItem(subView, pi->info(), this); } p = p->parent(); } new GroupItem(subView, item->info(), this); } // eventually remove it from the other listview removeListItem(unsubView, item->info()); } else { if (!itemInListView(subView, item->info())) { new GroupItem(unsubView, item->info(), this); } // eventually remove it from the other listview removeListItem(subView, item->info()); } // update the buttons slotChangeButtonState(item); } //------------------------------------------------------------------------------ void KSubscription::filterChanged( TQListViewItem* item, const TQString & text ) { if ( !item && groupView ) item = groupView->firstChild(); if ( !item ) return; do { if ( item->firstChild() ) // recursive descend filterChanged(item->firstChild(), text); GroupItem* gr = static_cast(item); if (subCB->isChecked() || newCB->isChecked() || !text.isEmpty() || noTreeCB->isChecked()) { // set it invisible if ( subCB->isChecked() && (!gr->isCheckItem() || (gr->isCheckItem() && !gr->info().subscribed)) ) { // only subscribed gr->setVisible(false); continue; } if ( newCB->isChecked() && (!gr->isCheckItem() || (gr->isCheckItem() && !gr->info().newGroup)) ) { // only new gr->setVisible(false); continue; } if ( !text.isEmpty() && gr->text(0).find(text, 0, false) == -1) { // searchfield gr->setVisible(false); continue; } if ( noTreeCB->isChecked() && !gr->isCheckItem() ) { // disable treeview gr->setVisible(false); continue; } gr->setVisible(true); } else { gr->setVisible(true); } } while ((item = item->nextSibling())); } //------------------------------------------------------------------------------ uint KSubscription::activeItemCount() { TQListViewItemIterator it(groupView); uint count = 0; for ( ; it.current(); ++it) { if (static_cast(it.current())->isCheckItem() && it.current()->isVisible() && it.current()->isEnabled()) count++; } return count; } //------------------------------------------------------------------------------ void KSubscription::restoreOriginalParent() { TQPtrList move; TQListViewItemIterator it(groupView); for ( ; it.current(); ++it) { TQListViewItem* origParent = static_cast(it.current())-> originalParent(); if (origParent && origParent != it.current()->parent()) { // remember this to avoid messing up the iterator move.append(it.current()); } } TQPtrListIterator it2( move ); for ( ; it2.current(); ++it2) { // restore the original parent TQListViewItem* origParent = static_cast(it2.current())-> originalParent(); groupView->takeItem(it2.current()); origParent->insertItem(it2.current()); } } //----------------------------------------------------------------------------- void KSubscription::saveOpenStates() { TQListViewItemIterator it(groupView); for ( ; it.current(); ++it) { static_cast(it.current())->setLastOpenState( it.current()->isOpen() ); } } //----------------------------------------------------------------------------- void KSubscription::restoreOpenStates() { TQListViewItemIterator it(groupView); for ( ; it.current(); ++it) { it.current()->setOpen( static_cast(it.current())->lastOpenState() ); } } //----------------------------------------------------------------------------- void KSubscription::slotLoadingComplete() { mLoading = false; enableButton(User1, true); enableButton(User2, true); newCB->setEnabled(true); noTreeCB->setEnabled(true); subCB->setEnabled(true); // remember the correct parent TQListViewItemIterator it(groupView); for ( ; it.current(); ++it) { static_cast(it.current())-> setOriginalParent( it.current()->parent() ); } emit listChanged(); } //------------------------------------------------------------------------------ void KSubscription::slotChangeButtonState( TQListViewItem *item ) { if (!item || (item->listView() == groupView && !static_cast(item)->isCheckItem())) { // disable and return arrowBtn1->setEnabled(false); arrowBtn2->setEnabled(false); return; } // set the direction of the buttons and enable/disable them TQListView* currentView = item->listView(); if (currentView == groupView) { setDirectionButton1(Right); setDirectionButton2(Right); if (static_cast(item)->isOn()) { // already subscribed arrowBtn1->setEnabled(false); arrowBtn2->setEnabled(true); } else { // unsubscribed arrowBtn1->setEnabled(true); arrowBtn2->setEnabled(false); } } else if (currentView == subView) { // undo possible setDirectionButton1(Left); arrowBtn1->setEnabled(true); arrowBtn2->setEnabled(false); } else if (currentView == unsubView) { // undo possible setDirectionButton2(Left); arrowBtn1->setEnabled(false); arrowBtn2->setEnabled(true); } } //------------------------------------------------------------------------------ void KSubscription::slotButton1() { if (mDirButton1 == Right) { if (groupView->currentItem() && static_cast(groupView->currentItem())->isCheckItem()) { // activate GroupItem* item = static_cast(groupView->currentItem()); item->setOn(true); } } else { if (subView->currentItem()) { GroupItem* item = static_cast(subView->currentItem()); // get the corresponding item from the groupView TQListViewItem* listitem = getListItem(groupView, item->info()); if (listitem) { // deactivate GroupItem* chk = static_cast(listitem); chk->setOn(false); } } } } //------------------------------------------------------------------------------ void KSubscription::slotButton2() { if (mDirButton2 == Right) { if (groupView->currentItem() && static_cast(groupView->currentItem())->isCheckItem()) { // deactivate GroupItem* item = static_cast(groupView->currentItem()); item->setOn(false); } } else { if (unsubView->currentItem()) { GroupItem* item = static_cast(unsubView->currentItem()); // get the corresponding item from the groupView TQListViewItem* listitem = getListItem(groupView, item->info()); if (listitem) { // activate GroupItem* chk = static_cast(listitem); chk->setOn(true); } } } } //------------------------------------------------------------------------------ void KSubscription::slotCBToggled() { if (!noTreeCB->isChecked() && !newCB->isChecked() && !subCB->isChecked()) { restoreOriginalParent(); } // set items {in}visible filterChanged(groupView->firstChild()); emit listChanged(); } //------------------------------------------------------------------------------ void KSubscription::slotFilterTextChanged( const TQString & text ) { // remember is the items are open if (mLastText.isEmpty()) saveOpenStates(); if (!mLastText.isEmpty() && text.length() < mLastText.length()) { // reset restoreOriginalParent(); TQListViewItemIterator it(groupView); for ( ; it.current(); ++it) { it.current()->setVisible(true); it.current()->setEnabled(true); } } // set items {in}visible filterChanged(groupView->firstChild(), text); // restore the open-states if (text.isEmpty()) restoreOpenStates(); emit listChanged(); mLastText = text; } //------------------------------------------------------------------------------ void KSubscription::slotUpdateStatusLabel() { TQString text; if (mLoading) text = i18n("Loading... (1 matching)", "Loading... (%n matching)", activeItemCount()); else text = i18n("%1: (1 matching)", "%1: (%n matching)", activeItemCount()) .arg(account()->name()); leftLabel->setText(text); } //------------------------------------------------------------------------------ void KSubscription::slotLoadFolders() { enableButton(User1, false); mLoading = true; subView->clear(); unsubView->clear(); groupView->clear(); } #include "ksubscription.moc"