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"
30 #include "xxportmanager.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>
70 #include <KActionCollection>
71 #include <KActionMenu>
72 #include <KApplication>
73 #include <KCheckableProxyModel>
74 #include <kdescendantsproxymodel.h> //krazy:exclude=camelcase TODO wait for kdelibs4.9
78 #include <KSelectionProxyModel>
79 #include <KStandardDirs>
80 #include <KTextBrowser>
81 #include <KToggleAction>
83 #include <KXmlGuiWindow>
84 #include <KCMultiDialog>
85 #include <kdeprintdialog.h>
86 #include <KPrintPreview>
89 #include <QActionGroup>
90 #include <QHBoxLayout>
91 #include <QHeaderView>
94 #include <QPrintDialog>
95 #include <QSortFilterProxyModel>
97 #include <QStackedWidget>
98 #include <QDBusConnection>
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
) ) {
114 class StructuralCollectionsNotCheckableProxy
: public KCheckableProxyModel
117 StructuralCollectionsNotCheckableProxy( QObject
*parent
)
118 : KCheckableProxyModel( parent
)
122 /* reimp */QVariant
data( const QModelIndex
&index
, int role
) const
124 if ( !index
.isValid() ) {
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
) ) {
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
>();
154 setupActions( guiClient
->actionCollection() );
157 * The item models, proxies and views have the following structure:
162 * mContactsFilterModel
168 * | mAllContactsModel
171 * mCollectionView selectionProxyModel descendantsModel
174 * | selectionModel | |
176 * proxyModel ---------' | |
179 * mCollectionTree | |
181 * | | _______________/
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
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
),
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") );
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
) );
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)
358 action( QLatin1String("options_show_qrcodes") )->setChecked( showQRCodes() );
361 connect( GlobalContactModel::instance()->model(), SIGNAL(modelAboutToBeReset()),
363 connect( GlobalContactModel::instance()->model(), SIGNAL(modelReset()),
364 SLOT(restoreState()) );
365 connect( kapp
, SIGNAL(aboutToQuit()), SLOT(saveState()) );
370 MainWidget::~MainWidget()
372 mModelColumnManager
->store();
373 saveSplitterStates();
375 KConfigGroup
group( Settings::self()->config(), "UiState_ContactView" );
376 KPIM::UiStateSaver::saveState( mItemView
, group
);
379 delete mGrantleeThemeManager
;
381 Settings::self()->writeConfig();
384 void MainWidget::restoreState()
388 Akonadi::ETMViewStateSaver
*saver
= new Akonadi::ETMViewStateSaver
;
389 saver
->setView( mCollectionView
);
391 const KConfigGroup
group( Settings::self()->config(), "CollectionViewState" );
392 saver
->restoreState( group
);
397 Akonadi::ETMViewStateSaver
*saver
= new Akonadi::ETMViewStateSaver
;
398 saver
->setSelectionModel( mCollectionSelectionModel
);
400 const KConfigGroup
group( Settings::self()->config(), "CollectionViewCheckState" );
401 saver
->restoreState( group
);
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()
419 Akonadi::ETMViewStateSaver saver
;
420 saver
.setView( mCollectionView
);
422 KConfigGroup
group( Settings::self()->config(), "CollectionViewState" );
423 saver
.saveState( group
);
429 Akonadi::ETMViewStateSaver saver
;
430 saver
.setSelectionModel( mCollectionSelectionModel
);
432 KConfigGroup
group( Settings::self()->config(), "CollectionViewCheckState" );
433 saver
.saveState( group
);
439 Akonadi::ETMViewStateSaver saver
;
440 saver
.setView( mItemView
);
441 saver
.setSelectionModel( mItemView
->selectionModel() );
443 KConfigGroup
group( Settings::self()->config(), "ItemViewState" );
444 saver
.saveState( group
);
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
);
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)) );
575 mViewModeGroup
= new QActionGroup( this );
577 KAction
*act
= new KAction( i18nc( "@action:inmenu", "Simple (one column)" ), mViewModeGroup
);
578 act
->setCheckable( true );
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 );
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 );
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
*)) );
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") );
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();
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()) );
663 action
= collection
->addAction( QLatin1String("debug_nepomuk") );
664 action
->setText( i18n( "Debug Nepomuk..." ) );
665 connect( action
, SIGNAL(triggered(bool)), this, SLOT(slotDebugNepomuk()) );
669 void MainWidget::printPreview()
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();
686 void MainWidget::print()
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
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
¤t
, 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 );
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 ) );
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
>();
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
825 mode
= currentMode
;// initialisation, no save
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 );
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 )
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 )
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);
917 void MainWidget::slotSearchDuplicateContacts()
919 QPointer
<SearchDuplicateContactWizard
> wizard
= new SearchDuplicateContactWizard(mItemView
->selectionModel(), this);
924 void MainWidget::slotDebugNepomuk()
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);