You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdepim/libkdepim/ksubscription.cpp

794 lines
22 KiB

/*
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 <qlayout.h>
#include <qtimer.h>
#include <qlabel.h>
#include <qpushbutton.h>
#include <qheader.h>
#include <qtoolbutton.h>
#include <kseparator.h>
#include <kapplication.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kdebug.h>
#include <klineedit.h>
//=============================================================================
KGroupInfo::KGroupInfo(const QString &name, const QString &description,
bool newGroup, bool subscribed,
Status status, QString 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( QListView *v, const KGroupInfo &gi, KSubscription* browser,
bool isCheckItem )
: QCheckListItem( v, gi.name, isCheckItem ? CheckBox : CheckBoxController ),
mInfo( gi ), mBrowser( browser ), mIsCheckItem( isCheckItem ),
mIgnoreStateChange( false )
{
if (listView()->columns() > 1)
setDescription();
}
//-----------------------------------------------------------------------------
GroupItem::GroupItem( QListViewItem *i, const KGroupInfo &gi, KSubscription* browser,
bool isCheckItem )
: QCheckListItem( 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())
QCheckListItem::setOn(on);
}
//------------------------------------------------------------------------------
void GroupItem::stateChange( bool on )
{
// delegate to parent
if ( !mIgnoreStateChange )
mBrowser->changeItemState(this, on);
}
//------------------------------------------------------------------------------
void GroupItem::setVisible( bool b )
{
if (b)
{
QListViewItem::setVisible(b);
setEnabled(true);
}
else
{
if (isCheckItem())
{
bool setInvisible = true;
for (QListViewItem * lvchild = firstChild(); lvchild != 0;
lvchild = lvchild->nextSibling())
{
if (lvchild->isVisible()) // item has a visible child
setInvisible = false;
}
if (setInvisible)
QListViewItem::setVisible(b);
else
{
// leave it visible so that children remain visible
setOpen(true);
setEnabled(false);
}
}
else
{
// non-checkable item
QPtrList<QListViewItem> moveItems;
for (QListViewItem * lvchild = firstChild(); lvchild != 0;
lvchild = lvchild->nextSibling())
{
if (static_cast<GroupItem*>(lvchild)->isCheckItem())
{
// remember the items
moveItems.append(lvchild);
}
}
QPtrListIterator<QListViewItem> it( moveItems );
for ( ; it.current(); ++it)
{
// move the checkitem to top
QListViewItem* parent = it.current()->parent();
if (parent) parent->takeItem(it.current());
listView()->insertItem(it.current());
}
QListViewItem::setVisible(false);
}
}
}
//-----------------------------------------------------------------------------
void GroupItem::paintCell( QPainter * p, const QColorGroup & cg,
int column, int width, int align )
{
if (mIsCheckItem)
return QCheckListItem::paintCell( p, cg, column, width, align );
else
return QListViewItem::paintCell( p, cg, column, width, align );
}
//-----------------------------------------------------------------------------
void GroupItem::paintFocus( QPainter * p, const QColorGroup & cg,
const QRect & r )
{
if (mIsCheckItem)
QCheckListItem::paintFocus(p, cg, r);
else
QListViewItem::paintFocus(p, cg, r);
}
//-----------------------------------------------------------------------------
int GroupItem::width( const QFontMetrics& fm, const QListView* lv, int column) const
{
if (mIsCheckItem)
return QCheckListItem::width(fm, lv, column);
else
return QListViewItem::width(fm, lv, column);
}
//-----------------------------------------------------------------------------
void GroupItem::setup()
{
if (mIsCheckItem)
QCheckListItem::setup();
else
QListViewItem::setup();
}
//=============================================================================
KSubscription::KSubscription( QWidget *parent, const QString &caption,
KAccount * acct, int buttons, const QString &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 QWidget(this);
setMainWidget(page);
QLabel *comment = new QLabel("<p>"+
i18n("Manage which mail folders you want to see in your folder view") + "</p>", page);
QToolButton *clearButton = new QToolButton( page );
clearButton->setIconSet( KGlobal::iconLoader()->loadIconSet(
KApplication::reverseLayout() ? "clear_left":"locationbar_erase", KIcon::Small, 0 ) );
filterEdit = new KLineEdit(page);
QLabel *l = new QLabel(filterEdit,i18n("S&earch:"), page);
connect( clearButton, SIGNAL( clicked() ), filterEdit, SLOT( clear() ) );
// checkboxes
noTreeCB = new QCheckBox(i18n("Disable &tree view"), page);
noTreeCB->setChecked(false);
subCB = new QCheckBox(i18n("&Subscribed only"), page);
subCB->setChecked(false);
newCB = new QCheckBox(i18n("&New only"), page);
newCB->setChecked(false);
KSeparator *sep = new KSeparator(KSeparator::HLine, page);
// init the labels
QFont fnt = font();
fnt.setBold(true);
leftLabel = new QLabel(i18n("Loading..."), page);
rightLabel = new QLabel(i18n("Current changes:"), page);
leftLabel->setFont(fnt);
rightLabel->setFont(fnt);
// icons
pmRight = BarIconSet("forward");
pmLeft = BarIconSet("back");
arrowBtn1 = new QPushButton(page);
arrowBtn1->setEnabled(false);
arrowBtn2 = new QPushButton(page);
arrowBtn2->setEnabled(false);
arrowBtn1->setIconSet(pmRight);
arrowBtn2->setIconSet(pmRight);
arrowBtn1->setFixedSize(35,30);
arrowBtn2->setFixedSize(35,30);
// the main listview
groupView = new QListView(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
QGridLayout *topL = new QGridLayout(page,4,1,0, KDialog::spacingHint());
QHBoxLayout *filterL = new QHBoxLayout(KDialog::spacingHint());
QVBoxLayout *arrL = new QVBoxLayout(KDialog::spacingHint());
listL = new QGridLayout(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 QListView(page);
subView->addColumn(i18n("Subscribe To"));
subView->header()->setStretchEnabled(true, 0);
unsubView = new QListView(page);
unsubView->addColumn(i18n("Unsubscribe From"));
unsubView->header()->setStretchEnabled(true, 0);
QVBoxLayout *protL = new QVBoxLayout(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, SIGNAL(clicked(QListViewItem *)),
this, SLOT(slotChangeButtonState(QListViewItem*)));
connect(subView, SIGNAL(clicked(QListViewItem *)),
this, SLOT(slotChangeButtonState(QListViewItem*)));
connect(unsubView, SIGNAL(clicked(QListViewItem *)),
this, SLOT(slotChangeButtonState(QListViewItem*)));
// connect buttons
connect(arrowBtn1, SIGNAL(clicked()), SLOT(slotButton1()));
connect(arrowBtn2, SIGNAL(clicked()), SLOT(slotButton2()));
connect(this, SIGNAL(user1Clicked()), SLOT(slotLoadFolders()));
// connect checkboxes
connect(subCB, SIGNAL(clicked()), SLOT(slotCBToggled()));
connect(newCB, SIGNAL(clicked()), SLOT(slotCBToggled()));
connect(noTreeCB, SIGNAL(clicked()), SLOT(slotCBToggled()));
// connect textfield
connect(filterEdit, SIGNAL(textChanged(const QString&)),
SLOT(slotFilterTextChanged(const QString&)));
// update status
connect(this, SIGNAL(listChanged()), SLOT(slotUpdateStatusLabel()));
}
//-----------------------------------------------------------------------------
KSubscription::~KSubscription()
{
}
//-----------------------------------------------------------------------------
void KSubscription::setStartItem( const KGroupInfo &info )
{
QListViewItemIterator it(groupView);
for ( ; it.current(); ++it)
{
if (static_cast<GroupItem*>(it.current())->info() == info)
{
it.current()->setSelected(true);
it.current()->setOpen(true);
}
}
}
//-----------------------------------------------------------------------------
void KSubscription::removeListItem( QListView *view, const KGroupInfo &gi )
{
if(!view) return;
QListViewItemIterator it(view);
for ( ; it.current(); ++it)
{
if (static_cast<GroupItem*>(it.current())->info() == gi)
{
delete it.current();
break;
}
}
if (view == groupView)
emit listChanged();
}
//-----------------------------------------------------------------------------
QListViewItem* KSubscription::getListItem( QListView *view, const KGroupInfo &gi )
{
if(!view) return 0;
QListViewItemIterator it(view);
for ( ; it.current(); ++it)
{
if (static_cast<GroupItem*>(it.current())->info() == gi)
return (it.current());
}
return 0;
}
//-----------------------------------------------------------------------------
bool KSubscription::itemInListView( QListView *view, const KGroupInfo &gi )
{
if(!view) return false;
QListViewItemIterator it(view);
for ( ; it.current(); ++it)
if (static_cast<GroupItem*>(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()))
{
QListViewItem *p = item->parent();
while (p)
{
// make sure all parents are subscribed
GroupItem* pi = static_cast<GroupItem*>(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( QListViewItem* item, const QString & text )
{
if ( !item && groupView )
item = groupView->firstChild();
if ( !item )
return;
do
{
if ( item->firstChild() ) // recursive descend
filterChanged(item->firstChild(), text);
GroupItem* gr = static_cast<GroupItem*>(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()
{
QListViewItemIterator it(groupView);
uint count = 0;
for ( ; it.current(); ++it)
{
if (static_cast<GroupItem*>(it.current())->isCheckItem() &&
it.current()->isVisible() && it.current()->isEnabled())
count++;
}
return count;
}
//------------------------------------------------------------------------------
void KSubscription::restoreOriginalParent()
{
QPtrList<QListViewItem> move;
QListViewItemIterator it(groupView);
for ( ; it.current(); ++it)
{
QListViewItem* origParent = static_cast<GroupItem*>(it.current())->
originalParent();
if (origParent && origParent != it.current()->parent())
{
// remember this to avoid messing up the iterator
move.append(it.current());
}
}
QPtrListIterator<QListViewItem> it2( move );
for ( ; it2.current(); ++it2)
{
// restore the original parent
QListViewItem* origParent = static_cast<GroupItem*>(it2.current())->
originalParent();
groupView->takeItem(it2.current());
origParent->insertItem(it2.current());
}
}
//-----------------------------------------------------------------------------
void KSubscription::saveOpenStates()
{
QListViewItemIterator it(groupView);
for ( ; it.current(); ++it)
{
static_cast<GroupItem*>(it.current())->setLastOpenState(
it.current()->isOpen() );
}
}
//-----------------------------------------------------------------------------
void KSubscription::restoreOpenStates()
{
QListViewItemIterator it(groupView);
for ( ; it.current(); ++it)
{
it.current()->setOpen(
static_cast<GroupItem*>(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
QListViewItemIterator it(groupView);
for ( ; it.current(); ++it)
{
static_cast<GroupItem*>(it.current())->
setOriginalParent( it.current()->parent() );
}
emit listChanged();
}
//------------------------------------------------------------------------------
void KSubscription::slotChangeButtonState( QListViewItem *item )
{
if (!item ||
(item->listView() == groupView &&
!static_cast<GroupItem*>(item)->isCheckItem()))
{
// disable and return
arrowBtn1->setEnabled(false);
arrowBtn2->setEnabled(false);
return;
}
// set the direction of the buttons and enable/disable them
QListView* currentView = item->listView();
if (currentView == groupView)
{
setDirectionButton1(Right);
setDirectionButton2(Right);
if (static_cast<GroupItem*>(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<GroupItem*>(groupView->currentItem())->isCheckItem())
{
// activate
GroupItem* item = static_cast<GroupItem*>(groupView->currentItem());
item->setOn(true);
}
}
else {
if (subView->currentItem())
{
GroupItem* item = static_cast<GroupItem*>(subView->currentItem());
// get the corresponding item from the groupView
QListViewItem* listitem = getListItem(groupView, item->info());
if (listitem)
{
// deactivate
GroupItem* chk = static_cast<GroupItem*>(listitem);
chk->setOn(false);
}
}
}
}
//------------------------------------------------------------------------------
void KSubscription::slotButton2()
{
if (mDirButton2 == Right)
{
if (groupView->currentItem() &&
static_cast<GroupItem*>(groupView->currentItem())->isCheckItem())
{
// deactivate
GroupItem* item = static_cast<GroupItem*>(groupView->currentItem());
item->setOn(false);
}
}
else {
if (unsubView->currentItem())
{
GroupItem* item = static_cast<GroupItem*>(unsubView->currentItem());
// get the corresponding item from the groupView
QListViewItem* listitem = getListItem(groupView, item->info());
if (listitem)
{
// activate
GroupItem* chk = static_cast<GroupItem*>(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 QString & text )
{
// remember is the items are open
if (mLastText.isEmpty())
saveOpenStates();
if (!mLastText.isEmpty() && text.length() < mLastText.length())
{
// reset
restoreOriginalParent();
QListViewItemIterator 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()
{
QString 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"