akonadicollectionview.cpp 42.7 KB
Newer Older
1
2
3
4
5
6
/*
  This file is part of KOrganizer.

  Copyright (c) 2003,2004 Cornelius Schumacher <schumacher@kde.org>
  Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
  Copyright (C) 2009 Sebastian Sauer <sebsauer@kdab.net>
Laurent Montel's avatar
Laurent Montel committed
7
  Copyright (c) 2010-2017 Laurent Montel <montel@kde.org>
Sergio Martins's avatar
Sergio Martins committed
8
  Copyright (C) 2012 Sérgio Martins <iamsergio@gmail.com>
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

  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.

  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.

  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.

  As a special exception, permission is given to link this program
  with any edition of Qt, and distribute the resulting executable,
  without including the source code for Qt in the source distribution.
*/

#include "akonadicollectionview.h"
#include "kocore.h"
#include "kohelper.h"
Laurent Montel's avatar
Laurent Montel committed
32
#include "prefs/koprefs.h"
33
#include "koglobals.h"
34
#include "manageshowcollectionproperties.h"
35
36
#include "views/collectionview/reparentingmodel.h"
#include "views/collectionview/calendardelegate.h"
37
#include "views/collectionview/quickview.h"
38

Laurent Montel's avatar
Laurent Montel committed
39
40
#include <CalendarSupport/KCalPrefs>
#include <CalendarSupport/Utils>
41

Laurent Montel's avatar
Laurent Montel committed
42
43
44
#include <AkonadiCore/AgentFilterProxyModel>
#include <AkonadiCore/AgentInstanceCreateJob>
#include <AkonadiCore/AgentManager>
Laurent Montel's avatar
Laurent Montel committed
45
#include <AkonadiWidgets/AgentTypeDialog>
Laurent Montel's avatar
Laurent Montel committed
46
#include <AkonadiCore/CollectionDeleteJob>
Laurent Montel's avatar
Laurent Montel committed
47
48
49
50
51
#include <AkonadiCore/CollectionFilterProxyModel>
#include <AkonadiCore/EntityDisplayAttribute>
#include <AkonadiWidgets/EntityTreeView>
#include <AkonadiCore/EntityTreeModel>
#include <AkonadiWidgets/ETMViewStateSaver>
52
#include <Akonadi/Calendar/StandardCalendarActionManager>
53
#include <AkonadiCore/CollectionIdentificationAttribute>
54
#include <pimcommon/manageserversidesubscriptionjob.h>
Laurent Montel's avatar
Laurent Montel committed
55
#include "PimCommon/PimUtil"
56

57
#include <KActionCollection>
58
#include <KCheckableProxyModel>
59
#include <KConfigGroup>
60
#include <KMessageBox>
Sergio Martins's avatar
Sergio Martins committed
61
#include <KRecursiveFilterProxyModel>
Laurent Montel's avatar
Laurent Montel committed
62
#include "korganizer_debug.h"
63

64
65
66
#include <QAction>
#include <QColorDialog>
#include <QDialog>
67
#include <QHeaderView>
68
#include <QLineEdit>
69
#include <QPainter>
70
#include <QStackedWidget>
71
72
#include <QStyledItemDelegate>
#include <QVBoxLayout>
73
74
75
76
77

static Akonadi::EntityTreeModel *findEtm(QAbstractItemModel *model)
{
    QAbstractProxyModel *proxyModel;
    while (model) {
78
        proxyModel = qobject_cast<QAbstractProxyModel *>(model);
79
80
81
82
83
84
        if (proxyModel && proxyModel->sourceModel()) {
            model = proxyModel->sourceModel();
        } else {
            break;
        }
    }
85
    return qobject_cast<Akonadi::EntityTreeModel *>(model);
86
87
88
89
90
}

/**
* Automatically checks new calendar entries
*/
91
92
class NewCalendarChecker : public QObject
{
93
94
95
    Q_OBJECT
public:
    NewCalendarChecker(QAbstractItemModel *model)
96
97
        : QObject(model),
          mCheckableProxy(model)
98
    {
99
        connect(model, &QAbstractItemModel::rowsInserted, this, &NewCalendarChecker::onSourceRowsInserted);
100
        qRegisterMetaType<QPersistentModelIndex>("QPersistentModelIndex");
101
102
    }

Laurent Montel's avatar
Laurent Montel committed
103
private Q_SLOTS:
104
105
106
107
108
109
110
    void onSourceRowsInserted(const QModelIndex &parent, int start, int end)
    {
        Akonadi::EntityTreeModel *etm = findEtm(mCheckableProxy);
        //Only check new collections and not during initial population
        if (!etm || !etm->isCollectionTreeFetched()) {
            return;
        }
111
112
        for (int i = start; i <= end; ++i) {
            qCDebug(KORGANIZER_LOG) << "checking " << i << parent << mCheckableProxy->index(i, 0, parent).data().toString();
113
            const QModelIndex index = mCheckableProxy->index(i, 0, parent);
114
115
116
117
118
119
120
121
            QMetaObject::invokeMethod(this, "setCheckState", Qt::QueuedConnection, QGenericReturnArgument(), Q_ARG(QPersistentModelIndex, index));
        }
    }
    void setCheckState(const QPersistentModelIndex &index)
    {
        mCheckableProxy->setData(index, Qt::Checked, Qt::CheckStateRole);
        if (mCheckableProxy->hasChildren(index)) {
            onSourceRowsInserted(index, 0, mCheckableProxy->rowCount(index) - 1);
122
123
124
125
126
127
128
129
130
131
132
133
134
        }
    }

private:
    QAbstractItemModel *mCheckableProxy;
};

/**
* Handles expansion state of a treeview
*
* Persists state, and automatically expands new entries.
* With expandAll enabled this class simply ensures that all indexes are fully expanded.
*/
135
136
class NewNodeExpander : public QObject
{
137
138
139
    Q_OBJECT
public:
    NewNodeExpander(QTreeView *view, bool expandAll, const QString &treeStateConfig)
140
141
142
143
        : QObject(view),
          mTreeView(view),
          mExpandAll(expandAll),
          mTreeStateConfig(treeStateConfig)
144
    {
145
146
147
        connect(view->model(), &QAbstractItemModel::rowsInserted, this, &NewNodeExpander::onSourceRowsInserted);
        connect(view->model(), &QAbstractItemModel::layoutChanged, this, &NewNodeExpander::onLayoutChanged);
        connect(view->model(), &QAbstractItemModel::modelReset, this, &NewNodeExpander::onModelReset);
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
        restoreTreeState();
    }

