File indexing completed on 2024-11-24 04:41:37

0001 /*
0002   SPDX-FileCopyrightText: 2007 Till Adam <adam@kde.org>
0003   SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
0004   SPDX-FileCopyrightText: 2010 Andras Mantia <andras@kdab.com>
0005 
0006   SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0
0007 */
0008 
0009 #include "timelineview_p.h"
0010 #include "timelineitem.h"
0011 
0012 #include <KGanttGraphicsView>
0013 
0014 #include <Akonadi/CalendarUtils>
0015 #include <Akonadi/IncidenceChanger>
0016 #include <CalendarSupport/CollectionSelection>
0017 #include <KCalendarCore/OccurrenceIterator>
0018 
0019 #include "calendarview_debug.h"
0020 
0021 #include <QStandardItemModel>
0022 
0023 using namespace KCalendarCore;
0024 using namespace EventViews;
0025 
0026 TimelineViewPrivate::TimelineViewPrivate(TimelineView *parent)
0027     : q(parent)
0028 {
0029 }
0030 
0031 TimelineViewPrivate::~TimelineViewPrivate() = default;
0032 
0033 void TimelineViewPrivate::itemSelected(const QModelIndex &index)
0034 {
0035     auto tlitem = dynamic_cast<TimelineSubItem *>(static_cast<QStandardItemModel *>(mGantt->model())->item(index.row(), index.column()));
0036     if (tlitem) {
0037         Q_EMIT q->incidenceSelected(tlitem->incidence(), tlitem->originalStart().date());
0038     }
0039 }
0040 
0041 void TimelineViewPrivate::itemDoubleClicked(const QModelIndex &index)
0042 {
0043     auto tlitem = dynamic_cast<TimelineSubItem *>(static_cast<QStandardItemModel *>(mGantt->model())->item(index.row(), index.column()));
0044     if (tlitem) {
0045         Q_EMIT q->editIncidenceSignal(tlitem->incidence());
0046     }
0047 }
0048 
0049 void TimelineViewPrivate::contextMenuRequested(QPoint point)
0050 {
0051     QPersistentModelIndex index = mGantt->indexAt(point);
0052     // mHintDate = QDateTime( mGantt->getDateTimeForCoordX( QCursor::pos().x(), true ) );
0053     auto tlitem = dynamic_cast<TimelineSubItem *>(static_cast<QStandardItemModel *>(mGantt->model())->item(index.row(), index.column()));
0054     if (!tlitem) {
0055         Q_EMIT q->showNewEventPopupSignal();
0056         mSelectedItemList = Akonadi::Item::List();
0057     } else {
0058         if (const auto calendar = tlitem->parent()->calendar(); calendar) {
0059             Q_EMIT q->showIncidencePopupSignal(calendar, tlitem->incidence(), Akonadi::CalendarUtils::incidence(tlitem->incidence())->dtStart().date());
0060         }
0061 
0062         mSelectedItemList << tlitem->incidence();
0063     }
0064 }
0065 
0066 // slot
0067 void TimelineViewPrivate::newEventWithHint(const QDateTime &dt)
0068 {
0069     mHintDate = dt;
0070     Q_EMIT q->newEventSignal(dt);
0071 }
0072 
0073 TimelineItem *TimelineViewPrivate::calendarItemForIncidence(const Akonadi::Item &incidence) const
0074 {
0075     auto item = mCalendarItemMap.constFind(incidence.parentCollection().id());
0076     if (item == mCalendarItemMap.cend()) {
0077         return mCalendarItemMap.value(-1);
0078     }
0079 
0080     return *item;
0081 }
0082 
0083 void TimelineViewPrivate::insertIncidence(const Akonadi::CollectionCalendar::Ptr &calendar, const Akonadi::Item &aitem, QDate day)
0084 {
0085     const Incidence::Ptr incidence = Akonadi::CalendarUtils::incidence(aitem);
0086     // qCDebug(CALENDARVIEW_LOG) << "Item " << aitem.id() << " parentcollection: " << aitem.parentCollection().id();
0087     TimelineItem *item = calendarItemForIncidence(aitem);
0088     if (!item) {
0089         qCWarning(CALENDARVIEW_LOG) << "Help! Something is really wrong here!";
0090         return;
0091     }
0092 
0093     if (incidence->recurs()) {
0094         KCalendarCore::OccurrenceIterator occurIter(*calendar, incidence, QDateTime(day, QTime(0, 0, 0)), QDateTime(day, QTime(23, 59, 59)));
0095         while (occurIter.hasNext()) {
0096             occurIter.next();
0097             const Akonadi::Item akonadiItem = calendar->item(occurIter.incidence());
0098             const QDateTime startOfOccurrence = occurIter.occurrenceStartDate();
0099             const QDateTime endOfOccurrence = occurIter.incidence()->endDateForStart(startOfOccurrence);
0100             item->insertIncidence(akonadiItem, startOfOccurrence.toLocalTime(), endOfOccurrence.toLocalTime());
0101         }
0102     } else {
0103         if (incidence->dtStart().date() == day || incidence->dtStart().date() < mStartDate) {
0104             item->insertIncidence(aitem);
0105         }
0106     }
0107 }
0108 
0109 void TimelineViewPrivate::insertIncidence(const Akonadi::CollectionCalendar::Ptr &calendar, const Akonadi::Item &incidence)
0110 {
0111     const Event::Ptr event = Akonadi::CalendarUtils::event(incidence);
0112     if (!event) {
0113         return;
0114     }
0115 
0116     if (event->recurs()) {
0117         insertIncidence(calendar, incidence, QDate());
0118     }
0119 
0120     for (QDate day = mStartDate; day <= mEndDate; day = day.addDays(1)) {
0121         const auto events = calendar->events(day, QTimeZone::systemTimeZone(), KCalendarCore::EventSortStartDate, KCalendarCore::SortDirectionAscending);
0122         if (events.contains(event)) {
0123             // PENDING(AKONADI_PORT) check if correct. also check the original if,
0124             // was inside the for loop (unnecessarily)
0125             for (const KCalendarCore::Event::Ptr &i : events) {
0126                 Akonadi::Item item = calendar->item(i);
0127                 insertIncidence(calendar, item, day);
0128             }
0129         }
0130     }
0131 }
0132 
0133 void TimelineViewPrivate::removeIncidence(const Akonadi::Item &incidence)
0134 {
0135     TimelineItem *item = calendarItemForIncidence(incidence);
0136     if (item) {
0137         item->removeIncidence(incidence);
0138     } else {
0139 #if 0 // AKONADI_PORT_DISABLED
0140       // try harder, the incidence might already be removed from the resource
0141         typedef QMap<QString, KOrg::TimelineItem *> M2_t;
0142         typedef QMap<KCalendarCore::ResourceCalendar *, M2_t> M1_t;
0143         for (M1_t::ConstIterator it1 = d->mCalendarItemMap.constBegin();
0144              it1 != mCalendarItemMap.constEnd(); ++it1) {
0145             for (M2_t::ConstIterator it2 = it1.value().constBegin();
0146                  it2 != it1.value().constEnd(); ++it2) {
0147                 if (it2.value()) {
0148                     it2.value()->removeIncidence(incidence);
0149                 }
0150             }
0151         }
0152 #endif
0153     }
0154 }
0155 
0156 void TimelineViewPrivate::itemChanged(QStandardItem *item)
0157 {
0158     auto tlit = dynamic_cast<TimelineSubItem *>(item);
0159     if (!tlit) {
0160         return;
0161     }
0162 
0163     const Akonadi::Item i = tlit->incidence();
0164     const Incidence::Ptr inc = Akonadi::CalendarUtils::incidence(i);
0165 
0166     QDateTime newStart(tlit->startTime());
0167     if (inc->allDay()) {
0168         newStart = QDateTime(newStart.date().startOfDay());
0169     }
0170 
0171     int delta = tlit->originalStart().secsTo(newStart);
0172     inc->setDtStart(inc->dtStart().addSecs(delta));
0173     int duration = tlit->startTime().secsTo(tlit->endTime());
0174     int allDayOffset = 0;
0175     if (inc->allDay()) {
0176         int secsPerDay = 60 * 60 * 24;
0177         duration /= secsPerDay;
0178         duration *= secsPerDay;
0179         allDayOffset = secsPerDay;
0180         duration -= allDayOffset;
0181         if (duration < 0) {
0182             duration = 0;
0183         }
0184     }
0185     inc->setDuration(duration);
0186     TimelineItem *parent = tlit->parent();
0187     parent->moveItems(i, tlit->originalStart().secsTo(newStart), duration + allDayOffset);
0188 }
0189 
0190 #include "moc_timelineview_p.cpp"