mainwidget.cpp 42.3 KB
Newer Older
1
/*
Allen Winter's avatar
Allen Winter committed
2
  This file is part of KAddressBook.
3

Allen Winter's avatar
Allen Winter committed
4
  Copyright (c) 2007 Tobias Koenig <tokoe@kde.org>
5

Allen Winter's avatar
Allen Winter committed
6
7
8
9
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.
10

Allen Winter's avatar
Allen Winter committed
11
12
13
14
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.
15

Allen Winter's avatar
Allen Winter committed
16
17
18
  You should have received a copy of the GNU General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
20
21
*/

#include "mainwidget.h"
Laurent Montel's avatar
Laurent Montel committed
22
#include "groupingproxymodel/qgroupingproxymodel.h"
23
24
25
26
#include "contactswitcher.h"
#include "globalcontactmodel.h"
#include "modelcolumnmanager.h"
#include "printing/printingwizard.h"
Laurent Montel's avatar
Laurent Montel committed
27
#include "widgets/quicksearchwidget.h"
28
#include "settings.h"
Laurent Montel's avatar
Laurent Montel committed
29
#include "xxport/xxportmanager.h"
Laurent Montel's avatar
Laurent Montel committed
30
#include "kaddressbookadaptor.h"
31
32
#include "categoryselectwidget.h"
#include "categoryfilterproxymodel.h"
33
#include "kaddressbook_options.h"
Laurent Montel's avatar
Laurent Montel committed
34
#include "contactselectiondialog.h"
35

Laurent Montel's avatar
Laurent Montel committed
36
37
#include "KaddressbookGrantlee/GrantleeContactFormatter"
#include "KaddressbookGrantlee/GrantleeContactGroupFormatter"
38
#include "grantleetheme/grantleethememanager.h"
39

Laurent Montel's avatar
Laurent Montel committed
40
#include "Libkdepim/UiStateSaver"
41

Laurent Montel's avatar
Laurent Montel committed
42
43
#include <PimCommon/CollectionAclPage>
#include <PimCommon/ImapAclAttribute>
Laurent Montel's avatar
Laurent Montel committed
44

Laurent Montel's avatar
Port++    
Laurent Montel committed
45
46
#include <AkonadiWidgets/ETMViewStateSaver>
#include <AkonadiCore/CollectionFilterProxyModel>
Laurent Montel's avatar
Laurent Montel committed
47
#include <AkonadiWidgets/ControlGui>
Laurent Montel's avatar
Port++    
Laurent Montel committed
48
49
50
51
52
53
#include <AkonadiCore/EntityMimeTypeFilterModel>
#include <AkonadiWidgets/EntityTreeView>
#include <AkonadiWidgets/ItemView>
#include <AkonadiCore/MimeTypeChecker>
#include <AkonadiCore/AttributeFactory>
#include <AkonadiWidgets/CollectionPropertiesDialog>
Laurent Montel's avatar
Laurent Montel committed
54
#include <AkonadiSearch/Debug/akonadisearchdebugdialog.h>
55
#include <KContacts/Addressee>
Laurent Montel's avatar
Laurent Montel committed
56
#include <QPointer>
Laurent Montel's avatar
Laurent Montel committed
57
58
#include "PimCommon/ManageServerSideSubscriptionJob"
#include "PimCommon/PimUtil"
59

Allen Winter's avatar
Allen Winter committed
60
61
62
63
64
65
66
67
#include <Akonadi/Contact/ContactDefaultActions>
#include <Akonadi/Contact/ContactGroupEditorDialog>
#include <Akonadi/Contact/ContactGroupViewer>
#include <Akonadi/Contact/ContactsFilterProxyModel>
#include <Akonadi/Contact/ContactsTreeModel>
#include <Akonadi/Contact/ContactViewer>
#include <Akonadi/Contact/StandardContactActionManager>

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
68
#include <KContacts/ContactGroup>
Laurent Montel's avatar
Laurent Montel committed
69
#include "kaddressbook_debug.h"
Laurent Montel's avatar
Port++    
Laurent Montel committed
70
#include <QAction>
Laurent Montel's avatar
Laurent Montel committed
71
#include <QApplication>
Allen Winter's avatar
Allen Winter committed
72
#include <KActionCollection>
73
#include <KActionMenu>
Allen Winter's avatar
Allen Winter committed
74
#include <KCheckableProxyModel>
Laurent Montel's avatar
Laurent Montel committed
75
#include <KDescendantsProxyModel>
Laurent Montel's avatar
Laurent Montel committed
76
#include <KLocalizedString>
Allen Winter's avatar
Allen Winter committed
77
#include <KSelectionProxyModel>
Laurent Montel's avatar
Laurent Montel committed
78
#include <QTextBrowser>
Allen Winter's avatar
Allen Winter committed
79
#include <KToggleAction>
80
#include <KCMultiDialog>
Laurent Montel's avatar
Laurent Montel committed
81
#include <KPrintPreview>
Laurent Montel's avatar
Laurent Montel committed
82
#include <KXMLGUIClient>
83
#include <KMessageBox>
84

85
86
87
88
89
90
91
#include <QActionGroup>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QPrinter>
#include <QPrintDialog>
#include <QSplitter>
#include <QStackedWidget>
Laurent Montel's avatar
Laurent Montel committed
92
#include <QDBusConnection>
Laurent Montel's avatar
Laurent Montel committed
93
#include <QDesktopServices>
94
#include <ItemModifyJob>
95

Laurent Montel's avatar
Laurent Montel committed
96
#include "plugininterface/kaddressbookplugininterface.h"
Laurent Montel's avatar
Laurent Montel committed
97

Laurent Montel's avatar
Laurent Montel committed
98
99
100
namespace
{
static bool isStructuralCollection(const Akonadi::Collection &collection)
101
{
Laurent Montel's avatar
Laurent Montel committed
102
    QStringList mimeTypes;
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
103
    mimeTypes << KContacts::Addressee::mimeType() << KContacts::ContactGroup::mimeType();
Laurent Montel's avatar
Laurent Montel committed
104
    const QStringList collectionMimeTypes = collection.contentMimeTypes();
Laurent Montel's avatar
Laurent Montel committed
105
106
    foreach (const QString &mimeType, mimeTypes) {
        if (collectionMimeTypes.contains(mimeType)) {
Laurent Montel's avatar
Laurent Montel committed
107
108
            return false;
        }
Allen Winter's avatar
Allen Winter committed
109
    }
Laurent Montel's avatar
Laurent Montel committed
110
    return true;
111
112
}

Allen Winter's avatar
Allen Winter committed
113
114
class StructuralCollectionsNotCheckableProxy : public KCheckableProxyModel
{
Laurent Montel's avatar
Laurent Montel committed
115
public:
Laurent Montel's avatar
Laurent Montel committed
116
    explicit StructuralCollectionsNotCheckableProxy(QObject *parent)
Laurent Montel's avatar
Laurent Montel committed
117
        : KCheckableProxyModel(parent)
Allen Winter's avatar
Allen Winter committed
118
119
    {
    }
120

121
    QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE
Allen Winter's avatar
Allen Winter committed
122
    {
Laurent Montel's avatar
Laurent Montel committed
123
        if (!index.isValid()) {
Laurent Montel's avatar
Laurent Montel committed
124
125
            return QVariant();
        }
Allen Winter's avatar
Allen Winter committed
126

Laurent Montel's avatar
Laurent Montel committed
127
        if (role == Qt::CheckStateRole) {
Laurent Montel's avatar
Laurent Montel committed
128
129
            // Don't show the checkbox if the collection can't contain incidences
            const Akonadi::Collection collection =
Laurent Montel's avatar
Laurent Montel committed
130
131
                index.data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
            if (collection.isValid() && isStructuralCollection(collection)) {
Laurent Montel's avatar
Laurent Montel committed
132
133
                return QVariant();
            }
Allen Winter's avatar
Allen Winter committed
134
        }
Laurent Montel's avatar
Laurent Montel committed
135
        return KCheckableProxyModel::data(index, role);
136
137
138
139
140
    }
};

}