    virtual ~NewNodeExpander()
    {
        //Ideally we'd automatically save the treestate of the parent view here,
        //but that unfortunately doesn't seem to work
    }

public Q_SLOTS:
    void saveState()
    {
        saveTreeState();
    }

private Q_SLOTS:
    void onSourceRowsInserted(const QModelIndex &parent, int start, int end)
    {
        //The initial expansion is handled by the state saver
        if (!mExpandAll) {
            Akonadi::EntityTreeModel *etm = findEtm(mTreeView->model());
            if (!etm || !etm->isCollectionTreeFetched()) {
                restoreTreeState();
                return;
            }
        }
174
        for (int i = start; i <= end; ++i) {
175
            const QModelIndex index = mTreeView->model()->index(i, 0, parent);
176
            // qCDebug(KORGANIZER_LOG) << "expanding " << index.data().toString();
177
178
179
180
181
            if (index.data(NodeTypeRole).toInt() == PersonNodeRole) {
                mTreeView->collapse(index);
            } else {
                mTreeView->expand(index);
            }
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
            if (mTreeView->model()->hasChildren(index)) {
                onSourceRowsInserted(index, 0, mTreeView->model()->rowCount(index) - 1);
            }
        }
    }

    void onLayoutChanged()
    {
        if (mExpandAll) {
            onSourceRowsInserted(QModelIndex(), 0, mTreeView->model()->rowCount(QModelIndex()) - 1);
        }
    }

    void onModelReset()
    {
        if (mExpandAll) {
            onSourceRowsInserted(QModelIndex(), 0, mTreeView->model()->rowCount(QModelIndex()) - 1);
        }
    }

private:
    void saveTreeState()
    {
        Akonadi::ETMViewStateSaver treeStateSaver;
206
207
        KSharedConfig::Ptr config = KSharedConfig::openConfig();
        KConfigGroup group = config->group(mTreeStateConfig);
208
209
210
211
212
213
214
215
216
217
218
219
220
221
        treeStateSaver.setView(mTreeView);
        treeStateSaver.setSelectionModel(0); // we only save expand state
        treeStateSaver.saveState(group);
    }

    void restoreTreeState()
    {
        if (mTreeStateConfig.isEmpty()) {
            return;
        }
        //Otherwise ETMViewStateSaver crashes
        if (!findEtm(mTreeView->model())) {
            return;
        }
222
        if (treeStateRestorer) {  // We don't need more than one to be running at the same time
223
224
            delete treeStateRestorer;
        }
225
        qCDebug(KORGANIZER_LOG) << "Restore tree state";
226
        treeStateRestorer = new Akonadi::ETMViewStateSaver(); // not a leak
227
        KConfigGroup group(KSharedConfig::openConfig(), mTreeStateConfig);
228
229
230
        treeStateRestorer->setView(mTreeView);
        treeStateRestorer->setSelectionModel(0);   // we only restore expand state
        treeStateRestorer->restoreState(group);
231
232
233
234
235
236
237
    }

    QPointer<Akonadi::ETMViewStateSaver> treeStateRestorer;
    QTreeView *mTreeView;
    bool mExpandAll;
    QString mTreeStateConfig;
};
238

Laurent Montel's avatar
Laurent Montel committed
239
AkonadiCollectionViewFactory::AkonadiCollectionViewFactory(CalendarView *view)
Laurent Montel's avatar
Laurent Montel committed
240
    : mView(view), mAkonadiCollectionView(nullptr)
241
242
243
{
}

