21
21
#include "mainwidget.h"
23
#include <QPrintDialog>
25
#include <QtGui/QAction>
26
#include <QtGui/QHBoxLayout>
27
#include <QtGui/QHeaderView>
28
#include <QtGui/QListView>
29
#include <QtGui/QSortFilterProxyModel>
30
#include <QtGui/QSplitter>
31
#include <QtGui/QStackedWidget>
32
#include <QtGui/QTextBrowser>
23
#include "contactswitcher.h"
24
#include "globalcontactmodel.h"
25
#include <kdescendantsproxymodel.h>
26
#include "modelcolumnmanager.h"
27
#include "printing/printingwizard.h"
28
#include "quicksearchwidget.h"
30
#include "xxportmanager.h"
33
#include "grantleecontactformatter.h"
34
#include "grantleecontactgroupformatter.h"
37
#include <akonadi/etmviewstatesaver.h>
34
38
#include <akonadi/collectionfilterproxymodel.h>
35
39
#include <akonadi/collectionmodel.h>
36
40
#include <akonadi/contact/contactdefaultactions.h>
37
41
#include <akonadi/contact/contacteditordialog.h>
38
42
#include <akonadi/contact/contactgroupeditordialog.h>
39
43
#include <akonadi/contact/contactgroupviewer.h>
44
#include <akonadi/contact/contactsfilterproxymodel.h>
45
#include <akonadi/contact/contactstreemodel.h>
40
46
#include <akonadi/contact/contactviewer.h>
47
#include <akonadi/contact/standardcontactactionmanager.h>
41
48
#include <akonadi/control.h>
42
49
#include <akonadi/entitymimetypefiltermodel.h>
43
50
#include <akonadi/entitytreeview.h>
49
56
#include <kactioncollection.h>
50
57
#include <kabc/addressee.h>
51
58
#include <kabc/contactgroup.h>
52
#include "kdescendantsproxymodel_p.h"
59
#include <kapplication.h>
60
#include <kcheckableproxymodel.h>
54
62
#include <klineedit.h>
55
63
#include <klocale.h>
56
64
#include <kselectionproxymodel.h>
65
#include <kstandarddirs.h>
66
#include <ktextbrowser.h>
57
67
#include <ktoggleaction.h>
58
68
#include <ktoolbar.h>
59
69
#include <kxmlguiwindow.h>
60
#include <libkdepim/contactstreemodel.h>
61
#include <libkdepim/contactsfilterproxymodel.h>
62
70
#include <libkdepim/uistatesaver.h>
64
#include "contactswitcher.h"
65
#include "globalcontactmodel.h"
66
#include "modelcolumnmanager.h"
67
#include "quicksearchwidget.h"
69
#include "standardcontactactionmanager.h"
70
#include "xxportmanager.h"
72
#include "printing/printingwizard.h"
72
#include <QtGui/QAction>
73
#include <QtGui/QHBoxLayout>
74
#include <QtGui/QHeaderView>
75
#include <QtGui/QListView>
76
#include <QtGui/QPrinter>
77
#include <QtGui/QPrintDialog>
78
#include <QtGui/QSortFilterProxyModel>
79
#include <QtGui/QSplitter>
80
#include <QtGui/QStackedWidget>
85
static bool isStructuralCollection( const Akonadi::Collection &collection )
87
QStringList mimeTypes;
88
mimeTypes << KABC::Addressee::mimeType() << KABC::ContactGroup::mimeType();
89
const QStringList collectionMimeTypes = collection.contentMimeTypes();
90
foreach ( const QString &mimeType, mimeTypes ) {
91
if ( collectionMimeTypes.contains( mimeType ) )
97
class StructuralCollectionsNotCheckableProxy : public KCheckableProxyModel {
99
StructuralCollectionsNotCheckableProxy(QObject* parent)
100
: KCheckableProxyModel(parent)
103
/* reimp */ QVariant data( const QModelIndex &index, int role ) const
105
if ( !index.isValid() )
108
if ( role == Qt::CheckStateRole ) {
109
// Don't show the checkbox if the collection can't contain incidences
110
const Akonadi::Collection collection = index.data( Akonadi::EntityTreeModel::CollectionRole ).value<Akonadi::Collection>();
111
if ( collection.isValid() && isStructuralCollection( collection ) ) {
115
return KCheckableProxyModel::data( index, role );
74
121
MainWidget::MainWidget( KXMLGUIClient *guiClient, QWidget *parent )
75
: QWidget( parent ), mAllContactsModel( 0 )
122
: QWidget( parent ), mAllContactsModel( 0 ), mXmlGuiClient( guiClient )
77
124
mXXPortManager = new XXPortManager( this );
107
159
* GlobalContactModel::instance(): The global contact model (contains collections and items)
108
160
* mCollectionTree: Filters out all items
161
* proxyModel: Allows the user to select collections by checkboxes
162
* selectionModel: Represents the selected collections that have been selected in
109
164
* mCollectionView: Shows the collections (address books) in a view
110
165
* selectionProxyModel: Filters out all collections and items that are no children
111
* of the collection currently selected in mCollectionView
166
* of the collections currently selected in selectionModel
112
167
* mItemTree: Filters out all collections
113
168
* mContactsFilterModel: Filters the contacts by the content of mQuickSearchWidget
114
169
* mItemView: Shows the items (contacts and contact groups) in a view
120
175
mCollectionTree = new Akonadi::EntityMimeTypeFilterModel( this );
176
mCollectionTree->setDynamicSortFilter( true );
177
mCollectionTree->setSortCaseSensitivity( Qt::CaseInsensitive );
121
178
mCollectionTree->setSourceModel( GlobalContactModel::instance()->model() );
122
179
mCollectionTree->addMimeTypeInclusionFilter( Akonadi::Collection::mimeType() );
123
180
mCollectionTree->setHeaderGroup( Akonadi::EntityTreeModel::CollectionTreeHeaders );
125
mXXPortManager->setItemModel( allContactsModel() );
182
mCollectionSelectionModel = new QItemSelectionModel( mCollectionTree );
183
StructuralCollectionsNotCheckableProxy *checkableProxyModel = new StructuralCollectionsNotCheckableProxy( this );
184
checkableProxyModel->setSelectionModel( mCollectionSelectionModel );
185
checkableProxyModel->setSourceModel( mCollectionTree );
127
mCollectionView->setModel( mCollectionTree );
187
mCollectionView->setModel( checkableProxyModel );
128
188
mCollectionView->setXmlGuiClient( guiClient );
129
189
mCollectionView->header()->setDefaultAlignment( Qt::AlignCenter );
130
190
mCollectionView->header()->setSortIndicatorShown( false );
132
192
connect( mCollectionView, SIGNAL( currentChanged( const Akonadi::Collection& ) ),
133
193
mXXPortManager, SLOT( setDefaultAddressBook( const Akonadi::Collection& ) ) );
135
KSelectionProxyModel *selectionProxyModel = new KSelectionProxyModel( mCollectionView->selectionModel(),
195
KSelectionProxyModel *selectionProxyModel = new KSelectionProxyModel( mCollectionSelectionModel,
137
197
selectionProxyModel->setSourceModel( GlobalContactModel::instance()->model() );
138
198
selectionProxyModel->setFilterBehavior( KSelectionProxyModel::ChildrenOfExactSelection );
142
202
mItemTree->addMimeTypeExclusionFilter( Akonadi::Collection::mimeType() );
143
203
mItemTree->setHeaderGroup( Akonadi::EntityTreeModel::ItemListHeaders );
145
mContactsFilterModel = new AkonadiFuture::ContactsFilterModel( this );
205
mContactsFilterModel = new Akonadi::ContactsFilterProxyModel( this );
146
206
mContactsFilterModel->setSourceModel( mItemTree );
147
207
connect( mQuickSearchWidget, SIGNAL( filterStringChanged( const QString& ) ),
148
208
mContactsFilterModel, SLOT( setFilterString( const QString& ) ) );
160
220
mXXPortManager->setSelectionModel( mItemView->selectionModel() );
222
mActionManager = new Akonadi::StandardContactActionManager( guiClient->actionCollection(), this );
223
mActionManager->setCollectionSelectionModel( mCollectionView->selectionModel() );
224
mActionManager->setItemSelectionModel( mItemView->selectionModel() );
225
mActionManager->createAllActions();
162
227
connect( mItemView, SIGNAL( currentChanged( const Akonadi::Item& ) ),
163
228
this, SLOT( itemSelected( const Akonadi::Item& ) ) );
164
229
connect( mItemView, SIGNAL( doubleClicked( const Akonadi::Item& ) ),
165
this, SLOT( editItem( const Akonadi::Item& ) ) );
230
mActionManager->action( Akonadi::StandardContactActionManager::EditItem ), SLOT( trigger() ) );
166
231
connect( mItemView->selectionModel(), SIGNAL( currentChanged( const QModelIndex&, const QModelIndex& ) ),
167
232
this, SLOT( itemSelectionChanged( const QModelIndex&, const QModelIndex& ) ) );
174
239
Akonadi::Control::widgetNeedsAkonadi( this );
176
mActionManager = new AkonadiFuture::StandardContactActionManager( guiClient->actionCollection(), this );
177
mActionManager->setCollectionSelectionModel( mCollectionView->selectionModel() );
178
mActionManager->setItemSelectionModel( mItemView->selectionModel() );
180
mActionManager->createAllActions();
182
connect( mActionManager->action( AkonadiFuture::StandardContactActionManager::CreateContact ), SIGNAL( triggered( bool ) ),
183
this, SLOT( newContact() ) );
184
connect( mActionManager->action( AkonadiFuture::StandardContactActionManager::CreateContactGroup ), SIGNAL( triggered( bool ) ),
185
this, SLOT( newGroup() ) );
186
connect( mActionManager, SIGNAL( editItem( const Akonadi::Item& ) ),
187
this, SLOT( editItem( const Akonadi::Item& ) ) );
189
241
mModelColumnManager = new ModelColumnManager( GlobalContactModel::instance()->model(), this );
190
242
mModelColumnManager->setWidget( mItemView->header() );
191
243
mModelColumnManager->load();
245
QMetaObject::invokeMethod( this, "delayedInit", Qt::QueuedConnection );
248
void MainWidget::delayedInit()
193
250
// restore previous state
195
252
const KConfigGroup group( Settings::self()->config(), "UiState_MainWidgetSplitter" );
199
256
const KConfigGroup group( Settings::self()->config(), "UiState_ContactView" );
200
257
KPIM::UiStateSaver::restoreState( mItemView, group );
203
const KConfigGroup group( Settings::self()->config(), "CollectionViewState" );
204
Akonadi::EntityTreeViewStateSaver *restorer = new Akonadi::EntityTreeViewStateSaver( mCollectionView );
205
restorer->restoreState( group );
208
const KConfigGroup group( Settings::self()->config(), "ItemViewState" );
209
Akonadi::EntityTreeViewStateSaver *restorer = new Akonadi::EntityTreeViewStateSaver( mItemView );
210
restorer->restoreState( group );
213
guiClient->actionCollection()->action( "options_show_simplegui" )->setChecked( Settings::self()->useSimpleMode() );
260
mXmlGuiClient->actionCollection()->action( "options_show_simplegui" )->setChecked( Settings::self()->useSimpleMode() );
262
connect( GlobalContactModel::instance()->model(), SIGNAL( modelAboutToBeReset() ), SLOT( saveState() ) );
263
connect( GlobalContactModel::instance()->model(), SIGNAL( modelReset() ), SLOT( restoreState() ) );
264
connect( kapp, SIGNAL( aboutToQuit() ), SLOT( saveState() ) );
216
269
MainWidget::~MainWidget()
218
271
mModelColumnManager->store();
221
KConfigGroup group( Settings::self()->config(), "CollectionViewState" );
222
Akonadi::EntityTreeViewStateSaver saver( mCollectionView );
223
saver.saveState( group );
227
KConfigGroup group( Settings::self()->config(), "ItemViewState" );
228
Akonadi::EntityTreeViewStateSaver saver( mItemView );
229
saver.saveState( group );
233
274
if ( !Settings::self()->useSimpleMode() ) {
234
275
// Do not save the splitter values when in simple mode, because we can't
235
276
// restore them correctly when switching back to normal mode
243
284
KPIM::UiStateSaver::saveState( mItemView, group );
246
289
Settings::self()->writeConfig();
292
void MainWidget::restoreState()
296
Akonadi::ETMViewStateSaver *saver = new Akonadi::ETMViewStateSaver;
297
saver->setView( mCollectionView );
299
const KConfigGroup group( Settings::self()->config(), "CollectionViewState" );
300
saver->restoreState( group );
305
Akonadi::ETMViewStateSaver *saver = new Akonadi::ETMViewStateSaver;
306
saver->setSelectionModel( mCollectionSelectionModel );
308
const KConfigGroup group( Settings::self()->config(), "CollectionViewCheckState" );
309
saver->restoreState( group );
314
Akonadi::ETMViewStateSaver *saver = new Akonadi::ETMViewStateSaver;
315
saver->setView( mItemView );
316
saver->setSelectionModel( mItemView->selectionModel() );
318
const KConfigGroup group( Settings::self()->config(), "ItemViewState" );
319
saver->restoreState( group );
323
void MainWidget::saveState()
327
Akonadi::ETMViewStateSaver saver;
328
saver.setView( mCollectionView );
330
KConfigGroup group( Settings::self()->config(), "CollectionViewState" );
331
saver.saveState( group );
337
Akonadi::ETMViewStateSaver saver;
338
saver.setSelectionModel( mCollectionSelectionModel );
340
KConfigGroup group( Settings::self()->config(), "CollectionViewCheckState" );
341
saver.saveState( group );
347
Akonadi::ETMViewStateSaver saver;
348
saver.setView( mItemView );
349
saver.setSelectionModel( mItemView->selectionModel() );
351
KConfigGroup group( Settings::self()->config(), "ItemViewState" );
352
saver.saveState( group );
249
357
void MainWidget::setupGui()
251
359
// the horizontal main layout
252
360
QHBoxLayout *layout = new QHBoxLayout( this );
361
layout->setMargin( 0 );
254
363
// The splitter that contains the three main parts of the gui
255
364
// - collection view on the left
306
415
Akonadi::ContactDefaultActions *actions = new Akonadi::ContactDefaultActions( this );
307
416
actions->connectToView( mContactDetails );
308
417
actions->connectToView( mContactGroupDetails );
419
#if 0 // disabled because Grantlee supports no i18n for KDE 4.6 yet
420
Akonadi::GrantleeContactFormatter *formatter =
421
new Akonadi::GrantleeContactFormatter( KStandardDirs::locate( "data", QLatin1String( "kaddressbook/viewertemplates/" ) ) );
423
mContactDetails->setContactFormatter( formatter );
425
Akonadi::GrantleeContactGroupFormatter *groupFormatter =
426
new Akonadi::GrantleeContactGroupFormatter( KStandardDirs::locate( "data", QLatin1String( "kaddressbook/viewertemplates/" ) ) );
428
mContactGroupDetails->setContactGroupFormatter( groupFormatter );
311
432
void MainWidget::setupActions( KActionCollection *collection )
326
447
action->setWhatsThis( i18n( "Select all contacts in the current address book view." ) );
327
448
connect( action, SIGNAL( triggered( bool ) ), mItemView, SLOT( selectAll() ) );
329
toggleAction = collection->add<KToggleAction>( "options_show_collectionview" );
330
toggleAction->setText( i18n( "Show Address Books View" ) );
331
toggleAction->setWhatsThis( i18n( "Toggle whether the address books view shall be visible." ) );
332
toggleAction->setCheckedState( KGuiItem( i18n( "Hide Address Books View" ) ) );
333
toggleAction->setChecked( true );
334
connect( toggleAction, SIGNAL( toggled( bool ) ), SLOT( setCollectionViewVisible( bool ) ) );
336
toggleAction = collection->add<KToggleAction>( "options_show_itemview" );
337
toggleAction->setText( i18n( "Show Contacts View" ) );
338
toggleAction->setWhatsThis( i18n( "Toggle whether the contacts view shall be visible." ) );
339
toggleAction->setCheckedState( KGuiItem( i18n( "Hide Contacts View" ) ) );
340
toggleAction->setChecked( true );
341
connect( toggleAction, SIGNAL( toggled( bool ) ), SLOT( setItemViewVisible( bool ) ) );
343
toggleAction = collection->add<KToggleAction>( "options_show_detailsview" );
344
toggleAction->setText( i18n( "Show Details View" ) );
345
toggleAction->setWhatsThis( i18n( "Toggle whether the details view shall be visible." ) );
346
toggleAction->setCheckedState( KGuiItem( i18n( "Hide Details View" ) ) );
347
toggleAction->setChecked( true );
348
connect( toggleAction, SIGNAL( toggled( bool ) ), SLOT( setDetailsViewVisible( bool ) ) );
350
450
toggleAction = collection->add<KToggleAction>( "options_show_simplegui" );
351
451
toggleAction->setText( i18n( "Show Simple View" ) );
352
452
action->setWhatsThis( i18n( "Show a simple mode of the address book view." ) );
417
517
QPrintDialog printDialog( &printer, this );
418
518
printDialog.setWindowTitle( i18n( "Print Contacts" ) );
419
if ( !printDialog.exec() )
519
if ( !printDialog.exec() ) //krazy:exclude=crashy
422
KABPrinting::PrintingWizard wizard( &printer, allContactsModel(),
423
mItemView->selectionModel(), this );
522
KABPrinting::PrintingWizard wizard( &printer, mItemView->selectionModel(), this );
424
523
wizard.setDefaultAddressBook( currentAddressBook() );
429
528
void MainWidget::newContact()
431
Akonadi::ContactEditorDialog dlg( Akonadi::ContactEditorDialog::CreateMode, this );
432
dlg.setDefaultAddressBook( currentAddressBook() );
530
mActionManager->action( Akonadi::StandardContactActionManager::CreateContact )->trigger();
437
533
void MainWidget::newGroup()
439
Akonadi::ContactGroupEditorDialog dlg( Akonadi::ContactGroupEditorDialog::CreateMode, this );
440
dlg.setDefaultAddressBook( currentAddressBook() );
445
void MainWidget::editItem( const Akonadi::Item &reference )
447
if ( Akonadi::MimeTypeChecker::isWantedItem( reference, KABC::Addressee::mimeType() ) ) {
448
editContact( reference );
449
} else if ( Akonadi::MimeTypeChecker::isWantedItem( reference, KABC::ContactGroup::mimeType() ) ) {
450
editGroup( reference );
535
mActionManager->action( Akonadi::StandardContactActionManager::CreateContactGroup )->trigger();
491
void MainWidget::setCollectionViewVisible( bool visible )
493
mCollectionView->setVisible( visible );
496
void MainWidget::setItemViewVisible( bool visible )
498
mItemView->setVisible( visible );
501
void MainWidget::setDetailsViewVisible( bool visible )
503
mDetailsPane->setVisible( visible );
506
575
void MainWidget::setSimpleGuiMode( bool on )
508
577
mCollectionView->setVisible( !on );
510
579
mDetailsPane->setVisible( true );
511
580
mContactSwitcher->setVisible( on );
513
// If simple mode is on, we use a model that provides all available contacts
514
// in a list, otherwise we use the model that provides all contacts of the
515
// currently selected collection.
517
mContactsFilterModel->setSourceModel( allContactsModel() );
519
mContactsFilterModel->setSourceModel( mItemTree );
521
if ( mCollectionView->model() )
522
mCollectionView->setCurrentIndex( mCollectionView->model()->index( 0, 0 ) );
524
582
if ( mItemView->model() )
525
583
mItemView->setCurrentIndex( mItemView->model()->index( 0, 0 ) );
527
585
Settings::self()->setUseSimpleMode( on );
530
void MainWidget::editContact( const Akonadi::Item &contact )
532
Akonadi::ContactEditorDialog dlg( Akonadi::ContactEditorDialog::EditMode, this );
533
dlg.setContact( contact );
537
void MainWidget::editGroup( const Akonadi::Item &group )
539
Akonadi::ContactGroupEditorDialog dlg( Akonadi::ContactGroupEditorDialog::EditMode, this );
540
dlg.setContactGroup( group );
544
588
Akonadi::Collection MainWidget::currentAddressBook() const
546
590
if ( mCollectionView->selectionModel() && mCollectionView->selectionModel()->hasSelection() ) {