Laurent Montel's avatar
Laurent Montel committed
141
MainWidget::MainWidget(KXMLGUIClient *guiClient, QWidget *parent)
Laurent Montel's avatar
Laurent Montel committed
142
143
144
145
146
147
    : QWidget(parent),
      mAllContactsModel(Q_NULLPTR),
      mXmlGuiClient(guiClient),
      mGrantleeThemeManager(Q_NULLPTR),
      mQuickSearchAction(Q_NULLPTR),
      mServerSideSubscription(Q_NULLPTR),
Laurent Montel's avatar
Laurent Montel committed
148
      mPluginInterface(Q_NULLPTR)
149
{
Laurent Montel's avatar
Laurent Montel committed
150

Laurent Montel's avatar
Laurent Montel committed
151
    (void) new KaddressbookAdaptor(this);
152
    QDBusConnection::sessionBus().registerObject(QStringLiteral("/KAddressBook"), this);
Laurent Montel's avatar
Laurent Montel committed
153

Laurent Montel's avatar
Laurent Montel committed
154
    mXXPortManager = new XXPortManager(this);
Laurent Montel's avatar
Laurent Montel committed
155
    Akonadi::AttributeFactory::registerAttribute<PimCommon::ImapAclAttribute>();
156

Laurent Montel's avatar
Laurent Montel committed
157
    mPluginInterface = new KAddressBookPluginInterface(guiClient->actionCollection(), this);
Laurent Montel's avatar
Laurent Montel committed
158
    setupGui();
Laurent Montel's avatar
Laurent Montel committed
159
    setupActions(guiClient->actionCollection());
160

Laurent Montel's avatar
Laurent Montel committed
161
    /*
Laurent Montel's avatar
Laurent Montel committed
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
    *  The item models, proxies and views have the following structure:
    *
    *                               mItemView
    *                                   ^
    *                                   |
    *                           mContactsFilterModel
    *                                   ^
    *                                   |
    * mCategorySelectWidget --> mCategoryFilterModel
    *                                   ^
    *                                   |
    *                               mItemTree
    *                                   ^
    *                                   |
    *                                   |           mAllContactsModel
    *                                   |                  ^
    *                                   |                  |
    *      mCollectionView     selectionProxyModel  descendantsModel
    *            ^               ^      ^                  ^
    *            |               |      |                  |
    *            |       selectionModel |                  |
    *            |               |      |                  |
    *        proxyModel ---------'      |                  |
    *            ^                      |                  |
    *            |                      |                  |
    *      mCollectionTree              |                  |
    *            ^                      |                  |
    *            |                      |   _______________/
    *             \                    /  /
    *            GlobalContactModel::instance()
    *
    *
    *  GlobalContactModel::instance():  The global contact model (contains collections and items)
    *                 mCollectionTree:  Filters out all items
    *                      proxyModel:  Allows the user to select collections by checkboxes
    *                  selectionModel:  Represents the selected collections that have been
    *                                   selected in proxyModel
    *                 mCollectionView:  Shows the collections (address books) in a view
    *             selectionProxyModel:  Filters out all collections and items that are no children
    *                                   of the collections currently selected in selectionModel
    *                       mItemTree:  Filters out all collections
    *           mCategorySelectWidget:  Selects a list of categories for filtering
    *            mCategoryFilterModel:  Filters the contacts by the selected categories
    *            mContactsFilterModel:  Filters the contacts by the content of mQuickSearchWidget
    *                       mItemView:  Shows the items (contacts and contact groups) in a view
    *
    *                descendantsModel:  Flattens the item/collection tree to a list
    *               mAllContactsModel:  Provides a list of all available contacts from all
    *                                   address books
    */

    mCollectionTree = new Akonadi::EntityMimeTypeFilterModel(this);
    mCollectionTree->setDynamicSortFilter(true);
    mCollectionTree->setSortCaseSensitivity(Qt::CaseInsensitive);
    mCollectionTree->setSourceModel(GlobalContactModel::instance()->model());
    mCollectionTree->addMimeTypeInclusionFilter(Akonadi::Collection::mimeType());
    mCollectionTree->setHeaderGroup(Akonadi::EntityTreeModel::CollectionTreeHeaders);

    mCollectionSelectionModel = new QItemSelectionModel(mCollectionTree);
    StructuralCollectionsNotCheckableProxy *checkableProxyModel =
        new StructuralCollectionsNotCheckableProxy(this);
    checkableProxyModel->setSelectionModel(mCollectionSelectionModel);
    checkableProxyModel->setSourceModel(mCollectionTree);

    mCollectionView->setModel(checkableProxyModel);
    mCollectionView->setXmlGuiClient(guiClient);
    mCollectionView->header()->setDefaultAlignment(Qt::AlignCenter);
    mCollectionView->header()->setSortIndicatorShown(false);

Laurent Montel's avatar
Laurent Montel committed
231
232
    connect(mCollectionView->model(), &QAbstractItemModel::rowsInserted,
            this, &MainWidget::slotCheckNewCalendar);
Laurent Montel's avatar
Laurent Montel committed
233
234

    connect(mCollectionView, SIGNAL(currentChanged(Akonadi::Collection)),
235
            this, SLOT(slotCurrentCollectionChanged(Akonadi::Collection)));
Laurent Montel's avatar
Laurent Montel committed
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251

    KSelectionProxyModel *selectionProxyModel =
        new KSelectionProxyModel(mCollectionSelectionModel, this);
    selectionProxyModel->setSourceModel(GlobalContactModel::instance()->model());
    selectionProxyModel->setFilterBehavior(KSelectionProxyModel::ChildrenOfExactSelection);

    mItemTree = new Akonadi::EntityMimeTypeFilterModel(this);
    mItemTree->setSourceModel(selectionProxyModel);
    mItemTree->addMimeTypeExclusionFilter(Akonadi::Collection::mimeType());
    mItemTree->setHeaderGroup(Akonadi::EntityTreeModel::ItemListHeaders);

    mCategoryFilterModel = new CategoryFilterProxyModel(this);
    mCategoryFilterModel->setSourceModel(mItemTree);
    mCategoryFilterModel->setFilterCategories(mCategorySelectWidget->filterTags());
    mCategoryFilterModel->setFilterEnabled(true);

Laurent Montel's avatar
Laurent Montel committed
252
253
    connect(mCategorySelectWidget, &CategorySelectWidget::filterChanged,
            mCategoryFilterModel, &CategoryFilterProxyModel::setFilterCategories);
Laurent Montel's avatar
Laurent Montel committed
254
255
256
257

    mContactsFilterModel = new Akonadi::ContactsFilterProxyModel(this);
    mContactsFilterModel->setSourceModel(mCategoryFilterModel);

Laurent Montel's avatar
Laurent Montel committed
258
259
260
261
    connect(mQuickSearchWidget, &QuickSearchWidget::filterStringChanged,
            mContactsFilterModel, &Akonadi::ContactsFilterProxyModel::setFilterString);
    connect(mQuickSearchWidget, &QuickSearchWidget::filterStringChanged,
            this, &MainWidget::selectFirstItem);
Laurent Montel's avatar
Laurent Montel committed
262
263
    connect(mQuickSearchWidget, &QuickSearchWidget::arrowDownKeyPressed,
            this, &MainWidget::setFocusToTreeView);
Laurent Montel's avatar
Laurent Montel committed
264
#if 0
Laurent Montel's avatar
Laurent Montel committed
265
    QGroupingProxyModel *proxy = new QGroupingProxyModel(this);
Laurent Montel's avatar
Laurent Montel committed
266
    proxy->setSourceModel(mContactsFilterModel);
Laurent Montel's avatar
Laurent Montel committed
267
    proxy->setModelColumn(2);
Laurent Montel's avatar
Laurent Montel committed
268

Laurent Montel's avatar
Laurent Montel committed
269
270
    mItemView->setModel(proxy);
#else
Laurent Montel's avatar
Laurent Montel committed
271
    mItemView->setModel(mContactsFilterModel);
Laurent Montel's avatar
Laurent Montel committed
272
#endif
Laurent Montel's avatar
Laurent Montel committed
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
    mItemView->setXmlGuiClient(guiClient);
    mItemView->setSelectionMode(QAbstractItemView::ExtendedSelection);
    mItemView->setRootIsDecorated(false);
    mItemView->header()->setDefaultAlignment(Qt::AlignCenter);

    mXXPortManager->setSelectionModel(mItemView->selectionModel());

    mActionManager = new Akonadi::StandardContactActionManager(guiClient->actionCollection(), this);
    mActionManager->setCollectionSelectionModel(mCollectionView->selectionModel());
    mActionManager->setItemSelectionModel(mItemView->selectionModel());

    QList<Akonadi::StandardActionManager::Type> standardActions;
    standardActions << Akonadi::StandardActionManager::CreateCollection
                    << Akonadi::StandardActionManager::DeleteCollections
                    << Akonadi::StandardActionManager::SynchronizeCollections
                    << Akonadi::StandardActionManager::CollectionProperties
                    << Akonadi::StandardActionManager::CopyItems
                    << Akonadi::StandardActionManager::Paste
                    << Akonadi::StandardActionManager::DeleteItems
                    << Akonadi::StandardActionManager::CutItems
                    << Akonadi::StandardActionManager::CreateResource
                    << Akonadi::StandardActionManager::DeleteResources
                    << Akonadi::StandardActionManager::ResourceProperties
                    << Akonadi::StandardActionManager::SynchronizeResources
297
298
299
                    << Akonadi::StandardActionManager::SynchronizeCollectionsRecursive
                    << Akonadi::StandardActionManager::MoveItemToMenu
                    << Akonadi::StandardActionManager::CopyItemToMenu;
Laurent Montel's avatar
Laurent Montel committed
300
301
302
303

    Q_FOREACH (Akonadi::StandardActionManager::Type standardAction, standardActions) {
        mActionManager->createAction(standardAction);
    }
304
    guiClient->actionCollection()->setDefaultShortcut(mActionManager->action(Akonadi::StandardActionManager::DeleteItems), QKeySequence(Qt::Key_Delete));
Laurent Montel's avatar
Laurent Montel committed
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
    QList<Akonadi::StandardContactActionManager::Type> contactActions;
    contactActions << Akonadi::StandardContactActionManager::CreateContact
                   << Akonadi::StandardContactActionManager::CreateContactGroup
                   << Akonadi::StandardContactActionManager::EditItem;

    Q_FOREACH (Akonadi::StandardContactActionManager::Type contactAction, contactActions) {
        mActionManager->createAction(contactAction);
    }
    static bool pageRegistered = false;

    if (!pageRegistered) {
        Akonadi::CollectionPropertiesDialog::registerPage(new PimCommon::CollectionAclPageFactory);
        pageRegistered = true;
    }

    const QStringList pages =
321
322
323
        QStringList() << QStringLiteral("Akonadi::CollectionGeneralPropertiesPage")
        << QStringLiteral("Akonadi::CachePolicyPage")
        << QStringLiteral("PimCommon::CollectionAclPage");
Laurent Montel's avatar
Laurent Montel committed
324
325
326
327
328
329
330
331

    mActionManager->setCollectionPropertiesPageNames(pages);

    connect(mItemView, SIGNAL(currentChanged(Akonadi::Item)),
            this, SLOT(itemSelected(Akonadi::Item)));
    connect(mItemView, SIGNAL(doubleClicked(Akonadi::Item)),
            mActionManager->action(Akonadi::StandardContactActionManager::EditItem),
            SLOT(trigger()));
Laurent Montel's avatar
Laurent Montel committed
332
333
334
335
    connect(mItemView->selectionModel(), &QItemSelectionModel::currentChanged,
            this, &MainWidget::itemSelectionChanged);
    connect(mItemView->selectionModel(), &QItemSelectionModel::selectionChanged,
            this, &MainWidget::slotSelectionChanged);
Laurent Montel's avatar
Laurent Montel committed
336
337
338
339
340
341

    // show the contact details view as default
    mDetailsViewStack->setCurrentWidget(mContactDetails);

    mContactSwitcher->setView(mItemView);

Laurent Montel's avatar
Laurent Montel committed
342
    Akonadi::ControlGui::widgetNeedsAkonadi(this);
Laurent Montel's avatar
Laurent Montel committed
343
344
345
346
347
348
349

    mModelColumnManager = new ModelColumnManager(GlobalContactModel::instance()->model(), this);
    mModelColumnManager->setWidget(mItemView->header());
    mModelColumnManager->load();

    QMetaObject::invokeMethod(this, "delayedInit", Qt::QueuedConnection);
    updateQuickSearchText();
Laurent Montel's avatar
Laurent Montel committed
350
    slotSelectionChanged();
351
352
}