Laurent Montel's avatar
Laurent Montel committed
244
245
namespace
{
246

Laurent Montel's avatar
Laurent Montel committed
247
static bool hasCompatibleMimeTypes(const Akonadi::Collection &collection)
248
{
Laurent Montel's avatar
Laurent Montel committed
249
250
251
    static QStringList goodMimeTypes;

    if (goodMimeTypes.isEmpty()) {
252
        goodMimeTypes << QStringLiteral("text/calendar")
Laurent Montel's avatar
Laurent Montel committed
253
254
255
256
257
258
259
260
261
                      << KCalCore::Event::eventMimeType()
                      << KCalCore::Todo::todoMimeType()
                      << KCalCore::Journal::journalMimeType();
    }

    for (int i = 0; i < goodMimeTypes.count(); ++i) {
        if (collection.contentMimeTypes().contains(goodMimeTypes.at(i))) {
            return true;
        }
262
    }
263

Laurent Montel's avatar
Laurent Montel committed
264
    return false;
265
266
}

267
class SortProxyModel : public QSortFilterProxyModel
Allen Winter's avatar
Allen Winter committed
268
{
Laurent Montel's avatar
Laurent Montel committed
269
public:
Laurent Montel's avatar
Laurent Montel committed
270
    explicit SortProxyModel(QObject *parent = nullptr)
271
        : QSortFilterProxyModel(parent)
Allen Winter's avatar
Allen Winter committed
272
    {
273
        setDynamicSortFilter(true);
Allen Winter's avatar
Allen Winter committed
274
275
    }

276
    static int score(const QModelIndex &index)
277
    {
278
279
280
        int score = 0;
        if (index.data(PersonRole).isValid()) {
            score += 1;
281
        }
282
283
        if (index.data(IsSearchResultRole).toBool()) {
            score += 2;
284
        }
285
286
287
        //Search collection
        if (index.data(Akonadi::EntityTreeModel::CollectionIdRole).toLongLong() == 1) {
            score += 3;
288
        }
289
290
291
        return score;
    }

292
    bool lessThan(const QModelIndex &left, const QModelIndex &right) const Q_DECL_OVERRIDE
293
294
295
    {
        const int leftScore = score(left);
        const int rightScore = score(right);
296
        // qCDebug(KORGANIZER_LOG) << left.data().toString() << leftScore << " : " << right.data().toString() << rightScore;
297
298
        if (leftScore != rightScore) {
            return leftScore < rightScore;
299
        }
300
301

        return QString::localeAwareCompare(left.data().toString(), right.data().toString()) < 0;
302
    }
Allen Winter's avatar
Allen Winter committed
303
};
304

Allen Winter's avatar
Allen Winter committed
305
306
class ColorProxyModel : public QSortFilterProxyModel
{
Laurent Montel's avatar
Laurent Montel committed
307
public:
Laurent Montel's avatar
Laurent Montel committed
308
    explicit ColorProxyModel(QObject *parent = nullptr)
Laurent Montel's avatar
Laurent Montel committed
309
        : QSortFilterProxyModel(parent), mInitDefaultCalendar(false)
Allen Winter's avatar
Allen Winter committed
310
311
    {
    }
312

Laurent Montel's avatar
Laurent Montel committed
313
    QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE
314
    {
Laurent Montel's avatar
Laurent Montel committed
315
316
        if (!index.isValid()) {
            return QVariant();
Allen Winter's avatar
Allen Winter committed
317
        }
Laurent Montel's avatar
Laurent Montel committed
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
        if (role == Qt::DecorationRole) {
            const Akonadi::Collection collection = CalendarSupport::collectionFromIndex(index);

            if (hasCompatibleMimeTypes(collection)) {
                if (collection.hasAttribute<Akonadi::EntityDisplayAttribute>() &&
                        !collection.attribute<Akonadi::EntityDisplayAttribute>()->iconName().isEmpty()) {
                    return collection.attribute<Akonadi::EntityDisplayAttribute>()->icon();
                }
            }
        } else if (role == Qt::FontRole) {
            const Akonadi::Collection collection = CalendarSupport::collectionFromIndex(index);
            if (!collection.contentMimeTypes().isEmpty() &&
                    KOHelper::isStandardCalendar(collection.id()) &&
                    collection.rights() & Akonadi::Collection::CanCreateItem) {
                QFont font = qvariant_cast<QFont>(QSortFilterProxyModel::data(index, Qt::FontRole));
                font.setBold(true);
                if (!mInitDefaultCalendar) {
                    mInitDefaultCalendar = true;
                    CalendarSupport::KCalPrefs::instance()->setDefaultCalendarId(collection.id());
                }
                return font;
            }
Allen Winter's avatar
Allen Winter committed
340
        }
341

Laurent Montel's avatar
Laurent Montel committed
342
        return QSortFilterProxyModel::data(index, role);
Allen Winter's avatar
Allen Winter committed
343
344
    }

Laurent Montel's avatar
Laurent Montel committed
345
    Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE
Allen Winter's avatar
Allen Winter committed
346
    {
Laurent Montel's avatar
Laurent Montel committed
347
        return Qt::ItemIsSelectable | QSortFilterProxyModel::flags(index);
Allen Winter's avatar
Allen Winter committed
348
    }
349

Laurent Montel's avatar
Laurent Montel committed
350
private:
351
    mutable bool mInitDefaultCalendar;
Allen Winter's avatar
Allen Winter committed
352
353
};

354
355
class CollectionFilter : public QSortFilterProxyModel
{
356
public:
Laurent Montel's avatar
Laurent Montel committed
357
    explicit CollectionFilter(QObject *parent = nullptr)
358
        : QSortFilterProxyModel(parent)
359
360
361
362
    {
        setDynamicSortFilter(true);
    }

363
protected:
Laurent Montel's avatar
Laurent Montel committed
364
    bool filterAcceptsRow(int row, const QModelIndex &sourceParent) const Q_DECL_OVERRIDE
365
    {
366
367
        const QModelIndex sourceIndex = sourceModel()->index(row, 0, sourceParent);
        Q_ASSERT(sourceIndex.isValid());
368
        const Akonadi::Collection &col = sourceIndex.data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
369
        Akonadi::CollectionIdentificationAttribute *attr = col.attribute<Akonadi::CollectionIdentificationAttribute>();
370
        //We filter the user folders because we insert person nodes for user folders.
371
372
        if ((attr && attr->collectionNamespace().startsWith("usertoplevel"))
                || col.name().contains(QStringLiteral("Other Users"))) {
373
374
375
376
377
378
            return false;
        }
        return true;
    }
};

379
380
381
class EnabledModel : public QSortFilterProxyModel
{
public:
Laurent Montel's avatar
Laurent Montel committed
382
    explicit EnabledModel(QObject *parent = nullptr)
383
        : QSortFilterProxyModel(parent)
384
385
386
387
388
    {
    }

protected:

Laurent Montel's avatar
Laurent Montel committed
389
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE
390
391
392
    {
        if (role == EnabledRole) {
            Akonadi::Collection col = index.data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
393
            if (col.enabled()) {
394
395
396
397
398
399
400
401
402
403
404
405
                return Qt::Checked;
            } else {
                return Qt::Unchecked;
            }
        }
        return QSortFilterProxyModel::data(index, role);
    }
};

class CalendarDelegateModel : public QSortFilterProxyModel
{
public:
Laurent Montel's avatar
Laurent Montel committed
406
    explicit CalendarDelegateModel(QObject *parent = nullptr)
407
        : QSortFilterProxyModel(parent)
408
409
410
411
412
413
414
    {
    }

protected:
    bool checkChildren(const QModelIndex &index, int role, const QVariant &value) const
    {
        const QModelIndex sourceIndex = mapToSource(index);
415
        for (int i = 0; i < sourceModel()->rowCount(sourceIndex); ++i) {
416
417
418
419
420
421
422
423
            const QModelIndex child = sourceModel()->index(i, 0, sourceIndex);
            if (child.data(role) != value) {
                return false;
            }
        }
        return true;
    }

424
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
    {
        if (role == Qt::CheckStateRole) {
            if (sourceModel()->hasChildren(mapToSource(index)) && index.data(NodeTypeRole).toInt() == PersonNodeRole) {
                bool allChecked = checkChildren(index, role, Qt::Checked);
                bool allUnchecked = checkChildren(index, role, Qt::Unchecked);
                if (allChecked) {
                    return Qt::Checked;
                } else if (allUnchecked) {
                    return Qt::Unchecked;
                } else {
                    return Qt::PartiallyChecked;
                }
            }
        }
        if (role == EnabledRole) {
            if (sourceModel()->hasChildren(mapToSource(index)) && index.data(NodeTypeRole).toInt() == PersonNodeRole) {
                bool allChecked = checkChildren(index, role, Qt::Checked);
                bool allUnchecked = checkChildren(index, role, Qt::Unchecked);
443
                // qCDebug(KORGANIZER_LOG) << "person node " << index.data().toString() << allChecked << allUnchecked;
444
445
446
447
448
449
450
451
452
453
454
455
                if (allChecked) {
                    return Qt::Checked;
                } else if (allUnchecked) {
                    return Qt::Unchecked;
                } else {
                    return Qt::PartiallyChecked;
                }
            }
        }

        return QSortFilterProxyModel::data(index, role);
    }
456
457
458
459
460
461

    void setChildren(const QModelIndex &sourceIndex, const QVariant &value, int role) const
    {
        if (!sourceIndex.isValid()) {
            return;
        }
462
        for (int i = 0; i < sourceModel()->rowCount(sourceIndex); ++i) {
463
464
465
466
467
468
            const QModelIndex child = sourceModel()->index(i, 0, sourceIndex);
            sourceModel()->setData(child, value, role);
            setChildren(child, value, role);
        }
    }

Laurent Montel's avatar
Laurent Montel committed
469
470
471
    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE {
        if (role == Qt::CheckStateRole)
        {
472
473
474
475
476
477
            if (sourceModel()->hasChildren(mapToSource(index)) && index.data(NodeTypeRole).toInt() == PersonNodeRole) {
                setChildren(mapToSource(index), value, role);
            }
        }
        return QSortFilterProxyModel::setData(index, value, role);
    }
478
479
};

Allen Winter's avatar
Allen Winter committed
480
} // anonymous namespace
481

