french -> French
[kdepim.git] / kaddressbook / mainwidget.cpp
blob557c39072c2d3d620a7d1f76b5f12e2cb30df5c6
1 /*
2 This file is part of KAddressBook.
4 Copyright (c) 2007 Tobias Koenig <tokoe@kde.org>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "mainwidget.h"
22 #include "contactswitcher.h"
23 #include "globalcontactmodel.h"
24 #include "modelcolumnmanager.h"
25 #include "printing/printingwizard.h"
26 #include "merge/searchduplicatecontactwizard.h"
27 #include "merge/mergecontactsdialog.h"
28 #include "quicksearchwidget.h"
29 #include "settings.h"
30 #include "xxportmanager.h"
31 #include "utils.h"
32 #include "kaddressbookadaptor.h"
35 #include "kaddressbookgrantlee/formatter/grantleecontactformatter.h"
36 #include "kaddressbookgrantlee/formatter/grantleecontactgroupformatter.h"
37 #include "grantleetheme/grantleethememanager.h"
38 #include "grantleetheme/globalsettings_base.h"
40 #include "libkdepim/misc/uistatesaver.h"
42 #include <pimcommon/acl/collectionaclpage.h>
43 #include <pimcommon/acl/imapaclattribute.h>
44 #include "pimcommon/nepomukdebug/nepomukdebugdialog.h"
47 #include <Akonadi/ETMViewStateSaver>
48 #include <Akonadi/CollectionFilterProxyModel>
49 #include <Akonadi/CollectionModel>
50 #include <Akonadi/Control>
51 #include <Akonadi/EntityMimeTypeFilterModel>
52 #include <Akonadi/EntityTreeView>
53 #include <Akonadi/ItemView>
54 #include <Akonadi/MimeTypeChecker>
55 #include <Akonadi/AttributeFactory>
56 #include <Akonadi/CollectionPropertiesDialog>
57 #include <Akonadi/Contact/ContactDefaultActions>
58 #include <Akonadi/Contact/ContactGroupEditorDialog>
59 #include <Akonadi/Contact/ContactGroupViewer>
60 #include <Akonadi/Contact/ContactsFilterProxyModel>
61 #include <Akonadi/Contact/ContactsTreeModel>
62 #include <Akonadi/Contact/ContactViewer>
63 #include <Akonadi/Contact/StandardContactActionManager>
65 #include <KABC/Addressee>
66 #include <KABC/ContactGroup>
68 #include <KCmdLineArgs>
69 #include <KAction>
70 #include <KActionCollection>
71 #include <KActionMenu>
72 #include <KApplication>
73 #include <KCheckableProxyModel>
74 #include <kdescendantsproxymodel.h> //krazy:exclude=camelcase TODO wait for kdelibs4.9
75 #include <KIcon>
76 #include <KLineEdit>
77 #include <KLocale>
78 #include <KSelectionProxyModel>
79 #include <KStandardDirs>
80 #include <KTextBrowser>
81 #include <KToggleAction>
82 #include <KToolBar>
83 #include <KXmlGuiWindow>
84 #include <KCMultiDialog>
85 #include <kdeprintdialog.h>
86 #include <KPrintPreview>
88 #include <QAction>
89 #include <QActionGroup>
90 #include <QHBoxLayout>
91 #include <QHeaderView>
92 #include <QListView>
93 #include <QPrinter>
94 #include <QPrintDialog>
95 #include <QSortFilterProxyModel>
96 #include <QSplitter>
97 #include <QStackedWidget>
98 #include <QDBusConnection>
100 namespace {
101 static bool isStructuralCollection( const Akonadi::Collection &collection )
103 QStringList mimeTypes;
104 mimeTypes << KABC::Addressee::mimeType() << KABC::ContactGroup::mimeType();
105 const QStringList collectionMimeTypes = collection.contentMimeTypes();
106 foreach ( const QString &mimeType, mimeTypes ) {
107 if ( collectionMimeTypes.contains( mimeType ) ) {
108 return false;
111 return true;
114 class StructuralCollectionsNotCheckableProxy : public KCheckableProxyModel
116 public:
117 StructuralCollectionsNotCheckableProxy( QObject *parent )
118 : KCheckableProxyModel( parent )
122 /* reimp */QVariant data( const QModelIndex &index, int role ) const
124 if ( !index.isValid() ) {
125 return QVariant();
128 if ( role == Qt::CheckStateRole ) {
129 // Don't show the checkbox if the collection can't contain incidences
130 const Akonadi::Collection collection =
131 index.data( Akonadi::EntityTreeModel::CollectionRole ).value<Akonadi::Collection>();
132 if ( collection.isValid() && isStructuralCollection( collection ) ) {
133 return QVariant();
136 return KCheckableProxyModel::data( index, role );
142 MainWidget::MainWidget( KXMLGUIClient *guiClient, QWidget *parent )
143 : QWidget( parent ), mAllContactsModel( 0 ), mXmlGuiClient( guiClient ), mGrantleeThemeManager(0)
146 (void) new KaddressbookAdaptor( this );
147 QDBusConnection::sessionBus().registerObject(QLatin1String("/KAddressBook"), this);
150 mXXPortManager = new XXPortManager( this );
151 Akonadi::AttributeFactory::registerAttribute<PimCommon::ImapAclAttribute>();
153 setupGui();
154 setupActions( guiClient->actionCollection() );
157 * The item models, proxies and views have the following structure:
159 * mItemView
162 * mContactsFilterModel
165 * mItemTree
168 * | mAllContactsModel
169 * | ^
170 * | |
171 * mCollectionView selectionProxyModel descendantsModel
172 * ^ ^ ^ ^
173 * | | | |
174 * | selectionModel | |
175 * | | | |
176 * proxyModel ---------' | |
177 * ^ | |
178 * | | |
179 * mCollectionTree | |
180 * ^ | |
181 * | | _______________/
182 * \ / /
183 * GlobalContactModel::instance()
186 * GlobalContactModel::instance(): The global contact model (contains collections and items)
187 * mCollectionTree: Filters out all items
188 * proxyModel: Allows the user to select collections by checkboxes
189 * selectionModel: Represents the selected collections that have been
190 * selected in proxyModel
191 * mCollectionView: Shows the collections (address books) in a view
192 * selectionProxyModel: Filters out all collections and items that are no children
193 * of the collections currently selected in selectionModel
194 * mItemTree: Filters out all collections
195 * mContactsFilterModel: Filters the contacts by the content of mQuickSearchWidget
196 * mItemView: Shows the items (contacts and contact groups) in a view
198 * descendantsModel: Flattens the item/collection tree to a list
199 * mAllContactsModel: Provides a list of all available contacts from all
200 * address books
203 mCollectionTree = new Akonadi::EntityMimeTypeFilterModel( this );
204 mCollectionTree->setDynamicSortFilter( true );
205 mCollectionTree->setSortCaseSensitivity( Qt::CaseInsensitive );
206 mCollectionTree->setSourceModel( GlobalContactModel::instance()->model() );
207 mCollectionTree->addMimeTypeInclusionFilter( Akonadi::Collection::mimeType() );
208 mCollectionTree->setHeaderGroup( Akonadi::EntityTreeModel::CollectionTreeHeaders );
210 mCollectionSelectionModel = new QItemSelectionModel( mCollectionTree );
211 StructuralCollectionsNotCheckableProxy *checkableProxyModel =
212 new StructuralCollectionsNotCheckableProxy( this );
213 checkableProxyModel->setSelectionModel( mCollectionSelectionModel );
214 checkableProxyModel->setSourceModel( mCollectionTree );
216 mCollectionView->setModel( checkableProxyModel );
217 mCollectionView->setXmlGuiClient( guiClient );
218 mCollectionView->header()->setDefaultAlignment( Qt::AlignCenter );
219 mCollectionView->header()->setSortIndicatorShown( false );
221 connect( mCollectionView, SIGNAL(currentChanged(Akonadi::Collection)),
222 mXXPortManager, SLOT(setDefaultAddressBook(Akonadi::Collection)) );
224 KSelectionProxyModel *selectionProxyModel =
225 new KSelectionProxyModel( mCollectionSelectionModel, this );
226 selectionProxyModel->setSourceModel( GlobalContactModel::instance()->model() );
227 selectionProxyModel->setFilterBehavior( KSelectionProxyModel::ChildrenOfExactSelection );
229 mItemTree = new Akonadi::EntityMimeTypeFilterModel( this );
230 mItemTree->setSourceModel( selectionProxyModel );
231 mItemTree->addMimeTypeExclusionFilter( Akonadi::Collection::mimeType() );
232 mItemTree->setHeaderGroup( Akonadi::EntityTreeModel::ItemListHeaders );
234 mContactsFilterModel = new Akonadi::ContactsFilterProxyModel( this );
235 mContactsFilterModel->setSourceModel( mItemTree );
236 connect( mQuickSearchWidget, SIGNAL(filterStringChanged(QString)),
237 mContactsFilterModel, SLOT(setFilterString(QString)) );
238 connect( mQuickSearchWidget, SIGNAL(filterStringChanged(QString)),
239 this, SLOT(selectFirstItem()) );
240 connect( mQuickSearchWidget, SIGNAL(arrowDownKeyPressed()),
241 mItemView, SLOT(setFocus()) );
243 mItemView->setModel( mContactsFilterModel );
244 mItemView->setXmlGuiClient( guiClient );
245 mItemView->setSelectionMode( QAbstractItemView::ExtendedSelection );
246 mItemView->setRootIsDecorated( false );
247 mItemView->header()->setDefaultAlignment( Qt::AlignCenter );
249 mXXPortManager->setSelectionModel( mItemView->selectionModel() );
251 mActionManager = new Akonadi::StandardContactActionManager( guiClient->actionCollection(), this );
252 mActionManager->setCollectionSelectionModel( mCollectionView->selectionModel() );
253 mActionManager->setItemSelectionModel( mItemView->selectionModel() );
255 QList<Akonadi::StandardActionManager::Type> standardActions;
256 standardActions << Akonadi::StandardActionManager::CreateCollection
257 << Akonadi::StandardActionManager::CopyCollections
258 << Akonadi::StandardActionManager::DeleteCollections
259 << Akonadi::StandardActionManager::SynchronizeCollections
260 << Akonadi::StandardActionManager::CollectionProperties
261 << Akonadi::StandardActionManager::CopyItems
262 << Akonadi::StandardActionManager::Paste
263 << Akonadi::StandardActionManager::DeleteItems
264 << Akonadi::StandardActionManager::CutItems
265 << Akonadi::StandardActionManager::CutCollections
266 << Akonadi::StandardActionManager::CreateResource
267 << Akonadi::StandardActionManager::DeleteResources
268 << Akonadi::StandardActionManager::ResourceProperties
269 << Akonadi::StandardActionManager::SynchronizeResources
270 << Akonadi::StandardActionManager::SynchronizeCollectionsRecursive;
272 Q_FOREACH( Akonadi::StandardActionManager::Type standardAction, standardActions ) {
273 mActionManager->createAction( standardAction );
276 QList<Akonadi::StandardContactActionManager::Type> contactActions;
277 contactActions << Akonadi::StandardContactActionManager::CreateContact
278 << Akonadi::StandardContactActionManager::CreateContactGroup
279 << Akonadi::StandardContactActionManager::EditItem;
281 Q_FOREACH( Akonadi::StandardContactActionManager::Type contactAction, contactActions ) {
282 mActionManager->createAction( contactAction );
284 static bool pageRegistered = false;
286 if ( !pageRegistered ) {
287 Akonadi::CollectionPropertiesDialog::registerPage( new PimCommon::CollectionAclPageFactory );
288 pageRegistered = true;
291 const QStringList pages =
292 QStringList() << QLatin1String( "Akonadi::CollectionGeneralPropertiesPage" )
293 << QLatin1String( "Akonadi::CachePolicyPage" )
294 << QLatin1String( "PimCommon::CollectionAclPage" );
296 mActionManager->setCollectionPropertiesPageNames( pages );
298 connect( mItemView, SIGNAL(currentChanged(Akonadi::Item)),
299 this, SLOT(itemSelected(Akonadi::Item)) );
300 connect( mItemView, SIGNAL(doubleClicked(Akonadi::Item)),
301 mActionManager->action( Akonadi::StandardContactActionManager::EditItem ),
302 SLOT(trigger()) );
303 connect( mItemView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
304 this, SLOT(itemSelectionChanged(QModelIndex,QModelIndex)) );
306 // show the contact details view as default
307 mDetailsViewStack->setCurrentWidget( mContactDetails );
309 mContactSwitcher->setView( mItemView );
311 Akonadi::Control::widgetNeedsAkonadi( this );
313 mModelColumnManager = new ModelColumnManager( GlobalContactModel::instance()->model(), this );
314 mModelColumnManager->setWidget( mItemView->header() );
315 mModelColumnManager->load();
317 QMetaObject::invokeMethod( this, "delayedInit", Qt::QueuedConnection );
320 void MainWidget::configure()
322 KCMultiDialog dlg( this );
323 dlg.addModule( QLatin1String("akonadicontact_actions.desktop") );
324 dlg.addModule( QLatin1String("kcmldap.desktop") );
326 dlg.exec();
329 bool MainWidget::handleCommandLine()
331 bool doneSomething = false;
332 KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
333 if ( args->isSet( "import" ) ) {
334 for ( int i = 0; i < args->count(); ++i ) {
335 importManager()->importFile( args->url( i ) );
338 args->clear();
339 return doneSomething;
343 XXPortManager *MainWidget::importManager() const
345 return mXXPortManager;
348 void MainWidget::delayedInit()
350 setViewMode(0); // get default from settings
352 const KConfigGroup group( Settings::self()->config(), "UiState_ContactView" );
353 KPIM::UiStateSaver::restoreState( mItemView, group );
355 #if defined(HAVE_PRISON)
356 mXmlGuiClient->
357 actionCollection()->
358 action( QLatin1String("options_show_qrcodes") )->setChecked( showQRCodes() );
359 #endif
361 connect( GlobalContactModel::instance()->model(), SIGNAL(modelAboutToBeReset()),
362 SLOT(saveState()) );
363 connect( GlobalContactModel::instance()->model(), SIGNAL(modelReset()),
364 SLOT(restoreState()) );
365 connect( kapp, SIGNAL(aboutToQuit()), SLOT(saveState()) );
367 restoreState();
370 MainWidget::~MainWidget()
372 mModelColumnManager->store();
373 saveSplitterStates();
375 KConfigGroup group( Settings::self()->config(), "UiState_ContactView" );
376 KPIM::UiStateSaver::saveState( mItemView, group );
378 saveState();
379 delete mGrantleeThemeManager;
381 Settings::self()->writeConfig();
384 void MainWidget::restoreState()
386 // collection view
388 Akonadi::ETMViewStateSaver *saver = new Akonadi::ETMViewStateSaver;
389 saver->setView( mCollectionView );
391 const KConfigGroup group( Settings::self()->config(), "CollectionViewState" );
392 saver->restoreState( group );
395 // collection view
397 Akonadi::ETMViewStateSaver *saver = new Akonadi::ETMViewStateSaver;
398 saver->setSelectionModel( mCollectionSelectionModel );
400 const KConfigGroup group( Settings::self()->config(), "CollectionViewCheckState" );
401 saver->restoreState( group );
404 // item view
406 Akonadi::ETMViewStateSaver *saver = new Akonadi::ETMViewStateSaver;
407 saver->setView( mItemView );
408 saver->setSelectionModel( mItemView->selectionModel() );
410 const KConfigGroup group( Settings::self()->config(), "ItemViewState" );
411 saver->restoreState( group );
415 void MainWidget::saveState()
417 // collection view
419 Akonadi::ETMViewStateSaver saver;
420 saver.setView( mCollectionView );
422 KConfigGroup group( Settings::self()->config(), "CollectionViewState" );
423 saver.saveState( group );
424 group.sync();
427 // collection view
429 Akonadi::ETMViewStateSaver saver;
430 saver.setSelectionModel( mCollectionSelectionModel );
432 KConfigGroup group( Settings::self()->config(), "CollectionViewCheckState" );
433 saver.saveState( group );
434 group.sync();
437 // item view
439 Akonadi::ETMViewStateSaver saver;
440 saver.setView( mItemView );
441 saver.setSelectionModel( mItemView->selectionModel() );
443 KConfigGroup group( Settings::self()->config(), "ItemViewState" );
444 saver.saveState( group );
445 group.sync();
449 void MainWidget::setupGui()
451 // the horizontal main layout
452 QHBoxLayout *layout = new QHBoxLayout( this );
453 layout->setMargin( 0 );
455 // Splitter 1 contains the two main parts of the GUI:
456 // - collection and item view splitter 2 on the left (see below)
457 // - details pane on the right, that contains
458 // - details view stack on the top
459 // - contact switcher at the bottom
460 mMainWidgetSplitter1 = new QSplitter(Qt::Horizontal);
461 mMainWidgetSplitter1->setObjectName( QLatin1String("MainWidgetSplitter1") );
462 layout->addWidget( mMainWidgetSplitter1 );
464 // Splitter 2 contains the remaining parts of the GUI:
465 // - collection view on either the left or the top
466 // - item view on either the right or the bottom
467 // The orientation of this splitter is changed for either
468 // a three or two column view; in simple mode it is hidden.
469 mMainWidgetSplitter2 = new QSplitter(Qt::Vertical);
470 mMainWidgetSplitter2->setObjectName( QLatin1String("MainWidgetSplitter2") );
471 mMainWidgetSplitter1->addWidget( mMainWidgetSplitter2 );
473 // the collection view
474 mCollectionView = new Akonadi::EntityTreeView();
475 mMainWidgetSplitter2->addWidget( mCollectionView );
477 // the items view
478 mItemView = new Akonadi::EntityTreeView();
479 mItemView->setObjectName( QLatin1String("ContactView") );
480 mItemView->setDefaultPopupMenu( QLatin1String( "akonadi_itemview_contextmenu" ) );
481 mItemView->setAlternatingRowColors(true);
482 mMainWidgetSplitter2->addWidget( mItemView );
484 // the details pane that contains the details view stack and contact switcher
485 mDetailsPane = new QWidget;
486 mMainWidgetSplitter1->addWidget( mDetailsPane );
488 mMainWidgetSplitter1->setStretchFactor( 1, 9 ); // maximum width for detail
489 mMainWidgetSplitter2->setStretchFactor( 1, 9 ); // for intuitive resizing
490 mMainWidgetSplitter2->setChildrenCollapsible(false);
491 mMainWidgetSplitter1->setChildrenCollapsible(false);
493 QVBoxLayout *detailsPaneLayout = new QVBoxLayout( mDetailsPane );
494 detailsPaneLayout->setMargin( 0 );
496 // the details view stack
497 mDetailsViewStack = new QStackedWidget();
498 detailsPaneLayout->addWidget( mDetailsViewStack );
500 // the details widget for contacts
501 mContactDetails = new Akonadi::ContactViewer( mDetailsViewStack );
502 mDetailsViewStack->addWidget( mContactDetails );
504 // the details widget for contact groups
505 mContactGroupDetails = new Akonadi::ContactGroupViewer( mDetailsViewStack );
506 mDetailsViewStack->addWidget( mContactGroupDetails );
508 // the details widget for empty items
509 mEmptyDetails = new KTextBrowser( mDetailsViewStack );
510 mDetailsViewStack->addWidget( mEmptyDetails );
512 // the contact switcher for the simple gui mode
513 mContactSwitcher = new ContactSwitcher;
514 detailsPaneLayout->addWidget( mContactSwitcher );
515 mContactSwitcher->setVisible( false );
517 // the quick search widget which is embedded in the toolbar action
518 mQuickSearchWidget = new QuickSearchWidget;
520 // setup the default actions
521 Akonadi::ContactDefaultActions *actions = new Akonadi::ContactDefaultActions( this );
522 actions->connectToView( mContactDetails );
523 actions->connectToView( mContactGroupDetails );
524 mFormatter = new KAddressBookGrantlee::GrantleeContactFormatter;
526 mContactDetails->setContactFormatter( mFormatter );
528 mGroupFormatter = new KAddressBookGrantlee::GrantleeContactGroupFormatter;
530 mContactGroupDetails->setContactGroupFormatter( mGroupFormatter );
533 void MainWidget::setupActions( KActionCollection *collection )
535 mGrantleeThemeManager = new GrantleeTheme::GrantleeThemeManager(QString::fromLatin1( "theme.desktop" ), collection, QLatin1String("kaddressbook/viewertemplates/"));
536 mGrantleeThemeManager->setDownloadNewStuffConfigFile(QLatin1String("kaddressbook_themes.knsrc"));
537 connect(mGrantleeThemeManager, SIGNAL(grantleeThemeSelected()), this, SLOT(slotGrantleeThemeSelected()));
538 connect(mGrantleeThemeManager, SIGNAL(updateThemes()), this, SLOT(slotGrantleeThemesUpdated()));
541 KActionMenu *themeMenu = new KActionMenu(i18n("&Themes"), this);
542 collection->addAction(QLatin1String("theme_menu"), themeMenu );
544 initGrantleeThemeName();
545 QActionGroup *group = new QActionGroup( this );
546 mGrantleeThemeManager->setThemeMenu(themeMenu);
547 mGrantleeThemeManager->setActionGroup(group);
549 KAction *action = KStandardAction::print( this, SLOT(print()), collection );
550 action->setWhatsThis(
551 i18nc( "@info:whatsthis",
552 "Print the complete address book or a selected number of contacts." ) );
554 if(KPrintPreview::isAvailable())
555 KStandardAction::printPreview( this, SLOT(printPreview()), collection );
557 action = collection->addAction( QLatin1String("quick_search") );
558 action->setText( i18n( "Quick search" ) );
559 action->setDefaultWidget( mQuickSearchWidget );
561 action = collection->addAction( QLatin1String("select_all") );
562 action->setText( i18n( "Select All" ) );
563 action->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_A ) );
564 action->setWhatsThis( i18n( "Select all contacts in the current address book view." ) );
565 connect( action, SIGNAL(triggered(bool)), mItemView, SLOT(selectAll()) );
567 #if defined(HAVE_PRISON)
568 KToggleAction *qrtoggleAction;
569 qrtoggleAction = collection->add<KToggleAction>( QLatin1String("options_show_qrcodes") );
570 qrtoggleAction->setText( i18n( "Show QR Codes" ) );
571 qrtoggleAction->setWhatsThis( i18n( "Show QR Codes in the contact." ) );
572 connect( qrtoggleAction, SIGNAL(toggled(bool)), SLOT(setQRCodeShow(bool)) );
573 #endif
575 mViewModeGroup = new QActionGroup( this );
577 KAction *act = new KAction( i18nc( "@action:inmenu", "Simple (one column)" ), mViewModeGroup );
578 act->setCheckable( true );
579 act->setData( 1 );
580 act->setShortcut( QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_1 ) );
581 act->setWhatsThis( i18n( "Show a simple mode of the address book view." ) );
582 collection->addAction( QLatin1String("view_mode_simple"), act );
584 act = new KAction( i18nc( "@action:inmenu", "Two Columns" ), mViewModeGroup );
585 act->setCheckable( true );
586 act->setData( 2 );
587 act->setShortcut( QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_2 ) );
588 collection->addAction( QLatin1String("view_mode_2columns"), act );
590 act = new KAction( i18nc( "@action:inmenu", "Three Columns" ), mViewModeGroup );
591 act->setCheckable( true );
592 act->setData( 3 );
593 act->setShortcut( QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_3 ) );
594 collection->addAction( QLatin1String("view_mode_3columns"), act );
596 connect( mViewModeGroup, SIGNAL(triggered(QAction*)), SLOT(setViewMode(QAction*)) );
598 // import actions
599 action = collection->addAction( QLatin1String("file_import_vcard") );
600 action->setText( i18n( "Import vCard..." ) );
601 action->setWhatsThis( i18n( "Import contacts from a vCard file." ) );
602 mXXPortManager->addImportAction( action, QLatin1String("vcard30") );
604 action = collection->addAction( QLatin1String("file_import_csv") );
605 action->setText( i18n( "Import CSV file..." ) );
606 action->setWhatsThis( i18n( "Import contacts from a file in comma separated value format." ) );
607 mXXPortManager->addImportAction( action, QLatin1String("csv") );
609 action = collection->addAction( QLatin1String("file_import_ldif") );
610 action->setText( i18n( "Import LDIF file..." ) );
611 action->setWhatsThis( i18n( "Import contacts from an LDIF file." ) );
612 mXXPortManager->addImportAction( action, QLatin1String("ldif") );
614 action = collection->addAction( QLatin1String("file_import_ldap") );
615 action->setText( i18n( "Import From LDAP server..." ) );
616 action->setWhatsThis( i18n( "Import contacts from an LDAP server." ) );
617 mXXPortManager->addImportAction( action, QLatin1String("ldap") );
619 action = collection->addAction( QLatin1String("file_import_gmx") );
620 action->setText( i18n( "Import GMX file..." ) );
621 action->setWhatsThis( i18n( "Import contacts from a GMX address book file." ) );
622 mXXPortManager->addImportAction( action, QLatin1String("gmx") );
624 // export actions
625 action = collection->addAction( QLatin1String("file_export_vcard30") );
626 action->setText( i18n( "Export vCard 3.0..." ) );
627 action->setWhatsThis( i18n( "Export contacts to a vCard 3.0 file." ) );
628 mXXPortManager->addExportAction( action, QLatin1String("vcard30") );
630 action = collection->addAction( QLatin1String("file_export_vcard21") );
631 action->setText( i18n( "Export vCard 2.1..." ) );
632 action->setWhatsThis( i18n( "Export contacts to a vCard 2.1 file." ) );
633 mXXPortManager->addExportAction( action, QLatin1String("vcard21") );
635 action = collection->addAction( QLatin1String("file_export_csv") );
636 action->setText( i18n( "Export CSV file..." ) );
637 action->setWhatsThis( i18n( "Export contacts to a file in comma separated value format." ) );
638 mXXPortManager->addExportAction( action, QLatin1String("csv") );
640 action = collection->addAction( QLatin1String("file_export_ldif") );
641 action->setText( i18n( "Export LDIF file..." ) );
642 action->setWhatsThis( i18n( "Export contacts to an LDIF file." ) );
643 mXXPortManager->addExportAction( action, QLatin1String("ldif") );
645 action = collection->addAction( QLatin1String("file_export_gmx") );
646 action->setText( i18n( "Export GMX file..." ) );
647 action->setWhatsThis( i18n( "Export contacts to a GMX address book file." ) );
648 mXXPortManager->addExportAction( action, QLatin1String("gmx") );
650 KToggleAction *actTheme = mGrantleeThemeManager->actionForTheme();
651 if (actTheme)
652 actTheme->setChecked(true);
654 action = collection->addAction( QLatin1String("merge_contacts") );
655 action->setText( i18n( "Merge Contacts..." ) );
656 connect( action, SIGNAL(triggered(bool)), this, SLOT(mergeContacts()) );
658 action = collection->addAction( QLatin1String("search_duplicate_contacts") );
659 action->setText( i18n( "Search Duplicate Contacts..." ) );
660 connect( action, SIGNAL(triggered(bool)), this, SLOT(slotSearchDuplicateContacts()) );
662 #if !defined(NDEBUG)
663 action = collection->addAction( QLatin1String("debug_nepomuk") );
664 action->setText( i18n( "Debug Nepomuk..." ) );
665 connect( action, SIGNAL(triggered(bool)), this, SLOT(slotDebugNepomuk()) );
666 #endif
669 void MainWidget::printPreview()
671 QPrinter printer;
672 printer.setDocName( i18n( "Address Book" ) );
673 printer.setOutputFileName( Settings::self()->defaultFileName() );
674 printer.setOutputFormat( QPrinter::PdfFormat );
675 printer.setCollateCopies( true );
677 KPrintPreview previewdlg( &printer, this );
678 KABPrinting::PrintingWizard wizard( &printer, mItemView->selectionModel(), this );
679 wizard.setDefaultAddressBook( currentAddressBook() );
681 const int result = wizard.exec();
682 if (result)
683 previewdlg.exec();
686 void MainWidget::print()
688 QPrinter printer;
689 printer.setDocName( i18n( "Address Book" ) );
690 printer.setOutputFileName( Settings::self()->defaultFileName() );
691 printer.setOutputFormat( QPrinter::PdfFormat );
692 printer.setCollateCopies( true );
694 QPrintDialog printDialog(KdePrint::createPrintDialog(&printer));
696 printDialog.setWindowTitle( i18n( "Print Contacts" ) );
697 if ( !printDialog.exec() ) { //krazy:exclude=crashy
698 return;
701 KABPrinting::PrintingWizard wizard( &printer, mItemView->selectionModel(), this );
702 wizard.setDefaultAddressBook( currentAddressBook() );
704 wizard.exec(); //krazy:exclude=crashy
706 Settings::self()->setDefaultFileName( printer.outputFileName() );
707 Settings::self()->setPrintingStyle( wizard.printingStyle() );
708 Settings::self()->setSortOrder( wizard.sortOrder() );
711 void MainWidget::newContact()
713 mActionManager->action( Akonadi::StandardContactActionManager::CreateContact )->trigger();
716 void MainWidget::newGroup()
718 mActionManager->action( Akonadi::StandardContactActionManager::CreateContactGroup )->trigger();
722 * Depending on the mime type of the selected item, this method
723 * brings up the right view on the detail view stack and sets the
724 * selected item on it.
726 void MainWidget::itemSelected( const Akonadi::Item &item )
728 if ( Akonadi::MimeTypeChecker::isWantedItem( item, KABC::Addressee::mimeType() ) ) {
729 mDetailsViewStack->setCurrentWidget( mContactDetails );
730 mContactDetails->setContact( item );
731 } else if ( Akonadi::MimeTypeChecker::isWantedItem( item, KABC::ContactGroup::mimeType() ) ) {
732 mDetailsViewStack->setCurrentWidget( mContactGroupDetails );
733 mContactGroupDetails->setContactGroup( item );
738 * Catch when the selection has gone ( e.g. an empty address book has been selected )
739 * clear the details view in this case.
741 void MainWidget::itemSelectionChanged( const QModelIndex &current, const QModelIndex & )
743 if ( !current.isValid() ) {
744 mDetailsViewStack->setCurrentWidget( mEmptyDetails );
748 void MainWidget::selectFirstItem()
750 // Whenever the quick search has changed, we select the first item
751 // in the item view, so that the detailsview is updated
752 if ( mItemView && mItemView->selectionModel() ) {
753 mItemView->selectionModel()->setCurrentIndex( mItemView->model()->index( 0, 0 ),
754 QItemSelectionModel::Rows |
755 QItemSelectionModel::ClearAndSelect );
759 bool MainWidget::showQRCodes()
761 #if defined(HAVE_PRISON)
762 KConfig config( QLatin1String( "akonadi_contactrc" ) );
763 KConfigGroup group( &config, QLatin1String( "View" ) );
764 return group.readEntry( "QRCodes", true );
765 #else
766 return true;
767 #endif
770 void MainWidget::setQRCodeShow( bool on )
772 #if defined(HAVE_PRISON)
773 // must write the configuration setting first before updating the view.
774 KConfig config( QLatin1String( "akonadi_contactrc" ) );
775 KConfigGroup group( &config, QLatin1String( "View" ) );
776 group.writeEntry( "QRCodes", on );
777 if ( mItemView->model() ) {
778 mItemView->setCurrentIndex( mItemView->model()->index( 0, 0 ) );
780 #else
781 Q_UNUSED( on );
782 #endif
785 Akonadi::Collection MainWidget::currentAddressBook() const
787 if ( mCollectionView->selectionModel() && mCollectionView->selectionModel()->hasSelection() ) {
788 const QModelIndex index = mCollectionView->selectionModel()->selectedIndexes().first();
789 const Akonadi::Collection collection =
790 index.data( Akonadi::EntityTreeModel::CollectionRole ).value<Akonadi::Collection>();
792 return collection;
795 return Akonadi::Collection();
798 QAbstractItemModel *MainWidget::allContactsModel()
800 if ( !mAllContactsModel ) {
801 KDescendantsProxyModel *descendantsModel = new KDescendantsProxyModel( this );
802 descendantsModel->setSourceModel( GlobalContactModel::instance()->model() );
804 mAllContactsModel = new Akonadi::EntityMimeTypeFilterModel( this );
805 mAllContactsModel->setSourceModel( descendantsModel );
806 mAllContactsModel->addMimeTypeExclusionFilter( Akonadi::Collection::mimeType() );
807 mAllContactsModel->setHeaderGroup( Akonadi::EntityTreeModel::ItemListHeaders );
810 return mAllContactsModel;
813 void MainWidget::setViewMode( QAction *action )
815 setViewMode( action->data().toInt() );
818 void MainWidget::setViewMode( int mode )
820 int currentMode = Settings::self()->viewMode();
821 //kDebug() << "cur" << currentMode << "new" << mode;
822 if ( mode == currentMode ) return; // nothing to do
824 if ( mode == 0 ) {
825 mode = currentMode;// initialisation, no save
826 } else {
827 saveSplitterStates(); // for 2- or 3-column mode
829 if ( mode == 1 ) { // simple mode
830 mMainWidgetSplitter2->setVisible( false );
831 mDetailsPane->setVisible( true );
832 mContactSwitcher->setVisible( true );
834 else {
835 mMainWidgetSplitter2->setVisible( true );
836 mContactSwitcher->setVisible( false );
838 if ( mode == 2 ) { // 2 columns
839 mMainWidgetSplitter2->setOrientation( Qt::Vertical );
841 else if ( mode == 3 ) { // 3 columns
842 mMainWidgetSplitter2->setOrientation( Qt::Horizontal );
846 Settings::self()->setViewMode( mode ); // save new mode in settings
847 restoreSplitterStates(); // restore state for new mode
848 mViewModeGroup->actions().at( mode-1 )->setChecked( true );
850 if ( mItemView->model() ) {
851 mItemView->setCurrentIndex( mItemView->model()->index( 0, 0 ) );
855 void MainWidget::saveSplitterStates() const
857 // The splitter states are saved separately for each column view mode,
858 // but only if not in simple mode (1 column).
859 int currentMode = Settings::self()->viewMode();
860 if ( currentMode == 1 )
861 return;
863 QString groupName = QString::fromLatin1( "UiState_MainWidgetSplitter_%1" ).arg( currentMode );
864 //kDebug() << "saving to group" << groupName;
865 KConfigGroup group( Settings::self()->config(), groupName );
866 KPIM::UiStateSaver::saveState( mMainWidgetSplitter1, group );
867 KPIM::UiStateSaver::saveState( mMainWidgetSplitter2, group );
870 void MainWidget::restoreSplitterStates()
872 // The splitter states are restored as appropriate for the current
873 // column view mode, but not for simple mode (1 column).
874 int currentMode = Settings::self()->viewMode();
875 if ( currentMode == 1 )
876 return;
878 QString groupName = QString::fromLatin1( "UiState_MainWidgetSplitter_%1" ).arg( currentMode );
879 //kDebug() << "restoring from group" << groupName;
880 KConfigGroup group( Settings::self()->config(), groupName );
881 KPIM::UiStateSaver::restoreState( mMainWidgetSplitter1, group );
882 KPIM::UiStateSaver::restoreState( mMainWidgetSplitter2, group );
885 void MainWidget::initGrantleeThemeName()
887 QString themeName = GrantleeTheme::GrantleeSettings::self()->grantleeThemeName();
888 if (themeName.isEmpty()) {
889 themeName = QLatin1String("default");
891 mFormatter->setGrantleeTheme(mGrantleeThemeManager->theme(themeName));
892 mGroupFormatter->setGrantleeTheme(mGrantleeThemeManager->theme(themeName));
895 void MainWidget::slotGrantleeThemeSelected()
897 initGrantleeThemeName();
898 if ( mItemView->model() ) {
899 mItemView->setCurrentIndex( mItemView->model()->index( 0, 0 ) );
903 void MainWidget::slotGrantleeThemesUpdated()
905 if ( mItemView->model() ) {
906 mItemView->setCurrentIndex( mItemView->model()->index( 0, 0 ) );
910 void MainWidget::mergeContacts()
912 QPointer<MergeContactsDialog> dlg = new MergeContactsDialog(mItemView->selectionModel(), this);
913 dlg->exec();
914 delete dlg;
917 void MainWidget::slotSearchDuplicateContacts()
919 QPointer<SearchDuplicateContactWizard> wizard = new SearchDuplicateContactWizard(mItemView->selectionModel(), this);
920 wizard->exec();
921 delete wizard;
924 void MainWidget::slotDebugNepomuk()
926 QStringList uidList;
927 const Akonadi::Item::List lst = Utils::collectSelectedContactsItem(mItemView->selectionModel());
928 Q_FOREACH ( const Akonadi::Item &item, lst ) {
929 uidList << QString::number( item.id() );
933 QPointer<PimCommon::NepomukDebugDialog> dlg = new PimCommon::NepomukDebugDialog(uidList, this);
934 dlg->exec();
935 delete dlg;