2
This file is part of libkdepim.
4
Copyright (C) 2002 Carsten Burghardt <burghardt@kde.org>
6
This library is free software; you can redistribute it and/or
7
modify it under the terms of the GNU Library General Public
8
License version 2 as published by the Free Software Foundation.
10
This library is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Library General Public License for more details.
15
You should have received a copy of the GNU Library General Public License
16
along with this library; see the file COPYING.LIB. If not, write to
17
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18
Boston, MA 02110-1301, USA.
21
#include "ksubscription.h"
25
#include <KIconLoader>
30
#include <QApplication>
34
#include <QPushButton>
35
#include <QToolButton>
36
#include <QGridLayout>
37
#include <QHBoxLayout>
38
#include <QVBoxLayout>
39
#include <QHeaderView>
43
//=============================================================================
45
KGroupInfo::KGroupInfo( const QString &name, const QString &description,
46
bool newGroup, bool subscribed,
47
Status status, const QString &path )
48
: name( name ), description( description ),
49
newGroup( newGroup ), subscribed( subscribed ),
50
status( status ), path( path )
54
//-----------------------------------------------------------------------------
55
bool KGroupInfo::operator== ( const KGroupInfo &gi2 )
57
return name == gi2.name;
60
//-----------------------------------------------------------------------------
61
bool KGroupInfo::operator< ( const KGroupInfo &gi2 )
63
return name < gi2.name;
66
//=============================================================================
68
GroupItem::GroupItem( QTreeWidget *v, const KGroupInfo &gi, KSubscription *browser,
70
: QTreeWidgetItem( v, customType ),
71
mInfo( gi ), mBrowser( browser ), mIsCheckItem( isCheckItem ),
72
mIgnoreStateChange( false )
74
setText( 0, gi.name );
76
setCheckState( 0, Qt::Unchecked );
77
setFlags( flags() | Qt::ItemIsUserCheckable );
78
mLastCheckState = isOn();
80
if ( treeWidget()->columnCount() > 1 ) {
84
connect( treeWidget(), SIGNAL( itemChanged ( QTreeWidgetItem *, int ) ),
85
this, SLOT( stateChange( QTreeWidgetItem* ) ) );
88
//-----------------------------------------------------------------------------
89
GroupItem::GroupItem( QTreeWidgetItem *i, const KGroupInfo &gi,
90
KSubscription *browser, bool isCheckItem )
91
: QTreeWidgetItem( i, customType ),
92
mInfo( gi ), mBrowser( browser ), mIsCheckItem( isCheckItem ),
93
mIgnoreStateChange( false )
95
setText( 0, gi.name );
97
setCheckState( 0, Qt::Unchecked );
98
setFlags( flags() | Qt::ItemIsUserCheckable );
99
mLastCheckState = isOn();
101
if ( treeWidget()->columnCount() > 1 ) {
104
connect( treeWidget(), SIGNAL( itemChanged ( QTreeWidgetItem *, int ) ),
105
this, SLOT( stateChange( QTreeWidgetItem* ) ) );
108
//-----------------------------------------------------------------------------
109
void GroupItem::setInfo( KGroupInfo info )
112
setText( 0, mInfo.name );
113
if ( treeWidget()->columnCount() > 1 ) {
118
//-----------------------------------------------------------------------------
119
void GroupItem::setDescription()
121
setText( 1, mInfo.description );
124
//-----------------------------------------------------------------------------
125
void GroupItem::setOn( bool on )
127
if ( mBrowser->isLoading() ) {
128
// set this only if we're loading/creating items
129
// otherwise changes are only permanent when the dialog is saved
130
mInfo.subscribed = on;
132
if ( isCheckItem() ) {
133
setCheckState( 0, on ? Qt::Checked : Qt::Unchecked );
137
//------------------------------------------------------------------------------
138
bool GroupItem::isOn() const
140
if ( !isCheckItem() )
143
return checkState( 0 ) == Qt::Checked;
146
//------------------------------------------------------------------------------
147
void GroupItem::stateChange( QTreeWidgetItem* item )
152
// delegate to parent
153
if ( !mIgnoreStateChange && mLastCheckState != isOn() ) {
154
mBrowser->changeItemState( this, isOn() );
157
mLastCheckState = isOn();
160
//------------------------------------------------------------------------------
161
void GroupItem::setVisible( bool b )
166
if ( isCheckItem() ) {
167
bool setInvisible = true;
169
while ( QTreeWidgetItem *item = QTreeWidgetItem::child( childIndex++ ) ) {
170
if ( !( item->isHidden() ) ) {
171
// item has a visible child
172
setInvisible = false;
175
if ( setInvisible ) {
178
treeWidget()->expandItem( this );
181
// non-checkable item
182
typedef QPair<QTreeWidgetItem*,bool> ItemWithVisibility;
183
QList< ItemWithVisibility > moveItems;
185
while ( QTreeWidgetItem *item = QTreeWidgetItem::child( childIndex++ ) ) {
186
if ( static_cast<GroupItem*>( item )->isCheckItem() ) {
187
// remember the items
188
moveItems.append( ItemWithVisibility( item, item->isHidden() ) );
191
foreach( const ItemWithVisibility &item, moveItems ) {
192
// move the checkitem to top
193
QTreeWidgetItem *parent = item.first->parent();
195
parent->removeChild( item.first );
197
treeWidget()->insertTopLevelItem( 0, item.first );
198
item.first->setHidden( item.second );
205
//=============================================================================
207
KSubscription::KSubscription( QWidget *parent, const QString &caption,
208
KAccount *acct, KDialog::ButtonCodes buttons,
209
const QString &user1, bool descriptionColumn )
213
setCaption( caption );
214
setButtons( buttons | Help | Ok | Cancel );
215
setDefaultButton( Ok );
216
setButtonText( User1, i18n( "Reload &List" ) );
217
setButtonText( User2, user1 );
219
showButtonSeparator( true );
222
setAttribute( Qt::WA_DeleteOnClose );
225
page = new QWidget( this );
226
setMainWidget( page );
230
"<p>" + i18n( "Manage which mail folders you want to see in your folder view" ) + "</p>",
233
filterEdit = new KLineEdit( page );
234
QLabel *l = new QLabel( i18n( "S&earch:" ), page );
235
l->setBuddy( filterEdit );
236
filterEdit->setClearButtonShown( true );
239
noTreeCB = new QCheckBox( i18n( "Disable &tree view" ), page );
240
noTreeCB->setChecked( false );
241
subCB = new QCheckBox( i18n( "&Subscribed only" ), page );
242
subCB->setChecked( false );
243
newCB = new QCheckBox( i18n( "&New only" ), page );
244
newCB->setChecked( false );
246
KSeparator *sep = new KSeparator( Qt::Horizontal, page );
251
leftLabel = new QLabel( i18n( "Loading..." ), page );
252
rightLabel = new QLabel( i18n( "Current changes:" ), page );
253
leftLabel->setFont( fnt );
254
rightLabel->setFont( fnt );
257
pmRight = KIcon( "go-next" );
258
pmLeft = KIcon( "go-previous" );
260
arrowBtn1 = new QPushButton( page );
261
arrowBtn1->setEnabled( false );
262
arrowBtn2 = new QPushButton( page );
263
arrowBtn2->setEnabled( false );
264
arrowBtn1->setIcon( pmRight );
265
arrowBtn2->setIcon( pmRight );
266
arrowBtn1->setFixedSize( 35, 30 );
267
arrowBtn2->setFixedSize( 35, 30 );
270
groupView = new QTreeWidget( page );
271
groupView->setRootIsDecorated( true );
272
groupView->setHeaderLabel( i18nc( "subscription name", "Name" ) );
273
groupView->setAllColumnsShowFocus( true );
274
groupView->setAlternatingRowColors( true );
275
if ( descriptionColumn ) {
276
groupView->setHeaderLabel( i18nc( "subscription description", "Description" ) );
280
QGridLayout *topL = new QGridLayout( page );
281
topL->setMargin( 0 );
282
topL->setSpacing( KDialog::spacingHint() );
284
QHBoxLayout *filterL = new QHBoxLayout();
285
filterL->setSpacing( KDialog::spacingHint() );
287
QVBoxLayout *arrL = new QVBoxLayout();
288
arrL->setSpacing( KDialog::spacingHint() );
290
listL = new QGridLayout();
291
listL->setSpacing( KDialog::spacingHint() );
293
topL->addWidget( comment, 0, 0 );
294
topL->addLayout( filterL, 1, 0 );
295
topL->addWidget( sep, 2, 0 );
296
topL->addLayout( listL, 3, 0 );
298
filterL->addWidget( l );
299
filterL->addWidget( filterEdit, 1 );
300
filterL->addWidget( noTreeCB );
301
filterL->addWidget( subCB );
302
filterL->addWidget( newCB );
304
listL->addWidget( leftLabel, 0, 0 );
305
listL->addWidget( rightLabel, 0, 2 );
306
listL->addWidget( groupView, 1, 0 );
307
listL->addLayout( arrL, 1, 1 );
308
listL->setRowStretch( 1, 1 );
309
listL->setColumnStretch( 0, 5 );
310
listL->setColumnStretch( 2, 2 );
312
arrL->addWidget( arrowBtn1, Qt::AlignCenter );
313
arrL->addWidget( arrowBtn2, Qt::AlignCenter );
316
subView = new QTreeWidget( page );
317
subView->setHeaderLabel( i18n( "Subscribe To" ) );
318
unsubView = new QTreeWidget( page );
319
unsubView->setHeaderLabel( i18n( "Unsubscribe From" ) );
321
QVBoxLayout *protL = new QVBoxLayout();
322
protL->setSpacing( 3 );
324
listL->addLayout( protL, 1, 2 );
325
protL->addWidget( subView );
326
protL->addWidget( unsubView );
328
// disable some widgets as long we're loading
329
enableButton( User1, false );
330
enableButton( User2, false );
331
newCB->setEnabled( false );
332
noTreeCB->setEnabled( false );
333
subCB->setEnabled( false );
335
filterEdit->setFocus();
338
connect( groupView, SIGNAL( itemClicked( QTreeWidgetItem *, int ) ),
339
this, SLOT(slotChangeButtonState(QTreeWidgetItem*)));
340
connect( subView, SIGNAL( itemClicked( QTreeWidgetItem *, int ) ),
341
this, SLOT(slotChangeButtonState(QTreeWidgetItem*)));
342
connect( unsubView, SIGNAL( itemClicked( QTreeWidgetItem *, int ) ),
343
this, SLOT(slotChangeButtonState(QTreeWidgetItem*)));
346
connect( arrowBtn1, SIGNAL(clicked()), SLOT(slotButton1()));
347
connect( arrowBtn2, SIGNAL(clicked()), SLOT(slotButton2()));
348
connect( this, SIGNAL(user1Clicked()), SLOT(slotLoadFolders()));
350
// connect checkboxes
351
connect( subCB, SIGNAL(clicked()), SLOT(slotCBToggled()));
352
connect( newCB, SIGNAL(clicked()), SLOT(slotCBToggled()));
353
connect( noTreeCB, SIGNAL(clicked()), SLOT(slotCBToggled()));
356
connect( filterEdit, SIGNAL(textChanged(const QString&)),
357
SLOT(slotFilterTextChanged(const QString&)));
360
connect( this, SIGNAL(listChanged()), SLOT(slotUpdateStatusLabel()));
363
//-----------------------------------------------------------------------------
364
KSubscription::~KSubscription()
368
//-----------------------------------------------------------------------------
369
void KSubscription::setStartItem( const KGroupInfo &info )
371
QTreeWidgetItemIterator it( groupView );
373
for ( ; *it; ++it ) {
374
if ( static_cast<GroupItem*>( *it )->info() == info ) {
375
( *it )->setSelected( true );
376
groupView->expandItem( *it );
381
//-----------------------------------------------------------------------------
382
void KSubscription::removeListItem( QTreeWidget *view, const KGroupInfo &gi )
387
QTreeWidgetItemIterator it( view );
389
for ( ; *it; ++it ) {
390
if ( static_cast<GroupItem*>( *it )->info() == gi ) {
393
QTreeWidgetItem *itemToDelete = *it;
394
QTreeWidgetItem *itemParent = itemToDelete->parent();
396
delete itemParent->takeChild( itemParent->indexOfChild( itemToDelete ) );
398
QTreeWidget *treeWidget = itemToDelete->treeWidget();
399
delete treeWidget->takeTopLevelItem( treeWidget->indexOfTopLevelItem( itemToDelete ) );
404
if ( view == groupView ) {
409
//-----------------------------------------------------------------------------
410
QTreeWidgetItem* KSubscription::getListItem( QTreeWidget *view, const KGroupInfo &gi )
415
QTreeWidgetItemIterator it( view );
417
for ( ; *it; ++it ) {
418
if ( static_cast<GroupItem*>( *it )->info() == gi ) {
425
//-----------------------------------------------------------------------------
426
bool KSubscription::itemInListView( QTreeWidget *view, const KGroupInfo &gi )
431
QTreeWidgetItemIterator it( view );
433
for ( ; *it; ++it ) {
434
if ( static_cast<GroupItem*>( *it )->info() == gi ) {
442
//------------------------------------------------------------------------------
443
void KSubscription::setDirectionButton1( Direction dir )
447
arrowBtn1->setIcon( pmLeft );
449
arrowBtn1->setIcon( pmRight );
453
//------------------------------------------------------------------------------
454
void KSubscription::setDirectionButton2( Direction dir )
458
arrowBtn2->setIcon( pmLeft );
460
arrowBtn2->setIcon( pmRight );
464
//------------------------------------------------------------------------------
465
void KSubscription::changeItemState( GroupItem *item, bool on )
467
// is this a checkable item
468
if ( !item->isCheckItem() ) {
472
// if we're currently loading the items ignore changes
477
if ( !itemInListView( unsubView, item->info() ) ) {
478
QTreeWidgetItem *p = item->QTreeWidgetItem::parent();
480
// make sure all parents are subscribed
481
GroupItem *pi = static_cast<GroupItem*>( p );
482
if ( pi->isCheckItem() && !pi->isOn() ) {
483
pi->setIgnoreStateChange( true );
485
pi->setIgnoreStateChange( false );
486
new GroupItem( subView, pi->info(), this );
490
new GroupItem( subView, item->info(), this );
492
// eventually remove it from the other listview
493
removeListItem( unsubView, item->info() );
495
if ( !itemInListView( subView, item->info() ) ) {
496
new GroupItem( unsubView, item->info(), this );
498
// eventually remove it from the other listview
499
removeListItem( subView, item->info() );
501
// update the buttons
502
slotChangeButtonState( item );
505
//------------------------------------------------------------------------------
506
void KSubscription::filterChanged( QTreeWidgetItem *item, const QString &text )
508
if ( !item && groupView ) {
509
item = groupView->topLevelItem( 0 );
515
QTreeWidgetItem *parent = item->parent();
517
parent = groupView->invisibleRootItem();
519
int childIndex = parent->indexOfChild( item );
520
while( ( item = parent->child( childIndex++ ) ) )
522
if ( item->childCount() > 0 ) {
524
filterChanged( item->child( 0 ), text );
527
GroupItem *gr = static_cast<GroupItem*>( item );
528
if ( subCB->isChecked() || newCB->isChecked() || !text.isEmpty() || noTreeCB->isChecked() ) {
530
if ( subCB->isChecked() &&
531
( !gr->isCheckItem() || ( gr->isCheckItem() && !gr->info().subscribed ) ) ) {
533
gr->setVisible( false );
536
if ( newCB->isChecked() &&
537
( !gr->isCheckItem() || ( gr->isCheckItem() && !gr->info().newGroup ) ) ) {
539
gr->setVisible( false );
542
if ( !text.isEmpty() && gr->text( 0 ).indexOf( text, 0, Qt::CaseInsensitive ) == -1 ) {
544
gr->setVisible( false );
547
if ( noTreeCB->isChecked() && !gr->isCheckItem() ) {
549
gr->setVisible( false );
553
gr->setVisible( true );
556
gr->setVisible( true );
561
//------------------------------------------------------------------------------
562
int KSubscription::activeItemCount()
564
QTreeWidgetItemIterator it( groupView );
567
for ( ; *it; ++it ) {
568
if ( static_cast<GroupItem*>( *it )->isCheckItem() &&
569
!( ( *it )->isHidden() ) ) {
577
//------------------------------------------------------------------------------
578
void KSubscription::restoreOriginalParent()
580
QList<QTreeWidgetItem*> move;
581
QTreeWidgetItemIterator it( groupView );
582
for ( ; *it; ++it ) {
583
QTreeWidgetItem *origParent =
584
static_cast<GroupItem*>( *it )->originalParent();
585
if ( origParent && origParent != ( *it )->parent() ) {
586
// remember this to avoid messing up the iterator
590
foreach( QTreeWidgetItem *item, move ) {
591
// restore the original parent
592
QTreeWidgetItem *origParent =
593
static_cast<GroupItem*>( item )->originalParent();
594
groupView->takeTopLevelItem( groupView->indexOfTopLevelItem( item ) );
595
origParent->insertChild( 0, item );
599
//-----------------------------------------------------------------------------
600
void KSubscription::saveOpenStates()
602
QTreeWidgetItemIterator it( groupView );
604
for ( ; *it; ++it ) {
605
static_cast<GroupItem*>( *it )->setLastOpenState( groupView->isItemExpanded( *it ) );
609
//-----------------------------------------------------------------------------
610
void KSubscription::restoreOpenStates()
612
QTreeWidgetItemIterator it( groupView );
614
for ( ; *it; ++it ) {
615
bool wasExpanded = static_cast<GroupItem*>( *it )->lastOpenState();
617
groupView->expandItem( *it );
619
groupView->collapseItem( *it );
623
//-----------------------------------------------------------------------------
624
void KSubscription::slotLoadingComplete()
628
enableButton( User1, true );
629
enableButton( User2, true );
630
newCB->setEnabled( true );
631
noTreeCB->setEnabled( true );
632
subCB->setEnabled( true );
634
// remember the correct parent
635
QTreeWidgetItemIterator it( groupView );
636
for ( ; *it; ++it ) {
637
static_cast<GroupItem*>( *it )->setOriginalParent( ( *it )->parent() );
643
//------------------------------------------------------------------------------
644
void KSubscription::slotChangeButtonState( QTreeWidgetItem *item )
647
( item->treeWidget() == groupView && !static_cast<GroupItem*>(item)->isCheckItem() ) ) {
648
// disable and return
649
arrowBtn1->setEnabled( false );
650
arrowBtn2->setEnabled( false );
653
// set the direction of the buttons and enable/disable them
654
QTreeWidget *currentView = item->treeWidget();
655
if ( currentView == groupView ) {
656
setDirectionButton1( Right );
657
setDirectionButton2( Right );
658
if ( static_cast<GroupItem*>(item)->isOn() ) {
659
// already subscribed
660
arrowBtn1->setEnabled( false );
661
arrowBtn2->setEnabled( true );
664
arrowBtn1->setEnabled( true );
665
arrowBtn2->setEnabled( false );
667
} else if ( currentView == subView ) {
669
setDirectionButton1( Left );
671
arrowBtn1->setEnabled( true );
672
arrowBtn2->setEnabled( false );
673
} else if ( currentView == unsubView ) {
675
setDirectionButton2( Left );
677
arrowBtn1->setEnabled( false );
678
arrowBtn2->setEnabled( true );
682
//------------------------------------------------------------------------------
683
void KSubscription::slotButton1()
685
if ( mDirButton1 == Right ) {
686
if ( groupView->currentItem() &&
687
static_cast<GroupItem*>( groupView->currentItem() )->isCheckItem() ) {
689
GroupItem *item = static_cast<GroupItem*>( groupView->currentItem() );
693
if ( subView->currentItem() ) {
694
GroupItem *item = static_cast<GroupItem*>( subView->currentItem() );
695
// get the corresponding item from the groupView
696
QTreeWidgetItem *listitem = getListItem( groupView, item->info() );
699
GroupItem *chk = static_cast<GroupItem*>( listitem );
706
//------------------------------------------------------------------------------
707
void KSubscription::slotButton2()
709
if ( mDirButton2 == Right ) {
710
if ( groupView->currentItem() &&
711
static_cast<GroupItem*>( groupView->currentItem() )->isCheckItem() ) {
713
GroupItem *item = static_cast<GroupItem*>( groupView->currentItem() );
714
item->setOn( false );
717
if ( unsubView->currentItem() ) {
718
GroupItem *item = static_cast<GroupItem*>( unsubView->currentItem() );
719
// get the corresponding item from the groupView
720
QTreeWidgetItem *listitem = getListItem( groupView, item->info() );
723
GroupItem *chk = static_cast<GroupItem*>( listitem );
730
//------------------------------------------------------------------------------
731
void KSubscription::slotCBToggled()
733
if ( !noTreeCB->isChecked() && !newCB->isChecked() && !subCB->isChecked() ) {
734
restoreOriginalParent();
736
// set items {in}visible
737
filterChanged( groupView->topLevelItem( 0 ) );
741
//------------------------------------------------------------------------------
742
void KSubscription::slotFilterTextChanged( const QString &text )
744
// remember is the items are open
745
if ( mLastText.isEmpty() ) {
749
if ( !mLastText.isEmpty() && text.length() < mLastText.length() ) {
751
restoreOriginalParent();
752
QTreeWidgetItemIterator it( groupView );
753
for ( ; *it; ++it ) {
754
( *it )->setHidden( false );
757
// set items {in}visible
758
filterChanged( groupView->topLevelItem( 0 ), text );
759
// restore the open-states
760
if ( text.isEmpty() ) {
768
//------------------------------------------------------------------------------
769
void KSubscription::slotUpdateStatusLabel()
773
text = i18np( "Loading... (1 matching)", "Loading... (%1 matching)", activeItemCount() );
775
text = i18np( "%2: (1 matching)", "%2: (%1 matching)", activeItemCount(), account()->name() );
778
leftLabel->setText( text );
781
//------------------------------------------------------------------------------
782
void KSubscription::slotLoadFolders()
784
enableButton( User1, false );