Laurent Montel's avatar
Laurent Montel committed
482
CalendarViewExtension *AkonadiCollectionViewFactory::create(QWidget *parent)
483
{
Laurent Montel's avatar
Laurent Montel committed
484
485
486
487
    mAkonadiCollectionView = new AkonadiCollectionView(view(), true, parent);
    QObject::connect(mAkonadiCollectionView, &AkonadiCollectionView::resourcesChanged, mView, &CalendarView::resourcesChanged);
    QObject::connect(mAkonadiCollectionView, &AkonadiCollectionView::resourcesAddedRemoved, mView, &CalendarView::resourcesChanged);
    return mAkonadiCollectionView;
488
489
}

Allen Winter's avatar
Allen Winter committed
490
CalendarView *AkonadiCollectionViewFactory::view() const
491
{
Laurent Montel's avatar
Laurent Montel committed
492
    return mView;
493
494
}

Allen Winter's avatar
Allen Winter committed
495
AkonadiCollectionView *AkonadiCollectionViewFactory::collectionView() const
496
{
Laurent Montel's avatar
Laurent Montel committed
497
    return mAkonadiCollectionView;
498
499
}

Laurent Montel's avatar
Laurent Montel committed
500
501
502
AkonadiCollectionView::AkonadiCollectionView(CalendarView *view, bool hasContextMenu,
        QWidget *parent)
    : CalendarViewExtension(parent),
Laurent Montel's avatar
Laurent Montel committed
503
504
505
506
507
508
509
510
511
      mActionManager(nullptr),
      mCollectionView(nullptr),
      mBaseModel(nullptr),
      mSelectionProxyModel(nullptr),
      mAssignColor(nullptr),
      mDisableColor(nullptr),
      mDefaultCalendar(nullptr),
      mEnableAction(nullptr),
      mServerSideSubscription(nullptr),
Laurent Montel's avatar
Laurent Montel committed
512
513
514
      mNotSendAddRemoveSignal(false),
      mWasDefaultCalendar(false),
      mHasContextMenu(hasContextMenu)