Laurent Montel's avatar
Laurent Montel committed
353
354
355
356
357
void MainWidget::setFocusToTreeView()
{
    mItemView->setFocus();
}

358
359
void MainWidget::configure()
{
Laurent Montel's avatar
Laurent Montel committed
360
    KCMultiDialog dlg(this);
361
362
    dlg.addModule(QStringLiteral("akonadicontact_actions.desktop"));
    dlg.addModule(QStringLiteral("kcmldap.desktop"));
363

Laurent Montel's avatar
Laurent Montel committed
364
    dlg.exec();
365
366
}

367
void MainWidget::handleCommandLine(const QStringList &arguments)
368
{
369
370
371
372
    QCommandLineParser parser;
    kaddressbook_options(&parser);
    parser.process(arguments);

373
    if (parser.isSet(QStringLiteral("import"))) {
374
        for (const QString &url : parser.positionalArguments()) {
Laurent Montel's avatar
Laurent Montel committed
375
            importManager()->importFile(QUrl::fromUserInput(url));
Laurent Montel's avatar
Laurent Montel committed
376
377
        }
    }
378
379
}

380
381
382
383
384
XXPortManager *MainWidget::importManager() const
{
    return mXXPortManager;
}

385
386
void MainWidget::updateQuickSearchText()
{
Laurent Montel's avatar
Laurent Montel committed
387
    mQuickSearchWidget->updateQuickSearchText(i18nc("@label Search contacts in list", "Search...<%1>", mQuickSearchAction->shortcut().toString()));
388
389
}

