eventmodel.cpp 6.82 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/*
 * Copyright (C) 2016  Daniel Vrátil <dvratil@kde.org>
 *
 * 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.
 *
 */

#include "eventmodel.h"
#include "pimeventsplugin_debug.h"

#include <Akonadi/Calendar/IncidenceChanger>

#include <AkonadiCore/Monitor>
#include <AkonadiCore/ItemFetchScope>
#include <AkonadiCore/CollectionFetchScope>
#include <AkonadiCore/EntityDisplayAttribute>
#include <AkonadiCore/CollectionColorAttribute>
#include <AkonadiCore/AttributeFactory>
#include <AkonadiCore/ItemFetchJob>

Laurent Montel's avatar
Laurent Montel committed
33
EventModel::EventModel(QObject *parent)
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
    : Akonadi::CalendarBase(parent)
{
    Akonadi::AttributeFactory::registerAttribute<Akonadi::CollectionColorAttribute>();
}

EventModel::~EventModel()
{
}

void EventModel::createMonitor()
{
    if (mMonitor) {
        return;
    }

    mMonitor = new Akonadi::Monitor(this);
50
    mMonitor->setObjectName(QStringLiteral("PlasmaEventModelMonitor"));
51
52
53
54
55
56
    mMonitor->itemFetchScope().fetchFullPayload(true);
    mMonitor->collectionFetchScope().fetchAttribute<Akonadi::EntityDisplayAttribute>();
    mMonitor->collectionFetchScope().fetchAttribute<Akonadi::CollectionColorAttribute>();
    mMonitor->fetchCollection(true);

    connect(mMonitor, &Akonadi::Monitor::itemAdded,
Laurent Montel's avatar
Laurent Montel committed
57
58
59
60
            this, [this](const Akonadi::Item &item) {
        // This is super-ugly, but the only way how to insert into CalendarBase
        // without having direct access to CalendarBasePrivate.
        // changeId is luckily ignored by CalendarBase.
Laurent Montel's avatar
Laurent Montel committed
61
        Q_EMIT incidenceChanger()->createFinished(0, item, Akonadi::IncidenceChanger::ResultCodeSuccess, QString());
Laurent Montel's avatar
Laurent Montel committed
62
    });
63
    connect(mMonitor, &Akonadi::Monitor::itemChanged,
Laurent Montel's avatar
Laurent Montel committed
64
            this, [this](const Akonadi::Item &item) {
65
        if (!item.hasPayload<KCalendarCore::Incidence::Ptr>()) {
66
67
            qCDebug(PIMEVENTSPLUGIN_LOG) << "Item" << item.id() << "has no payload!";
            return;
Laurent Montel's avatar
Laurent Montel committed
68
        }
69

70
        auto incidence = item.payload<KCalendarCore::Incidence::Ptr>();
Laurent Montel's avatar
Laurent Montel committed
71
72
73
        if (!incidence) {
            return;         // HUH?!
        }
74
        const KCalendarCore::Incidence::Ptr oldIncidence = this->incidence(incidence->instanceIdentifier());
Laurent Montel's avatar
Laurent Montel committed
75
76
77
78
79
80
81
82
83
        if (!oldIncidence) {
            // Change for event we don't know about -> discard
            return;
        }

        // Unfortunately the plasma applet does not handle event moves
        // so we have to simulate via remove+add
        if (oldIncidence->allDay() != incidence->allDay()
            || oldIncidence->dtStart() != incidence->dtStart()
84
            || oldIncidence->dateTime(KCalendarCore::IncidenceBase::RoleEnd) != incidence->dateTime(KCalendarCore::IncidenceBase::RoleEnd)) {
Laurent Montel's avatar
Laurent Montel committed
85
86
            Q_EMIT incidenceChanger()->deleteFinished(0, { item.id() }, Akonadi::IncidenceChanger::ResultCodeSuccess, QString());
            Q_EMIT incidenceChanger()->createFinished(0, item, Akonadi::IncidenceChanger::ResultCodeSuccess, QString());
Laurent Montel's avatar
Laurent Montel committed
87
        } else {
Laurent Montel's avatar
Laurent Montel committed
88
            Q_EMIT incidenceChanger()->modifyFinished(0, item, Akonadi::IncidenceChanger::ResultCodeSuccess, QString());
Laurent Montel's avatar
Laurent Montel committed
89
90
        }
    });
91
    connect(mMonitor, &Akonadi::Monitor::itemRemoved,
Laurent Montel's avatar
Laurent Montel committed
92
            this, [this](const Akonadi::Item &item) {
Laurent Montel's avatar
Laurent Montel committed
93
        Q_EMIT incidenceChanger()->deleteFinished(0, { item.id() }, Akonadi::IncidenceChanger::ResultCodeSuccess, QString());
Laurent Montel's avatar
Laurent Montel committed
94
    });
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
    connect(mMonitor, &Akonadi::Monitor::collectionRemoved,
            this, &EventModel::removeCalendar);
}