515
{
Laurent Montel's avatar
Laurent Montel committed
516
    mManagerShowCollectionProperties = new ManageShowCollectionProperties(this, this);
517

Laurent Montel's avatar
Laurent Montel committed
518
519
    QVBoxLayout *topLayout = new QVBoxLayout(this);
    topLayout->setMargin(0);
520

521
    QLineEdit *searchCol = new QLineEdit(this);
522
523
    searchCol->setClearButtonEnabled(true);
    searchCol->setPlaceholderText(i18nc("@info/plain Displayed grayed-out inside the "
Laurent Montel's avatar
Laurent Montel committed
524
                                        "textbox, verb to search", "Search"));
525
    topLayout->addWidget(searchCol);
Laurent Montel's avatar
Laurent Montel committed
526
527

    ColorProxyModel *colorProxy = new ColorProxyModel(this);
528
    colorProxy->setObjectName(QStringLiteral("Show calendar colors"));
Laurent Montel's avatar
Laurent Montel committed
529
530
531
    colorProxy->setDynamicSortFilter(true);
    mBaseModel = colorProxy;

532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
    //Model that displays users
    ReparentingModel *userProxy = new ReparentingModel(this);
    userProxy->setNodeManager(ReparentingModel::NodeManager::Ptr(new PersonNodeManager(*userProxy)));
    userProxy->setSourceModel(colorProxy);

    EnabledModel *enabledModel = new EnabledModel(this);
    enabledModel->setSourceModel(userProxy);

    CalendarDelegateModel *calendarDelegateModel = new CalendarDelegateModel(this);
    calendarDelegateModel->setSourceModel(enabledModel);

    //Hide collections that are not required
    CollectionFilter *collectionFilter = new CollectionFilter(this);
    collectionFilter->setSourceModel(calendarDelegateModel);

    SortProxyModel *sortProxy = new SortProxyModel(this);
    sortProxy->setSourceModel(collectionFilter);
    sortProxy->setObjectName(QStringLiteral("sortproxy"));

Laurent Montel's avatar
Laurent Montel committed
551
552
553
    mCollectionView = new Akonadi::EntityTreeView(this);
    mCollectionView->header()->hide();
    mCollectionView->setRootIsDecorated(true);
554
555
556
557
558
    // mCollectionView->setSorting( true );
    {
        StyledCalendarDelegate *delegate = new StyledCalendarDelegate(mCollectionView);
        connect(delegate, &StyledCalendarDelegate::action, this, &AkonadiCollectionView::onAction);
        mCollectionView->setItemDelegate(delegate);
559
    }
560
561
562
    mCollectionView->setModel(sortProxy);
    connect(mCollectionView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &AkonadiCollectionView::updateMenu);
    mNewNodeExpander = new NewNodeExpander(mCollectionView, false, QStringLiteral("CollectionTreeView"));
Laurent Montel's avatar
Laurent Montel committed
563
564

    //Filter tree view.
565
566
567
568
569
570
571
572
573
574
    ReparentingModel *searchProxy = new ReparentingModel(this);
    searchProxy->setSourceModel(collectionFilter);
    searchProxy->setObjectName(QStringLiteral("searchProxy"));

    KRecursiveFilterProxyModel *filterTreeViewModel = new KRecursiveFilterProxyModel(this);
    filterTreeViewModel->setDynamicSortFilter(true);
    filterTreeViewModel->setSourceModel(searchProxy);
    filterTreeViewModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
//   filterTreeViewModel->setObjectName( "Recursive filtering, for the search bar" );
    connect(searchCol, &QLineEdit::textChanged, filterTreeViewModel, &KRecursiveFilterProxyModel::setFilterWildcard);
575

576
577
    SortProxyModel *searchSortProxy = new SortProxyModel(this);
    searchSortProxy->setSourceModel(filterTreeViewModel);
578

579
580
581
582
583
584
585
    Akonadi::EntityTreeView *mSearchView = new Akonadi::EntityTreeView(this);
    mSearchView->header()->hide();
    mSearchView->setRootIsDecorated(true);
    {
        StyledCalendarDelegate *delegate = new StyledCalendarDelegate(mCollectionView);
        connect(delegate, &StyledCalendarDelegate::action, this, &AkonadiCollectionView::onAction);
        mSearchView->setItemDelegate(delegate);
586
    }
587
588
589
590
591
592
    mSearchView->setModel(searchSortProxy);
    new NewNodeExpander(mSearchView, true, QString());

    mController = new Controller(userProxy, searchProxy, this);
    connect(searchCol, &QLineEdit::textChanged, mController, &Controller::setSearchString);
    connect(mController, &Controller::searchIsActive, this, &AkonadiCollectionView::onSearchIsActive);
Laurent Montel's avatar
Laurent Montel committed
593

594
595
596
597
    mStackedWidget = new QStackedWidget(this);
    mStackedWidget->addWidget(mCollectionView);
    mStackedWidget->addWidget(mSearchView);
    mStackedWidget->setCurrentWidget(mCollectionView);
Laurent Montel's avatar
Laurent Montel committed
598

599
600
601
602
603
604
605
606
607
608
    topLayout->addWidget(mStackedWidget);

    KMessageWidget *msgWidget = new KMessageWidget(this);
    msgWidget->setCloseButtonVisible(false);
    msgWidget->setMessageType(KMessageWidget::Positive);
    msgWidget->setObjectName(QStringLiteral("msgwidget"));
    msgWidget->setVisible(false);
    msgWidget->setText(i18n("searching..."));
    connect(mController, &Controller::searching, msgWidget, &KMessageWidget::setVisible);
    topLayout->addWidget(msgWidget);
Laurent Montel's avatar
Laurent Montel committed
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631

    connect(mBaseModel, &QAbstractProxyModel::rowsInserted, this, &AkonadiCollectionView::rowsInserted);

    KXMLGUIClient *xmlclient = KOCore::self()->xmlguiClient(view);
    if (xmlclient) {
        mCollectionView->setXmlGuiClient(xmlclient);

        mActionManager =
            new Akonadi::StandardCalendarActionManager(xmlclient->actionCollection(), mCollectionView);

        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
632
                        << Akonadi::StandardActionManager::SynchronizeCollectionTree
Laurent Montel's avatar
Laurent Montel committed
633
634
                        << Akonadi::StandardActionManager::CopyCollectionToMenu
                        << Akonadi::StandardActionManager::MoveCollectionToMenu;
Laurent Montel's avatar
Laurent Montel committed
635
636
637
638

        Q_FOREACH (Akonadi::StandardActionManager::Type standardAction, standardActions) {
            mActionManager->createAction(standardAction);
        }
639

Laurent Montel's avatar
Laurent Montel committed
640
641
642
643
644
645
        QList<Akonadi::StandardCalendarActionManager::Type> calendarActions;
        calendarActions << Akonadi::StandardCalendarActionManager::CreateEvent
                        << Akonadi::StandardCalendarActionManager::CreateTodo
                        << Akonadi::StandardCalendarActionManager::CreateSubTodo
                        << Akonadi::StandardCalendarActionManager::CreateJournal
                        << Akonadi::StandardCalendarActionManager::EditIncidence;
646

Laurent Montel's avatar
Laurent Montel committed
647
648
649
        Q_FOREACH (Akonadi::StandardCalendarActionManager::Type calendarAction, calendarActions) {
            mActionManager->createAction(calendarAction);
        }
650

Laurent Montel's avatar
Laurent Montel committed
651
652
653
654
655
656
        mActionManager->setCollectionSelectionModel(mCollectionView->selectionModel());

        mActionManager->interceptAction(Akonadi::StandardActionManager::CreateResource);
        mActionManager->interceptAction(Akonadi::StandardActionManager::DeleteResources);
        mActionManager->interceptAction(Akonadi::StandardActionManager::DeleteCollections);

Laurent Montel's avatar
Laurent Montel committed
657
658
659
660
661
662
        connect(mActionManager->action(Akonadi::StandardActionManager::CreateResource), &QAction::triggered,
                this, &AkonadiCollectionView::newCalendar);
        connect(mActionManager->action(Akonadi::StandardActionManager::DeleteResources), &QAction::triggered,
                this, &AkonadiCollectionView::deleteCalendar);
        connect(mActionManager->action(Akonadi::StandardActionManager::DeleteCollections), &QAction::triggered,
                this, &AkonadiCollectionView::deleteCalendar);
Laurent Montel's avatar
Laurent Montel committed
663
664
665
666
667

        mActionManager->setContextText(Akonadi::StandardActionManager::CollectionProperties,
                                       Akonadi::StandardActionManager::DialogTitle,
                                       ki18nc("@title:window", "Properties of Calendar Folder %1"));

668
669
670
        mActionManager->action(Akonadi::StandardActionManager::CreateCollection)->setProperty("ContentMimeTypes",
                QStringList() << Akonadi::Collection::mimeType() << KCalCore::Event::eventMimeType());

Laurent Montel's avatar
Laurent Montel committed
671
672
        mActionManager->interceptAction(Akonadi::StandardActionManager::CollectionProperties);
        connect(mActionManager->action(Akonadi::StandardActionManager::CollectionProperties), &QAction::triggered, mManagerShowCollectionProperties, &ManageShowCollectionProperties::showCollectionProperties);
Laurent Montel's avatar
Laurent Montel committed
673
674
675
676

        mDisableColor = new QAction(mCollectionView);
        mDisableColor->setText(i18n("&Disable Color"));
        mDisableColor->setEnabled(false);
Laurent Montel's avatar
Laurent Montel committed
677
        xmlclient->actionCollection()->addAction(QStringLiteral("disable_color"),
Laurent Montel's avatar
Laurent Montel committed
678
679
680
681
682
683
                mDisableColor);
        connect(mDisableColor, &QAction::triggered, this, &AkonadiCollectionView::disableColor);

        mAssignColor = new QAction(mCollectionView);
        mAssignColor->setText(i18n("&Assign Color..."));
        mAssignColor->setEnabled(false);
Laurent Montel's avatar
Laurent Montel committed
684
        xmlclient->actionCollection()->addAction(QStringLiteral("assign_color"), mAssignColor);
Laurent Montel's avatar
Laurent Montel committed
685
686
687
688
689
        connect(mAssignColor, &QAction::triggered, this, &AkonadiCollectionView::assignColor);

        mDefaultCalendar = new QAction(mCollectionView);
        mDefaultCalendar->setText(i18n("Use as &Default Calendar"));
        mDefaultCalendar->setEnabled(false);
Laurent Montel's avatar
Laurent Montel committed
690
        xmlclient->actionCollection()->addAction(QStringLiteral("set_standard_calendar"),
Laurent Montel's avatar
Laurent Montel committed
691
                mDefaultCalendar);
692
693

        //Disable a calendar or remove a referenced calendar
Laurent Montel's avatar
Laurent Montel committed
694
        QAction *disableAction = xmlclient->actionCollection()->addAction(QStringLiteral("collection_disable"), this, &AkonadiCollectionView::edit_disable);
695
        disableAction->setText(i18n("Remove from list"));
Laurent Montel's avatar
Laurent Montel committed
696
        disableAction->setIcon(QIcon::fromTheme(QStringLiteral("list-remove")));
697
698

        //Enable (subscribe) to a calendar.
Laurent Montel's avatar
Laurent Montel committed
699
        mEnableAction = xmlclient->actionCollection()->addAction(QStringLiteral("collection_enable"), this, &AkonadiCollectionView::edit_enable);
700
        mEnableAction->setText(i18n("Add to list permanently"));
Laurent Montel's avatar
Laurent Montel committed
701
        mEnableAction->setIcon(QIcon::fromTheme(QStringLiteral("bookmarks")));
702

703
704
705
706
        mServerSideSubscription = new QAction(QIcon::fromTheme(QStringLiteral("folder-bookmarks")), i18n("Serverside Subscription..."), this);
        xmlclient->actionCollection()->addAction(QStringLiteral("serverside_subscription"), mServerSideSubscription);
        connect(mServerSideSubscription, &QAction::triggered, this, &AkonadiCollectionView::slotServerSideSubscription);

Laurent Montel's avatar
Laurent Montel committed
707
    }
708
709
710
711
}