390
391
void MainWidget::delayedInit()
{
Laurent Montel's avatar
Laurent Montel committed
392
    setViewMode(0);                                        // get default from settings
393

Laurent Montel's avatar
Laurent Montel committed
394
395
    const KConfigGroup group(Settings::self()->config(), "UiState_ContactView");
    KPIM::UiStateSaver::restoreState(mItemView, group);
396

397
#if defined(HAVE_PRISON)
Laurent Montel's avatar
Laurent Montel committed
398
    mXmlGuiClient->actionCollection()->action(QStringLiteral("options_show_qrcodes"))->setChecked(showQRCodes());
399
#endif
400

401
402
403
404
    connect(GlobalContactModel::instance()->model(), &QAbstractItemModel::modelAboutToBeReset,
            this, &MainWidget::saveState);
    connect(GlobalContactModel::instance()->model(), &QAbstractItemModel::modelReset,
            this, &MainWidget::restoreState);
Laurent Montel's avatar
Laurent Montel committed
405
    connect(qApp, &QApplication::aboutToQuit, this, &MainWidget::saveState);
406

Laurent Montel's avatar
Laurent Montel committed
407
408
    restoreState();
    updateQuickSearchText();
Laurent Montel's avatar
Laurent Montel committed
409
    initializePluginActions();
410
411
412
413
}

MainWidget::~MainWidget()
{
Laurent Montel's avatar
Laurent Montel committed
414
415
    mModelColumnManager->store();
    saveSplitterStates();
416

Laurent Montel's avatar
Laurent Montel committed
417
418
    KConfigGroup group(Settings::self()->config(), "UiState_ContactView");
    KPIM::UiStateSaver::saveState(mItemView, group);
419

Laurent Montel's avatar
Laurent Montel committed
420
421
    saveState();
    delete mGrantleeThemeManager;
422
423
424
    delete mFormatter;
    delete mGroupFormatter;

425

Laurent Montel's avatar
Laurent Montel committed
426
    Settings::self()->save();
427
428
429
430
}

void MainWidget::restoreState()
{
Laurent Montel's avatar
Laurent Montel committed
431
432
433
434
    // collection view
    {
        Akonadi::ETMViewStateSaver *saver = new Akonadi::ETMViewStateSaver;
        saver->setView(mCollectionView);
435

Laurent Montel's avatar
Laurent Montel committed
436
437
438
        const KConfigGroup group(Settings::self()->config(), "CollectionViewState");
        saver->restoreState(group);
    }
439

Laurent Montel's avatar
Laurent Montel committed
440
441
442
443
    // collection view
    {
        Akonadi::ETMViewStateSaver *saver = new Akonadi::ETMViewStateSaver;
        saver->setSelectionModel(mCollectionSelectionModel);
444

Laurent Montel's avatar
Laurent Montel committed
445
446
447
        const KConfigGroup group(Settings::self()->config(), "CollectionViewCheckState");
        saver->restoreState(group);
    }
448

Laurent Montel's avatar
Laurent Montel committed
449
450
451
452
453
    // item view
    {
        Akonadi::ETMViewStateSaver *saver = new Akonadi::ETMViewStateSaver;
        saver->setView(mItemView);
        saver->setSelectionModel(mItemView->selectionModel());
454

Laurent Montel's avatar
Laurent Montel committed
455
456
457
        const KConfigGroup group(Settings::self()->config(), "ItemViewState");
        saver->restoreState(group);
    }
458
459
}

460
void MainWidget::saveState()
461
{
Laurent Montel's avatar
Laurent Montel committed
462
463
464
465
    // collection view
    {
        Akonadi::ETMViewStateSaver saver;
        saver.setView(mCollectionView);
466

Laurent Montel's avatar
Laurent Montel committed
467
468
469
470
        KConfigGroup group(Settings::self()->config(), "CollectionViewState");
        saver.saveState(group);
        group.sync();
    }
471

Laurent Montel's avatar
Laurent Montel committed
472
473
474
475
    // collection view
    {
        Akonadi::ETMViewStateSaver saver;
        saver.setSelectionModel(mCollectionSelectionModel);
476

Laurent Montel's avatar
Laurent Montel committed
477
478
479
480
        KConfigGroup group(Settings::self()->config(), "CollectionViewCheckState");
        saver.saveState(group);
        group.sync();
    }
481

Laurent Montel's avatar
Laurent Montel committed
482
483
484
485
486
    // item view
    {
        Akonadi::ETMViewStateSaver saver;
        saver.setView(mItemView);
        saver.setSelectionModel(mItemView->selectionModel());
487

Laurent Montel's avatar
Laurent Montel committed
488
489
490
491
        KConfigGroup group(Settings::self()->config(), "ItemViewState");
        saver.saveState(group);
        group.sync();
    }
492
493
494
495
}

