eventdatavisitor.cpp 7.07 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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
/*
 * 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 "eventdatavisitor.h"
#include "pimeventsplugin_debug.h"

#include <Akonadi/Calendar/ETMCalendar>

BaseEventDataVisitor::BaseEventDataVisitor(Akonadi::ETMCalendar *calendar,
                                           const QDate &start, const QDate &end)
    : mCalendar(calendar)
    , mStart(start)
    , mEnd(end)
{
}

BaseEventDataVisitor::~BaseEventDataVisitor()
{
}

bool BaseEventDataVisitor::act(const KCalCore::Incidence::Ptr &incidence)
{
    return incidence->accept(*this, incidence);
}

bool BaseEventDataVisitor::act(const KCalCore::Event::List &events)
{
    bool ok = false;
    Q_FOREACH (const KCalCore::Event::Ptr &event, events) {
        ok = event.staticCast<KCalCore::IncidenceBase>()->accept(*this, event) || ok;
    }
    return ok;
}
bool BaseEventDataVisitor::act(const KCalCore::Todo::List &todos)
{
    bool ok = false;
    Q_FOREACH (const KCalCore::Todo::Ptr &todo, todos) {
        ok = todo.staticCast<KCalCore::IncidenceBase>()->accept(*this, todo) || ok;
    }
    return ok;
}

bool BaseEventDataVisitor::isInRange(const QDate &start, const QDate &end) const
{
    if (!mStart.isValid() || !mEnd.isValid()) {
        return true;
    }

    if (!end.isValid() && start >= mStart && start <= mEnd) {
        return true;
    } else if (start < mStart) {
        return end >= mStart;
    } else if (end > mEnd) {
        return start <= mEnd;
    } else {
        return true;
    }
}

QString BaseEventDataVisitor::generateUid(const KCalCore::Incidence::Ptr &incidence,
                                          const KDateTime &recurrenceId) const
{
    // Get a corresponding Akonadi Item: Akonadi ID is the only reliably unique
    // and persistent identifier when dealing with incidences from multiple
    // calendars
82 83
    const qint64 itemId = itemIdForIncidence(incidence);
    if (itemId <= 0) {
84 85 86 87 88
        // Can this happen? What do we do now?!
        return QString();
    }

    if (recurrenceId.isValid()) {
89
        return QStringLiteral("Akonadi-%1-%2").arg(itemId)
90 91
                                              .arg(recurrenceId.toString(QStringLiteral("%Y%m%dT%H%M%S%Z")));
    } else {
92
        return QStringLiteral("Akonadi-%1").arg(itemId);
93 94 95
    }
}

96 97 98 99 100
qint64 BaseEventDataVisitor::itemIdForIncidence(const KCalCore::Incidence::Ptr &incidence) const
{
    return mCalendar->item(incidence).id();
}

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
QVector<CalendarEvents::EventData> BaseEventDataVisitor::explodeIncidenceOccurences(const CalendarEvents::EventData &ed,
                                                                                    const KCalCore::Incidence::Ptr &incidence,
                                                                                    bool &ok)
{
    Q_ASSERT(incidence->recurs());

    const qint64 duration = ed.startDateTime().secsTo(ed.endDateTime());

    KDateTime rec(mStart.addDays(-1), QTime(0, 0, 0));
    rec = incidence->recurrence()->getNextDateTime(rec);
    QVector<CalendarEvents::EventData> results;
    while (rec.isValid() && rec.date() <= mEnd) {
        CalendarEvents::EventData copy = ed;
        const QDateTime dt = rec.dateTime();
        copy.setStartDateTime(dt);
        // TODO: Is there a better way to find when an instance ends without
        // going through the expensive lookup in Incidence::instance(uid, recurrenceId)?
        copy.setEndDateTime(dt.addSecs(duration));
        copy.setUid(generateUid(incidence, rec));
        results.push_back(copy);

        rec = incidence->recurrence()->getNextDateTime(rec);
    }

    ok = true;
    return results;
}


130 131 132 133 134 135 136 137 138 139 140 141 142


EventDataVisitor::EventDataVisitor(Akonadi::ETMCalendar *calendar,
                                   const QDate &start, const QDate &end)
    : BaseEventDataVisitor(calendar, start , end)
{
}

EventDataVisitor::~EventDataVisitor()
{
}


143
const QMultiHash<QDate, CalendarEvents::EventData> &EventDataVisitor::results() const
144 145 146 147
{
    return mResults;
}

148 149
bool EventDataVisitor::visit(const KCalCore::Incidence::Ptr &incidence,
                             CalendarEvents::EventData::EventType type)
150
{
151 152 153
    CalendarEvents::EventData data = incidenceData(incidence);
    data.setEventType(type);
    if (incidence->recurs()) {
154
        bool ok = false;
155
        const auto list = explodeIncidenceOccurences(data, incidence, ok);
156 157 158 159 160 161
        if (ok) {
            for (const auto &data : list) {
                mResults.insert(data.startDateTime().date(), data);
            }
        }
        return ok;
162
    } else if (isInRange(data.startDateTime().date(), data.endDateTime().date())) {
163 164 165 166 167 168 169
        mResults.insert(data.startDateTime().date(), data);
        return true;
    }

    return false;
}

170
bool EventDataVisitor::visit(const KCalCore::Event::Ptr &event)
171
{
172 173
    return visit(event, CalendarEvents::EventData::Event);
}
174

175 176 177
bool EventDataVisitor::visit(const KCalCore::Todo::Ptr &todo)
{
    return visit(todo, CalendarEvents::EventData::Todo);
178 179 180 181 182 183 184 185 186 187
}

CalendarEvents::EventData EventDataVisitor::incidenceData(const KCalCore::Incidence::Ptr &incidence) const
{
    CalendarEvents::EventData data;
    data.setTitle(incidence->summary());
    data.setDescription(incidence->description());
    data.setIsAllDay(incidence->allDay());
    data.setIsMinor(false);
    data.setUid(generateUid(incidence));
188 189
    data.setStartDateTime(incidence->dtStart().dateTime());
    data.setEndDateTime(incidence->dateTime(KCalCore::Incidence::RoleEnd).dateTime());
190 191 192 193 194 195 196 197 198
    // TODO: Set calendar color
    return data;
}

EventDataIdVisitor::EventDataIdVisitor(Akonadi::ETMCalendar *calendar, const QDate &start, const QDate &end)
    : BaseEventDataVisitor(calendar, start, end)
{
}

199
const QStringList &EventDataIdVisitor::results() const
200 201 202 203 204 205
{
    return mResults;
}

bool EventDataIdVisitor::visit(const KCalCore::Event::Ptr &event)
{
206 207 208 209 210 211 212 213 214 215 216
    return visit(event.staticCast<KCalCore::Incidence>());
}

bool EventDataIdVisitor::visit(const KCalCore::Todo::Ptr &todo)
{
    return visit(todo.staticCast<KCalCore::Incidence>());
}

bool EventDataIdVisitor::visit(const KCalCore::Incidence::Ptr& incidence)
{
    if (incidence->recurs()) {
217 218
        CalendarEvents::EventData ed;
        bool ok = false;
219
        const auto list = explodeIncidenceOccurences(ed, incidence, ok);
220 221 222 223 224 225 226
        if (ok) {
            for (const auto &data : list) {
                mResults.push_back(data.uid());
            }
        }
        return ok;
    } else {
227
        mResults.push_back(generateUid(incidence, incidence->recurrenceId()));
228
    }
229 230
    return true;
}