AkonadiCollectionView::~AkonadiCollectionView()
{
712
713
    //Necessary because it's apparently impossible to detect in the note expander when to save the state before view get's deleted
    mNewNodeExpander->saveState();
714
715
}

716
void AkonadiCollectionView::onSearchIsActive(bool active)
717
{
718
719
720
721
    if (!active) {
        mStackedWidget->setCurrentIndex(0);
    } else {
        mStackedWidget->setCurrentIndex(1);
Laurent Montel's avatar
Laurent Montel committed
722
    }
723
724
}

725
726
727
728
729
730
731
732
733
734
735
736
737
738
void AkonadiCollectionView::slotServerSideSubscription()
{
    const QModelIndex index = mCollectionView->selectionModel()->currentIndex(); //selectedRows()
    Q_ASSERT(index.isValid());
    const Akonadi::Collection collection = CalendarSupport::collectionFromIndex(index);
    if (!collection.isValid()) {
        return;
    }
    PimCommon::ManageServerSideSubscriptionJob *job = new PimCommon::ManageServerSideSubscriptionJob(this);
    job->setCurrentCollection(collection);
    job->setParentWidget(this);
    job->start();
}

Laurent Montel's avatar
Laurent Montel committed
739
740
741
742
743
744
745
746
Akonadi::Collection AkonadiCollectionView::currentCalendar() const
{
    const QModelIndex index = mCollectionView->selectionModel()->currentIndex(); //selectedRows()
    Q_ASSERT(index.isValid());
    Akonadi::Collection collection = CalendarSupport::collectionFromIndex(index);
    return collection;
}

747
748
void AkonadiCollectionView::setDefaultCalendar()
{
Laurent Montel's avatar
Laurent Montel committed
749
750
751
752
753
754
755
756
    QModelIndex index = mCollectionView->selectionModel()->currentIndex(); //selectedRows()
    Q_ASSERT(index.isValid());
    const Akonadi::Collection collection = CalendarSupport::collectionFromIndex(index);
    CalendarSupport::KCalPrefs::instance()->setDefaultCalendarId(collection.id());
    CalendarSupport::KCalPrefs::instance()->usrSave();
    updateMenu();
    updateView();

Laurent Montel's avatar
Laurent Montel committed
757
    Q_EMIT defaultResourceChanged(collection);
758
759
760
761
}

void AkonadiCollectionView::assignColor()
{
Laurent Montel's avatar
Laurent Montel committed
762
763
764
765
766
767
768
769
770
771
772
    QModelIndex index = mCollectionView->selectionModel()->currentIndex(); //selectedRows()
    Q_ASSERT(index.isValid());
    const Akonadi::Collection collection = CalendarSupport::collectionFromIndex(index);
    Q_ASSERT(collection.isValid());

    const QString identifier = QString::number(collection.id());
    const QColor defaultColor = KOPrefs::instance()->resourceColor(identifier);
    QColor myColor;
    myColor = QColorDialog::getColor(defaultColor);
    if (myColor.isValid() && myColor != defaultColor) {
        KOPrefs::instance()->setResourceColor(identifier, myColor);
Laurent Montel's avatar
Laurent Montel committed
773
        Q_EMIT colorsChanged();
Laurent Montel's avatar
Laurent Montel committed
774
775
776
        updateMenu();
        updateView();
    }
777
778
779
780
}

void AkonadiCollectionView::disableColor()
{
Laurent Montel's avatar
Laurent Montel committed
781
782
783
784
785
786
787
788
    QModelIndex index = mCollectionView->selectionModel()->currentIndex(); //selectedRows()
    Q_ASSERT(index.isValid());
    const Akonadi::Collection collection = CalendarSupport::collectionFromIndex(index);
    Q_ASSERT(collection.isValid());
    const QString identifier = QString::number(collection.id());
    KOPrefs::instance()->setResourceColor(identifier, QColor());
    updateMenu();
    updateView();
Laurent Montel's avatar
Laurent Montel committed
789
    Q_EMIT colorsChanged();
790
791
}

Laurent Montel's avatar
Laurent Montel committed
792
void AkonadiCollectionView::setCollectionSelectionProxyModel(KCheckableProxyModel *m)
793
{
Laurent Montel's avatar
Laurent Montel committed
794
795
796
    if (mSelectionProxyModel == m) {
        return;
    }
Allen Winter's avatar
Allen Winter committed
797

Laurent Montel's avatar
Laurent Montel committed
798
799
800
801
    mSelectionProxyModel = m;
    if (!mSelectionProxyModel) {
        return;
    }
Allen Winter's avatar
Allen Winter committed
802

803
    new NewCalendarChecker(m);
Laurent Montel's avatar
Laurent Montel committed
804
    mBaseModel->setSourceModel(mSelectionProxyModel);
805
806
}

807
KCheckableProxyModel *AkonadiCollectionView::collectionSelectionProxyModel() const
808
{
Laurent Montel's avatar
Laurent Montel committed
809
    return mSelectionProxyModel;
810
811
}

Allen Winter's avatar
Allen Winter committed
812
Akonadi::EntityTreeView *AkonadiCollectionView::view() const
813
{
Laurent Montel's avatar
Laurent Montel committed
814
    return mCollectionView;
815
816
817
818
}

void AkonadiCollectionView::updateView()
{
Laurent Montel's avatar
Laurent Montel committed
819
    Q_EMIT resourcesChanged(mSelectionProxyModel ?
Laurent Montel's avatar
Laurent Montel committed
820
821
                            mSelectionProxyModel->selectionModel()->hasSelection() :
                            false);
822
823
824
825
}