void MainWidget::setupGui()
{
Laurent Montel's avatar
Laurent Montel committed
496
497
498
499
500
501
502
503
504
505
    // the horizontal main layout
    QHBoxLayout *layout = new QHBoxLayout(this);
    layout->setMargin(0);

    // Splitter 1 contains the two main parts of the GUI:
    //  - collection and item view splitter 2 on the left (see below)
    //  - details pane on the right, that contains
    //   - details view stack on the top
    //   - contact switcher at the bottom
    mMainWidgetSplitter1 = new QSplitter(Qt::Horizontal);
506
    mMainWidgetSplitter1->setObjectName(QStringLiteral("MainWidgetSplitter1"));
Laurent Montel's avatar
Laurent Montel committed
507
508
509
510
511
512
513
514
    layout->addWidget(mMainWidgetSplitter1);

    // Splitter 2 contains the remaining parts of the GUI:
    //  - collection view on either the left or the top
    //  - item view on either the right or the bottom
    // The orientation of this splitter is changed for either
    // a three or two column view;  in simple mode it is hidden.
    mMainWidgetSplitter2 = new QSplitter(Qt::Vertical);
515
    mMainWidgetSplitter2->setObjectName(QStringLiteral("MainWidgetSplitter2"));
Laurent Montel's avatar
Laurent Montel committed
516
517
518
519
520
521
522
523
    mMainWidgetSplitter1->addWidget(mMainWidgetSplitter2);

    // the collection view
    mCollectionView = new Akonadi::EntityTreeView();
    mMainWidgetSplitter2->addWidget(mCollectionView);

    // the items view
    mItemView = new Akonadi::EntityTreeView();
524
525
    mItemView->setObjectName(QStringLiteral("ContactView"));
    mItemView->setDefaultPopupMenu(QStringLiteral("akonadi_itemview_contextmenu"));
Laurent Montel's avatar
Laurent Montel committed
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
    mItemView->setAlternatingRowColors(true);
    mMainWidgetSplitter2->addWidget(mItemView);

    // the details pane that contains the details view stack and contact switcher
    mDetailsPane = new QWidget;
    mMainWidgetSplitter1->addWidget(mDetailsPane);

    mMainWidgetSplitter1->setStretchFactor(1, 9);          // maximum width for detail
    mMainWidgetSplitter2->setStretchFactor(1, 9);          // for intuitive resizing
    mMainWidgetSplitter2->setChildrenCollapsible(false);
    mMainWidgetSplitter1->setChildrenCollapsible(false);

    QVBoxLayout *detailsPaneLayout = new QVBoxLayout(mDetailsPane);
    detailsPaneLayout->setMargin(0);

    // the details view stack
    mDetailsViewStack = new QStackedWidget();
    detailsPaneLayout->addWidget(mDetailsViewStack);

    // the details widget for contacts
    mContactDetails = new Akonadi::ContactViewer(mDetailsViewStack);
    mDetailsViewStack->addWidget(mContactDetails);

    // the details widget for contact groups
    mContactGroupDetails = new Akonadi::ContactGroupViewer(mDetailsViewStack);
    mDetailsViewStack->addWidget(mContactGroupDetails);

    // the details widget for empty items
    mEmptyDetails = new QTextBrowser(mDetailsViewStack);
    mDetailsViewStack->addWidget(mEmptyDetails);

    // the contact switcher for the simple gui mode
    mContactSwitcher = new ContactSwitcher;
    detailsPaneLayout->addWidget(mContactSwitcher);
    mContactSwitcher->setVisible(false);

    // the quick search widget which is embedded in the toolbar action
    mQuickSearchWidget = new QuickSearchWidget;
564
    mQuickSearchWidget->setMaximumWidth(500);
Laurent Montel's avatar
Laurent Montel committed
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580

    // the category filter widget which is embedded in the toolbar action
    mCategorySelectWidget = new CategorySelectWidget;

    // setup the default actions
    Akonadi::ContactDefaultActions *actions = new Akonadi::ContactDefaultActions(this);
    actions->connectToView(mContactDetails);
    actions->connectToView(mContactGroupDetails);
    mFormatter = new KAddressBookGrantlee::GrantleeContactFormatter;

    mContactDetails->setContactFormatter(mFormatter);

    mGroupFormatter = new KAddressBookGrantlee::GrantleeContactGroupFormatter;

    mContactGroupDetails->setContactGroupFormatter(mGroupFormatter);
}
581

Laurent Montel's avatar
Laurent Montel committed
582
void MainWidget::initializePluginActions()
Laurent Montel's avatar
Laurent Montel committed
583
{
Laurent Montel's avatar
Laurent Montel committed
584
    mPluginInterface->initializePluginActions(QStringLiteral("kaddressbook"), mXmlGuiClient);
Laurent Montel's avatar
Laurent Montel committed
585
586
}

Laurent Montel's avatar
Laurent Montel committed
587
588
void MainWidget::setupActions(KActionCollection *collection)
{
Laurent Montel's avatar
Laurent Montel committed
589
    mPluginInterface->setParentWidget(this);
590
    mPluginInterface->setMainWidget(this);
Laurent Montel's avatar
Laurent Montel committed
591
    mPluginInterface->createPluginInterface();
592
    mGrantleeThemeManager = new GrantleeTheme::ThemeManager(QStringLiteral("addressbook"),
Laurent Montel's avatar
Laurent Montel committed
593
594
595
            QStringLiteral("theme.desktop"),
            collection,
            QStringLiteral("kaddressbook/viewertemplates/"));
596
    mGrantleeThemeManager->setDownloadNewStuffConfigFile(QStringLiteral("kaddressbook_themes.knsrc"));
597
598
    connect(mGrantleeThemeManager, &GrantleeTheme::ThemeManager::grantleeThemeSelected, this, &MainWidget::slotGrantleeThemeSelected);
    connect(mGrantleeThemeManager, &GrantleeTheme::ThemeManager::updateThemes, this, &MainWidget::slotGrantleeThemesUpdated);
599

Laurent Montel's avatar
Laurent Montel committed
600
    KActionMenu *themeMenu  = new KActionMenu(i18n("&Themes"), this);
601
    collection->addAction(QStringLiteral("theme_menu"), themeMenu);
602

Laurent Montel's avatar
Laurent Montel committed
603
604
605
606
    initGrantleeThemeName();
    QActionGroup *group = new QActionGroup(this);
    mGrantleeThemeManager->setThemeMenu(themeMenu);
    mGrantleeThemeManager->setActionGroup(group);
607

Laurent Montel's avatar
Laurent Montel committed
608
609
610
611
    QAction *action = KStandardAction::print(this, SLOT(print()), collection);
    action->setWhatsThis(
        i18nc("@info:whatsthis",
              "Print the complete address book or a selected number of contacts."));
612

Laurent Montel's avatar
Laurent Montel committed
613
614
615
    if (KPrintPreview::isAvailable()) {
        KStandardAction::printPreview(this, SLOT(printPreview()), collection);
    }
616

Laurent Montel's avatar
Laurent Montel committed
617
618
619
    QWidgetAction *quicksearch = new QWidgetAction(this);
    quicksearch->setText(i18n("Quick search"));
    quicksearch->setDefaultWidget(mQuickSearchWidget);
620
    collection->addAction(QStringLiteral("quick_search"), quicksearch);
621

Laurent Montel's avatar
Laurent Montel committed
622
623
624
    QWidgetAction *categoryFilter = new QWidgetAction(this);
    categoryFilter->setText(i18n("Category filter"));
    categoryFilter->setDefaultWidget(mCategorySelectWidget);
625
    collection->addAction(QStringLiteral("category_filter"), categoryFilter);
626

627
    action = collection->addAction(QStringLiteral("select_all"));
Laurent Montel's avatar
Laurent Montel committed
628
629
630
631
    action->setText(i18n("Select All"));
    collection->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_A));
    action->setWhatsThis(i18n("Select all contacts in the current address book view."));
    connect(action, &QAction::triggered, mItemView, &Akonadi::EntityTreeView::selectAll);
632

Laurent Montel's avatar
Laurent Montel committed
633
634
#if defined(HAVE_PRISON)
    KToggleAction *qrtoggleAction;
635
    qrtoggleAction = collection->add<KToggleAction>(QStringLiteral("options_show_qrcodes"));