void EventModel::addCalendar(const Akonadi::Collection &col)
{
    if (!mCols.contains(col)) {
        mCols.push_back(col);

        createMonitor();
        mMonitor->setCollectionMonitored(col, true);

        populateCollection(col);
    }
}

void EventModel::removeCalendar(const Akonadi::Collection &col)
{
    auto it = std::find(mCols.begin(), mCols.end(), col);
    if (it != mCols.end()) {
        mCols.erase(it);
        if (mMonitor) {
            mMonitor->setCollectionMonitored(col, false);
        }

        removeCollection(col);
    }
}

QVector<Akonadi::Collection> EventModel::collections() const
{
    return mCols;
}

Akonadi::Collection EventModel::collection(qint64 id) const
{
    auto it = std::find(mCols.cbegin(), mCols.cend(), Akonadi::Collection(id));
    return it == mCols.cend() ? Akonadi::Collection(id) : *it;
}

void EventModel::populateCollection(const Akonadi::Collection &col)
{
    qCDebug(PIMEVENTSPLUGIN_LOG) << "Populating events from collection" << col.id();
    auto job = new Akonadi::ItemFetchJob(col, this);
    job->fetchScope().fetchFullPayload(true);
    job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent);
    job->setDeliveryOption(Akonadi::ItemFetchJob::EmitItemsInBatches);
    mFetchJobs.insert(col.id(), job);
    connect(job, &Akonadi::ItemFetchJob::itemsReceived,
            this, &EventModel::onItemsReceived);
    connect(job, &Akonadi::ItemFetchJob::result,
Laurent Montel's avatar
Laurent Montel committed
146
147
148
149
150
            job, [this, col](KJob *job) {
        mFetchJobs.remove(col.id());
        auto fetch = qobject_cast<Akonadi::ItemFetchJob *>(job);
        qCDebug(PIMEVENTSPLUGIN_LOG) << "Received" << fetch->count() << "events for collection" << col.id();
    });
151
152
153
154
155
156
}

void EventModel::onItemsReceived(const Akonadi::Item::List &items)
{
    qCDebug(PIMEVENTSPLUGIN_LOG) << "Batch: received" << items.count() << "items";
    for (const auto &item : items) {
157
        if (item.hasPayload<KCalendarCore::Incidence::Ptr>()) {
Laurent Montel's avatar
Laurent Montel committed
158
            Q_EMIT incidenceChanger()->createFinished(0, item, Akonadi::IncidenceChanger::ResultCodeSuccess, QString());
159
160
161
        } else {
            qCDebug(PIMEVENTSPLUGIN_LOG) << "Item" << item.id() << "has no payload";
        }
162
163
164
165
166
167
    }
}

void EventModel::removeCollection(const Akonadi::Collection &col)
{
    if (KJob *job = mFetchJobs.take(col.id())) {
Laurent Montel's avatar
Laurent Montel committed
168
        disconnect(job, nullptr, this, nullptr);
169
170
171
172
173
174
175
176
177
178
179
180
181
182
        job->kill();
    }

    const auto items = this->items(col.id());
    qCDebug(PIMEVENTSPLUGIN_LOG) << "Removing" << items.count() << "events for collection" << col.id();
    if (items.isEmpty()) {
        return;
    }

    QVector<Akonadi::Item::Id> ids;
    ids.reserve(items.size());
    std::transform(items.cbegin(), items.cend(), std::back_inserter(ids),
                   std::mem_fn(&Akonadi::Item::id));

Laurent Montel's avatar
Laurent Montel committed
183
    Q_EMIT incidenceChanger()->deleteFinished(0, ids, Akonadi::IncidenceChanger::ResultCodeSuccess, QString());
184
}