void AkonadiCollectionView::updateMenu()
{
Laurent Montel's avatar
Laurent Montel committed
826
827
828
829
830
831
832
833
834
    if (!mHasContextMenu) {
        return;
    }
    bool enableAction = mCollectionView->selectionModel()->hasSelection();
    enableAction = enableAction &&
                   (KOPrefs::instance()->agendaViewColors() != KOPrefs::CategoryOnly);
    mAssignColor->setEnabled(enableAction);
    QModelIndex index = mCollectionView->selectionModel()->currentIndex(); //selectedRows()

835
    bool disableStuff = true;
Laurent Montel's avatar
Laurent Montel committed
836
837

    if (index.isValid()) {
838
        //Returns an invalid collection on person nodes
Laurent Montel's avatar
Laurent Montel committed
839
840
        const Akonadi::Collection collection = CalendarSupport::collectionFromIndex(index);

841
        if (collection.isValid() && !collection.contentMimeTypes().isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
842
843
844
            const QString identifier = QString::number(collection.id());
            const QColor defaultColor = KOPrefs::instance()->resourceColor(identifier);
            enableAction = enableAction && defaultColor.isValid();
845
            if (collection.remoteId() == QLatin1String("akonadi_birthdays_resource")) {
846
                enableAction = false;
Laurent Montel's avatar
Laurent Montel committed
847
                mAssignColor->setEnabled(enableAction);
848
            }
849

Laurent Montel's avatar
Laurent Montel committed
850
851
852
            mDisableColor->setEnabled(enableAction);
            mDefaultCalendar->setEnabled(!KOHelper::isStandardCalendar(collection.id()) &&
                                         collection.rights() & Akonadi::Collection::CanCreateItem);
853
854
855
856
            disableStuff = false;
        }
        if (collection.isValid() && collection.shouldList(Akonadi::Collection::ListDisplay)) {
            mEnableAction->setEnabled(false);
Laurent Montel's avatar
Laurent Montel committed
857
        } else {
858
            mEnableAction->setEnabled(true);
Laurent Montel's avatar
Laurent Montel committed
859
        }
860
861
        bool isOnline;
        mServerSideSubscription->setEnabled(PimCommon::Util::isImapFolder(collection, isOnline));
Laurent Montel's avatar
Laurent Montel committed
862
863
    } else {
        mServerSideSubscription->setEnabled(false);
Laurent Montel's avatar
Laurent Montel committed
864
865
866
867
868
    }
    if (disableStuff) {
        mDisableColor->setEnabled(false);
        mDefaultCalendar->setEnabled(false);
        mAssignColor->setEnabled(false);
869
870
871
872
873
    }
}

void AkonadiCollectionView::newCalendar()
{
Laurent Montel's avatar
Laurent Montel committed
874
875
    Akonadi::AgentTypeDialog dlg(this);
    dlg.setWindowTitle(i18n("Add Calendar"));
Laurent Montel's avatar
Laurent Montel committed
876
    dlg.agentFilterProxyModel()->addMimeTypeFilter(QStringLiteral("text/calendar"));
877
    dlg.agentFilterProxyModel()->addCapabilityFilter(QStringLiteral("Resource"));   // show only resources, no agents
Laurent Montel's avatar
Laurent Montel committed
878
879
880
881
882
883
884
885
886
    if (dlg.exec()) {
        mNotSendAddRemoveSignal = true;
        const Akonadi::AgentType agentType = dlg.agentType();
        if (agentType.isValid()) {
            Akonadi::AgentInstanceCreateJob *job = new Akonadi::AgentInstanceCreateJob(agentType, this);
            job->configure(this);
            connect(job, &Akonadi::AgentInstanceCreateJob::result, this, &AkonadiCollectionView::newCalendarDone);
            job->start();
        }
887
888
889
    }
}

Laurent Montel's avatar
Laurent Montel committed
890
void AkonadiCollectionView::newCalendarDone(KJob *job)
891
{
Laurent Montel's avatar
Laurent Montel committed
892
893
894
895
896
    Akonadi::AgentInstanceCreateJob *createjob = static_cast<Akonadi::AgentInstanceCreateJob *>(job);
    if (createjob->error()) {
        //TODO(AKONADI_PORT)
        // this should show an error dialog and should be merged
        // with the identical code in ActionManager
Laurent Montel's avatar
Laurent Montel committed
897
        qCWarning(KORGANIZER_LOG) << "Create calendar failed:" << createjob->errorString();
Laurent Montel's avatar
Laurent Montel committed
898
899
900
        mNotSendAddRemoveSignal = false;
        return;
    }
901
    mNotSendAddRemoveSignal = false;
Laurent Montel's avatar
Laurent Montel committed
902
    //TODO
903
904
905
906
}

void AkonadiCollectionView::deleteCalendar()
{
Laurent Montel's avatar
Laurent Montel committed
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
    QModelIndex index = mCollectionView->selectionModel()->currentIndex(); //selectedRows()
    Q_ASSERT(index.isValid());
    const Akonadi::Collection collection = CalendarSupport::collectionFromIndex(index);
    Q_ASSERT(collection.isValid());

    const QString displayname = index.model()->data(index, Qt::DisplayRole).toString();
    Q_ASSERT(!displayname.isEmpty());

    if (KMessageBox::warningContinueCancel(
                this,
                i18n("Do you really want to delete calendar %1?", displayname),
                i18n("Delete Calendar"),
                KStandardGuiItem::del(),
                KStandardGuiItem::cancel(),
                QString(),
                KMessageBox::Dangerous)  == KMessageBox::Continue) {

        bool isTopLevel = collection.parentCollection() == Akonadi::Collection::root();

        mNotSendAddRemoveSignal = true;
        mWasDefaultCalendar = KOHelper::isStandardCalendar(collection.id());

        if (!isTopLevel) {
            // deletes contents
            Akonadi::CollectionDeleteJob *job = new Akonadi::CollectionDeleteJob(collection, this);
            connect(job, &Akonadi::AgentInstanceCreateJob::result, this, &AkonadiCollectionView::deleteCalendarDone);
        } else {
            // deletes the agent, not the contents
            const Akonadi::AgentInstance instance =
                Akonadi::AgentManager::self()->instance(collection.resource());
            if (instance.isValid()) {
                Akonadi::AgentManager::self()->removeInstance(instance);
            }
        }
941
942
943
    }
}

Laurent Montel's avatar
Laurent Montel committed
944
void AkonadiCollectionView::deleteCalendarDone(KJob *job)
945
{
Laurent Montel's avatar
Laurent Montel committed
946
947
    Akonadi::CollectionDeleteJob *deletejob = static_cast<Akonadi::CollectionDeleteJob *>(job);
    if (deletejob->error()) {
Laurent Montel's avatar
Laurent Montel committed
948
        qCWarning(KORGANIZER_LOG) << "Delete calendar failed:" << deletejob->errorString();
Laurent Montel's avatar
Laurent Montel committed
949
950
951
952
953
954
        mNotSendAddRemoveSignal = false;
        return;
    }
    if (mWasDefaultCalendar) {
        CalendarSupport::KCalPrefs::instance()->setDefaultCalendarId(Akonadi::Collection().id());
    }
955
    mNotSendAddRemoveSignal = false;
Laurent Montel's avatar
Laurent Montel committed
956
    //TODO
957
958
}