Laurent Montel's avatar
Laurent Montel committed
636
637
638
639
    qrtoggleAction->setText(i18n("Show QR Codes"));
    qrtoggleAction->setWhatsThis(i18n("Show QR Codes in the contact."));
    connect(qrtoggleAction, &KToggleAction::toggled, this, &MainWidget::setQRCodeShow);
#endif
Laurent Montel's avatar
Laurent Montel committed
640

Laurent Montel's avatar
Laurent Montel committed
641
642
643
644
645
646
647
    mViewModeGroup = new QActionGroup(this);

    QAction *act = new QAction(i18nc("@action:inmenu", "Simple (one column)"), mViewModeGroup);
    act->setCheckable(true);
    act->setData(1);
    collection->setDefaultShortcut(act, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_1));
    act->setWhatsThis(i18n("Show a simple mode of the address book view."));
648
    collection->addAction(QStringLiteral("view_mode_simple"), act);
Laurent Montel's avatar
Laurent Montel committed
649
650
651
652

    act = new QAction(i18nc("@action:inmenu", "Two Columns"), mViewModeGroup);
    act->setCheckable(true);
    act->setData(2);
653
    collection->addAction(QStringLiteral("view_mode_2columns"), act);
Laurent Montel's avatar
Laurent Montel committed
654
655
656
657
658
659
    collection->setDefaultShortcut(act,  QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_2));

    act = new QAction(i18nc("@action:inmenu", "Three Columns"), mViewModeGroup);
    act->setCheckable(true);
    act->setData(3);
    collection->setDefaultShortcut(act, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_3));
660
    collection->addAction(QStringLiteral("view_mode_3columns"), act);
Laurent Montel's avatar
Laurent Montel committed
661
662
663
664

    connect(mViewModeGroup, SIGNAL(triggered(QAction*)), SLOT(setViewMode(QAction*)));

    // import actions
665
    action = collection->addAction(QStringLiteral("file_import_vcard"));
Laurent Montel's avatar
Laurent Montel committed
666
667
    action->setText(i18n("Import vCard..."));
    action->setWhatsThis(i18n("Import contacts from a vCard file."));
668
    mXXPortManager->addImportAction(action, QStringLiteral("vcard30"));
Laurent Montel's avatar
Laurent Montel committed
669

670
    action = collection->addAction(QStringLiteral("file_import_csv"));
Laurent Montel's avatar
Laurent Montel committed
671
672
    action->setText(i18n("Import CSV file..."));
    action->setWhatsThis(i18n("Import contacts from a file in comma separated value format."));
673
    mXXPortManager->addImportAction(action, QStringLiteral("csv"));
Laurent Montel's avatar
Laurent Montel committed
674

675
    action = collection->addAction(QStringLiteral("file_import_ldif"));
Laurent Montel's avatar
Laurent Montel committed
676
677
    action->setText(i18n("Import LDIF file..."));
    action->setWhatsThis(i18n("Import contacts from an LDIF file."));
678
    mXXPortManager->addImportAction(action, QStringLiteral("ldif"));
Laurent Montel's avatar
Laurent Montel committed
679

680
    action = collection->addAction(QStringLiteral("file_import_ldap"));
Laurent Montel's avatar
Laurent Montel committed
681
682
    action->setText(i18n("Import From LDAP server..."));
    action->setWhatsThis(i18n("Import contacts from an LDAP server."));
683
    mXXPortManager->addImportAction(action, QStringLiteral("ldap"));
Laurent Montel's avatar
Laurent Montel committed
684

685
    action = collection->addAction(QStringLiteral("file_import_gmx"));
Laurent Montel's avatar
Laurent Montel committed
686
687
    action->setText(i18n("Import GMX file..."));
    action->setWhatsThis(i18n("Import contacts from a GMX address book file."));
688
    mXXPortManager->addImportAction(action, QStringLiteral("gmx"));
Laurent Montel's avatar
Laurent Montel committed
689
690

    // export actions
691
    action = collection->addAction(QStringLiteral("file_export_vcard40"));
Laurent Montel's avatar
Laurent Montel committed
692
693
    action->setText(i18n("Export vCard 4.0..."));
    action->setWhatsThis(i18n("Export contacts to a vCard 4.0 file."));
694
    mXXPortManager->addExportAction(action, QStringLiteral("vcard40"));
Laurent Montel's avatar
Laurent Montel committed
695

696
    action = collection->addAction(QStringLiteral("file_export_vcard30"));
Laurent Montel's avatar
Laurent Montel committed
697
698
    action->setText(i18n("Export vCard 3.0..."));
    action->setWhatsThis(i18n("Export contacts to a vCard 3.0 file."));
699
    mXXPortManager->addExportAction(action, QStringLiteral("vcard30"));
Laurent Montel's avatar
Laurent Montel committed
700

701
    action = collection->addAction(QStringLiteral("file_export_vcard21"));
Laurent Montel's avatar
Laurent Montel committed
702
703
    action->setText(i18n("Export vCard 2.1..."));
    action->setWhatsThis(i18n("Export contacts to a vCard 2.1 file."));
704
    mXXPortManager->addExportAction(action, QStringLiteral("vcard21"));
Laurent Montel's avatar
Laurent Montel committed
705

706
    action = collection->addAction(QStringLiteral("file_export_csv"));
Laurent Montel's avatar
Laurent Montel committed
707
708
    action->setText(i18n("Export CSV file..."));
    action->setWhatsThis(i18n("Export contacts to a file in comma separated value format."));
709
    mXXPortManager->addExportAction(action, QStringLiteral("csv"));
Laurent Montel's avatar
Laurent Montel committed
710

711
    action = collection->addAction(QStringLiteral("file_export_ldif"));
Laurent Montel's avatar
Laurent Montel committed
712
713
    action->setText(i18n("Export LDIF file..."));
    action->setWhatsThis(i18n("Export contacts to an LDIF file."));
714
    mXXPortManager->addExportAction(action, QStringLiteral("ldif"));
Laurent Montel's avatar
Laurent Montel committed
715

716
    action = collection->addAction(QStringLiteral("file_export_gmx"));
Laurent Montel's avatar
Laurent Montel committed
717
718
    action->setText(i18n("Export GMX file..."));
    action->setWhatsThis(i18n("Export contacts to a GMX address book file."));
719
    mXXPortManager->addExportAction(action, QStringLiteral("gmx"));
Laurent Montel's avatar
Laurent Montel committed
720
721
722
723
724

    KToggleAction *actTheme = mGrantleeThemeManager->actionForTheme();
    if (actTheme) {
        actTheme->setChecked(true);
    }
725

Laurent Montel's avatar
Laurent Montel committed
726
727
    mQuickSearchAction = new QAction(i18n("Set Focus to Quick Search"), this);
    //If change shortcut change in quicksearchwidget->lineedit->setPlaceholderText
728
    collection->addAction(QStringLiteral("focus_to_quickseach"), mQuickSearchAction);
Laurent Montel's avatar
Laurent Montel committed
729
730
    connect(mQuickSearchAction, &QAction::triggered, mQuickSearchWidget, &QuickSearchWidget::slotFocusQuickSearch);
    collection->setDefaultShortcut(mQuickSearchAction, QKeySequence(Qt::ALT + Qt::Key_Q));
731

732
    if (!qEnvironmentVariableIsEmpty("KDEPIM_BALOO_DEBUG")) {
733
        action = collection->addAction(QStringLiteral("debug_baloo"));
Laurent Montel's avatar
Laurent Montel committed
734
        //Don't translate it. It's just for debug
735
        action->setText(QStringLiteral("Debug baloo..."));
Laurent Montel's avatar
Laurent Montel committed
736
        connect(action, &QAction::triggered, this, &MainWidget::slotDebugBaloo);
Laurent Montel's avatar
Laurent Montel committed
737
    }
738
739
740
741

    mServerSideSubscription = new QAction(QIcon::fromTheme(QStringLiteral("folder-bookmarks")), i18n("Serverside Subscription..."), this);
    collection->addAction(QStringLiteral("serverside_subscription"), mServerSideSubscription);
    connect(mServerSideSubscription, &QAction::triggered, this, &MainWidget::slotServerSideSubscription);
742
743
}

Laurent Montel's avatar
Laurent Montel committed
744
745
746
void MainWidget::printPreview()
{
    QPrinter printer;
Laurent Montel's avatar
Laurent Montel committed
747
748
749
750
    printer.setDocName(i18n("Address Book"));
    printer.setOutputFileName(Settings::self()->defaultFileName());
    printer.setOutputFormat(QPrinter::PdfFormat);
    printer.setCollateCopies(true);
Laurent Montel's avatar
Laurent Montel committed
751

Laurent Montel's avatar
Laurent Montel committed
752
753
754
    KPrintPreview previewdlg(&printer, this);
    KABPrinting::PrintingWizard wizard(&printer, mItemView->selectionModel(), this);
    wizard.setDefaultAddressBook(currentAddressBook());
Laurent Montel's avatar
Laurent Montel committed
755

Laurent Montel's avatar
Laurent Montel committed
756
    const int result = wizard.exec();
757
    if (result) {
Laurent Montel's avatar
Laurent Montel committed
758
759
760
        Settings::self()->setDefaultFileName(printer.outputFileName());
        Settings::self()->setPrintingStyle(wizard.printingStyle());
        Settings::self()->setSortOrder(wizard.sortOrder());
761
        previewdlg.exec();
762
    }
Laurent Montel's avatar
Laurent Montel committed
763
764
}

765
766
void MainWidget::print()
{
Laurent Montel's avatar
Laurent Montel committed
767
    QPrinter printer;
Laurent Montel's avatar
Laurent Montel committed
768
769
770
    printer.setDocName(i18n("Address Book"));
    printer.setOutputFileName(Settings::self()->defaultFileName());
    printer.setCollateCopies(true);
771

Volker Krause's avatar
Volker Krause committed
772
    QPointer<QPrintDialog> printDialog = new QPrintDialog(&printer, this);
Laurent Montel's avatar
Laurent Montel committed
773

Laurent Montel's avatar
Laurent Montel committed
774
775
    printDialog->setWindowTitle(i18n("Print Contacts"));
    if (!printDialog->exec() || !printDialog) {
776
        delete printDialog;
Laurent Montel's avatar
Laurent Montel committed
777
778
        return;
    }
Laurent Montel's avatar
Laurent Montel committed
779
780
    KABPrinting::PrintingWizard wizard(&printer, mItemView->selectionModel(), this);
    wizard.setDefaultAddressBook(currentAddressBook());
781

Laurent Montel's avatar
Laurent Montel committed
782
    wizard.exec(); //krazy:exclude=crashy
783

Laurent Montel's avatar
Laurent Montel committed
784
785
786
    Settings::self()->setDefaultFileName(printer.outputFileName());
    Settings::self()->setPrintingStyle(wizard.printingStyle());
    Settings::self()->setSortOrder(wizard.sortOrder());
787
788
789
790
}

void MainWidget::newContact()
{
Laurent Montel's avatar
Laurent Montel committed
791
    mActionManager->action(Akonadi::StandardContactActionManager::CreateContact)->trigger();
792
793
794
795
}

void MainWidget::newGroup()
{
Laurent Montel's avatar
Laurent Montel committed
796
    mActionManager->action(Akonadi::StandardContactActionManager::CreateContactGroup)->trigger();
797
798
799
800
801
802
803
}

/**
 * Depending on the mime type of the selected item, this method
 * brings up the right view on the detail view stack and sets the
 * selected item on it.
 */
Laurent Montel's avatar
Laurent Montel committed
804
void MainWidget::itemSelected(const Akonadi::Item &item)
805
{
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
806
    if (Akonadi::MimeTypeChecker::isWantedItem(item, KContacts::Addressee::mimeType())) {
Laurent Montel's avatar
Laurent Montel committed
807
808
        mDetailsViewStack->setCurrentWidget(mContactDetails);
        mContactDetails->setContact(item);
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
809
    } else if (Akonadi::MimeTypeChecker::isWantedItem(item, KContacts::ContactGroup::mimeType())) {
Laurent Montel's avatar
Laurent Montel committed
810
811
        mDetailsViewStack->setCurrentWidget(mContactGroupDetails);
        mContactGroupDetails->setContactGroup(item);
Laurent Montel's avatar
Laurent Montel committed
812
    }
813
814
}

815
816
817
818
/**
 * Catch when the selection has gone ( e.g. an empty address book has been selected )
 * clear the details view in this case.
 */
Laurent Montel's avatar
Laurent Montel committed
819
void MainWidget::itemSelectionChanged(const QModelIndex &current, const QModelIndex &)
820
{
Laurent Montel's avatar
Laurent Montel committed
821
822
    if (!current.isValid()) {
        mDetailsViewStack->setCurrentWidget(mEmptyDetails);
Laurent Montel's avatar
Laurent Montel committed
823
    }
824
825
}

826
827
void MainWidget::selectFirstItem()
{
Laurent Montel's avatar
Laurent Montel committed
828
829
    // Whenever the quick search has changed, we select the first item
    // in the item view, so that the detailsview is updated
Laurent Montel's avatar
Laurent Montel committed
830
831
832
833
    if (mItemView && mItemView->selectionModel()) {
        mItemView->selectionModel()->setCurrentIndex(mItemView->model()->index(0, 0),
                QItemSelectionModel::Rows |
                QItemSelectionModel::ClearAndSelect);
Laurent Montel's avatar
Laurent Montel committed
834
    }
835
836
}

837
838
839
bool MainWidget::showQRCodes()
{
#if defined(HAVE_PRISON)
840
841
    KConfig config(QStringLiteral("akonadi_contactrc"));
    KConfigGroup group(&config, QStringLiteral("View"));
Laurent Montel's avatar
Laurent Montel committed
842
    return group.readEntry("QRCodes", true);
843
#else
Laurent Montel's avatar
Laurent Montel committed
844
    return true;
845
846
847
#endif
}