Laurent Montel's avatar
Laurent Montel committed
959
void AkonadiCollectionView::rowsInserted(const QModelIndex &, int, int)
960
{
Laurent Montel's avatar
Laurent Montel committed
961
    if (!mNotSendAddRemoveSignal) {
Laurent Montel's avatar
Laurent Montel committed
962
        Q_EMIT resourcesAddedRemoved();
Laurent Montel's avatar
Laurent Montel committed
963
    }
964
965
}

966
Akonadi::Collection AkonadiCollectionView::selectedCollection() const
967
{
Laurent Montel's avatar
Laurent Montel committed
968
969
970
971
972
973
974
975
976
    Akonadi::Collection collection;
    QItemSelectionModel *selectionModel = mCollectionView->selectionModel();
    if (!selectionModel) {
        return collection;
    }
    QModelIndexList indexes = selectionModel->selectedIndexes();
    if (!indexes.isEmpty()) {
        collection = indexes.first().data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
    }
977
    return collection;
978
979
980
981
}

Akonadi::Collection::List AkonadiCollectionView::checkedCollections() const
{
Laurent Montel's avatar
Laurent Montel committed
982
983
984
    Akonadi::Collection::List collections;
    if (!mSelectionProxyModel) {
        return collections;
985
    }
Laurent Montel's avatar
Laurent Montel committed
986
987
988
989
990
991
992
993
994
995
996
997
998
999
    QItemSelectionModel *selectionModel = mSelectionProxyModel->selectionModel();
    if (!selectionModel) {
        return collections;
    }
    QModelIndexList indexes = selectionModel->selectedIndexes();
    foreach (const QModelIndex &index, indexes) {
        if (index.isValid()) {
            Akonadi::Collection collection = index.data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
            if (collection.isValid()) {
                collections << collection;
            }
        }
    }
    return collections;
1000
1001
}

1002
1003
bool AkonadiCollectionView::isChecked(const Akonadi::Collection &collection) const
{
Laurent Montel's avatar
Laurent Montel committed
1004
    if (!mSelectionProxyModel) {
1005
        return false;
Laurent Montel's avatar
Laurent Montel committed
1006
    }
1007
    QItemSelectionModel *selectionModel = mSelectionProxyModel->selectionModel();
Laurent Montel's avatar
Laurent Montel committed
1008
    if (!selectionModel) {
1009
        return false;
Laurent Montel's avatar
Laurent Montel committed
1010
    }
1011
    QModelIndexList indexes = selectionModel->selectedIndexes();
Laurent Montel's avatar
Laurent Montel committed
1012
    foreach (const QModelIndex &index, indexes) {
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
        if (index.isValid()) {
            Akonadi::Collection c = index.data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
            if (c.id() == collection.id()) {
                return true;
            }
        }
    }
    return false;
}

1023
1024
Akonadi::EntityTreeModel *AkonadiCollectionView::entityTreeModel() const
{
Laurent Montel's avatar
Laurent Montel committed
1025
1026
1027
1028
1029
1030
1031
    QAbstractProxyModel *proxy = qobject_cast<QAbstractProxyModel *>(mCollectionView->model());
    while (proxy) {
        Akonadi::EntityTreeModel *etm = qobject_cast<Akonadi::EntityTreeModel *>(proxy->sourceModel());
        if (etm) {
            return etm;
        }
        proxy = qobject_cast<QAbstractProxyModel *>(proxy->sourceModel());
Kevin Krammer's avatar
Kevin Krammer committed
1032
    }
1033

Laurent Montel's avatar
Laurent Montel committed
1034
    qCWarning(KORGANIZER_LOG) << "Couldn't find EntityTreeModel";
Laurent Montel's avatar
Laurent Montel committed
1035
    return nullptr;
1036
1037
}

1038
void AkonadiCollectionView::edit_disable()
1039
{
1040
#if 0
1041
1042
    Akonadi::Collection col = mCollectionView->currentIndex().data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
    if (col.isValid()) {
1043
1044
        mController->setCollectionState(col, Controller::Disabled);
    }
1045
#endif
1046
1047
    const QVariant var = mCollectionView->currentIndex().data(PersonRole);
    if (var.isValid()) {
1048
        mController->removePerson(var.value<KPIM::Person>());
1049
    }
1050
1051
1052
}

void AkonadiCollectionView::edit_enable()
1053
{
1054
    Akonadi::Collection col = mCollectionView->currentIndex().data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
1055
    qCDebug(KORGANIZER_LOG) << col.name();
1056
    if (col.isValid()) {
1057
1058
1059
1060
        mController->setCollectionState(col, Controller::Enabled);
    }
    const QVariant var = mCollectionView->currentIndex().data(PersonRole);
    if (var.isValid()) {
1061
        mController->addPerson(var.value<KPIM::Person>());
1062
1063
1064
    }
}

1065
1066
1067
1068
void AkonadiCollectionView::onAction(const QModelIndex &index, int a)
{
    const StyledCalendarDelegate::Action action = static_cast<StyledCalendarDelegate::Action>(a);
    switch (action) {
1069
1070
1071
    case StyledCalendarDelegate::AddToList: {
        const QVariant var = index.data(PersonRole);
        if (var.isValid()) {
1072
            mController->addPerson(var.value<KPIM::Person>());
1073
1074
1075
1076
        } else {
            const Akonadi::Collection col = CalendarSupport::collectionFromIndex(index);
            if (col.isValid()) {
                mController->setCollectionState(col, Controller::Referenced);
Laurent Montel's avatar
Laurent Montel committed
1077
1078
            }
        }
1079
1080
1081
    }
    break;
    case StyledCalendarDelegate::RemoveFromList: {
1082
#if 0
1083
1084
        const QVariant var = index.data(PersonRole);
        if (var.isValid()) {
1085
            mController->removePerson(var.value<KPIM::Person>());
1086
1087
1088
1089
        } else {
            const Akonadi::Collection col = CalendarSupport::collectionFromIndex(index);
            if (col.isValid()) {
                mController->setCollectionState(col, Controller::Disabled);
Laurent Montel's avatar
Laurent Montel committed
1090
1091
            }
        }
1092
#endif
1093
    }
1094
1095
1096
1097
    break;
    case StyledCalendarDelegate::Enable: {
        const QVariant var = index.data(PersonRole);
        if (var.isValid()) {
1098
            mController->setCollectionState(Akonadi::Collection(var.value<KPIM::Person>().rootCollection), Controller::Enabled, true);
1099
1100
1101
1102
        } else {
            const Akonadi::Collection col = CalendarSupport::collectionFromIndex(index);
            if (col.isValid()) {
                mController->setCollectionState(col, Controller::Enabled);
1103
            }
Laurent Montel's avatar
Laurent Montel committed
1104
        }
1105
    }