Laurent Montel's avatar
Laurent Montel committed
848
void MainWidget::setQRCodeShow(bool on)
849
850
{
#if defined(HAVE_PRISON)
Laurent Montel's avatar
Laurent Montel committed
851
    // must write the configuration setting first before updating the view.
852
853
    KConfig config(QStringLiteral("akonadi_contactrc"));
    KConfigGroup group(&config, QStringLiteral("View"));
Laurent Montel's avatar
Laurent Montel committed
854
    group.writeEntry("QRCodes", on);
855
856
    group.sync();
    if (mDetailsViewStack->currentWidget() == mContactDetails) {
857
858
        mFormatter->setShowQRCode(on);
        mContactDetails->setShowQRCode(on);
Laurent Montel's avatar
Laurent Montel committed
859
    }
860
#else
Laurent Montel's avatar
Laurent Montel committed
861
    Q_UNUSED(on);
862
863
864
#endif
}

Laurent Montel's avatar
Laurent Montel committed
865
866
867
868
869
870
871
872
873
874
875
Akonadi::Item::List MainWidget::selectedItems()
{
    Akonadi::Item::List items;
    QPointer<ContactSelectionDialog> dlg =
        new ContactSelectionDialog(mItemView->selectionModel(), false, this);
    dlg->setDefaultAddressBook(currentAddressBook());
    if (!dlg->exec() || !dlg) {
        delete dlg;
        return items;
    }

Laurent Montel's avatar
Laurent Montel committed
876
    items = dlg->selectedItems();
Laurent Montel's avatar
Laurent Montel committed
877
878
879
880
881
    delete dlg;

    return items;
}

882
883
Akonadi::Collection MainWidget::currentAddressBook() const
{
Laurent Montel's avatar
Laurent Montel committed
884
    if (mCollectionView->selectionModel() && mCollectionView->selectionModel()->hasSelection()) {
Laurent Montel's avatar
Laurent Montel committed
885
886
        const QModelIndex index = mCollectionView->selectionModel()->selectedIndexes().first();
        const Akonadi::Collection collection =
Laurent Montel's avatar
Laurent Montel committed
887
            index.data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
888

Laurent Montel's avatar
Laurent Montel committed
889
890
        return collection;
    }
891

Laurent Montel's avatar
Laurent Montel committed
892
    return Akonadi::Collection();
893
894
}

Allen Winter's avatar
Allen Winter committed
895
QAbstractItemModel *MainWidget::allContactsModel()
896
{
Laurent Montel's avatar
Laurent Montel committed
897
898
899
900
901
902
903
904
    if (!mAllContactsModel) {
        KDescendantsProxyModel *descendantsModel = new KDescendantsProxyModel(this);
        descendantsModel->setSourceModel(GlobalContactModel::instance()->model());

        mAllContactsModel = new Akonadi::EntityMimeTypeFilterModel(this);
        mAllContactsModel->setSourceModel(descendantsModel);
        mAllContactsModel->addMimeTypeExclusionFilter(Akonadi::Collection::mimeType());
        mAllContactsModel->setHeaderGroup(Akonadi::EntityTreeModel::ItemListHeaders);
Laurent Montel's avatar
Laurent Montel committed
905
    }
906

Laurent Montel's avatar
Laurent Montel committed
907
    return mAllContactsModel;
908
909
}

Laurent Montel's avatar
Laurent Montel committed
910
void MainWidget::setViewMode(QAction *action)
911
{
Laurent Montel's avatar
Laurent Montel committed
912
    setViewMode(action->data().toInt());
913
914
}

Laurent Montel's avatar
Laurent Montel committed
915
void MainWidget::setViewMode(int mode)
916
{
Laurent Montel's avatar
Laurent Montel committed
917
    int currentMode = Settings::self()->viewMode();
Laurent Montel's avatar
Laurent Montel committed
918
    //qCDebug(KADDRESSBOOK_LOG) << "cur" << currentMode << "new" << mode;
Laurent Montel's avatar
Laurent Montel committed
919
920
921
    if (mode == currentMode) {
        return;    // nothing to do
    }
922

Laurent Montel's avatar
Laurent Montel committed
923
    if (mode == 0) {
Laurent Montel's avatar
Laurent Montel committed
924
925
926
        mode = currentMode;// initialisation, no save
    } else {
        saveSplitterStates();                                // for 2- or 3-column mode
927
    }
Laurent Montel's avatar
Laurent Montel committed
928
929
930
931
932
933
934
    if (mode == 1) {                                          // simple mode
        mMainWidgetSplitter2->setVisible(false);
        mDetailsPane->setVisible(true);
        mContactSwitcher->setVisible(true);
    } else {
        mMainWidgetSplitter2->setVisible(true);
        mContactSwitcher->setVisible(false);
935

Laurent Montel's avatar
Laurent Montel committed
936
937
938
939
        if (mode == 2) {                                          // 2 columns
            mMainWidgetSplitter2->setOrientation(Qt::Vertical);
        } else if (mode == 3) {                                // 3 columns
            mMainWidgetSplitter2->setOrientation(Qt::Horizontal);
Laurent Montel's avatar
Laurent Montel committed
940
        }
941
942
    }

Laurent Montel's avatar
Laurent Montel committed
943
    Settings::self()->setViewMode(mode);                  // save new mode in settings
Laurent Montel's avatar
Laurent Montel committed
944
    restoreSplitterStates();                                // restore state for new mode
Laurent Montel's avatar
Laurent Montel committed
945
    mViewModeGroup->actions().at(mode - 1)->setChecked(true);
946

Laurent Montel's avatar
Laurent Montel committed
947
948
    if (mItemView->model()) {
        mItemView->setCurrentIndex(mItemView->model()->index(0, 0));
Laurent Montel's avatar
Laurent Montel committed
949
    }
950
951
952
953
}

void MainWidget::saveSplitterStates() const
{
Laurent Montel's avatar
Laurent Montel committed
954
955
956
    // The splitter states are saved separately for each column view mode,
    // but only if not in simple mode (1 column).
    int currentMode = Settings::self()->viewMode();
Laurent Montel's avatar
Laurent Montel committed
957
    if (currentMode == 1) {
Laurent Montel's avatar
Laurent Montel committed
958
        return;
Laurent Montel's avatar
Laurent Montel committed
959
    }
960

Laurent Montel's avatar
Laurent Montel committed
961
    const QString groupName = QStringLiteral("UiState_MainWidgetSplitter_%1").arg(currentMode);
Laurent Montel's avatar
Laurent Montel committed
962
    //qCDebug(KADDRESSBOOK_LOG) << "saving to group" << groupName;
Laurent Montel's avatar
Laurent Montel committed
963
964
965
    KConfigGroup group(Settings::self()->config(), groupName);
    KPIM::UiStateSaver::saveState(mMainWidgetSplitter1, group);
    KPIM::UiStateSaver::saveState(mMainWidgetSplitter2, group);
966
967
968
969
}

void MainWidget::restoreSplitterStates()
{
Laurent Montel's avatar
Laurent Montel committed
970
971
972
    // The splitter states are restored as appropriate for the current
    // column view mode, but not for simple mode (1 column).
    int currentMode = Settings::self()->viewMode();
Laurent Montel's avatar
Laurent Montel committed
973
    if (currentMode == 1) {
Laurent Montel's avatar
Laurent Montel committed
974
        return;
Laurent Montel's avatar
Laurent Montel committed
975
    }
976