File indexing completed on 2025-01-19 04:52:00
0001 /* 0002 Copyright (c) 2018 Michael Bohlender <michael.bohlender@kdemail.net> 0003 Copyright (c) 2018 Christian Mollekopf <mollekopf@kolabsys.com> 0004 Copyright (c) 2018 RĂ©mi Nicole <minijackson@riseup.net> 0005 0006 This library is free software; you can redistribute it and/or modify it 0007 under the terms of the GNU Library General Public License as published by 0008 the Free Software Foundation; either version 2 of the License, or (at your 0009 option) any later version. 0010 0011 This library is distributed in the hope that it will be useful, but WITHOUT 0012 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0013 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 0014 License for more details. 0015 0016 You should have received a copy of the GNU Library General Public License 0017 along with this library; see the file COPYING.LIB. If not, write to the 0018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 0019 02110-1301, USA. 0020 */ 0021 0022 #include "perioddayeventmodel.h" 0023 0024 #include <sink/log.h> 0025 0026 enum Roles { 0027 Events = EventOccurrenceModel::LastRole, 0028 Date 0029 }; 0030 0031 PeriodDayEventModel::PeriodDayEventModel(QObject *parent) 0032 : QAbstractItemModel(parent) 0033 { 0034 } 0035 0036 void PeriodDayEventModel::setModel(EventOccurrenceModel *model) 0037 { 0038 beginResetModel(); 0039 mSourceModel = model; 0040 auto resetModel = [this] { 0041 beginResetModel(); 0042 endResetModel(); 0043 }; 0044 QObject::connect(model, &QAbstractItemModel::dataChanged, this, resetModel); 0045 QObject::connect(model, &QAbstractItemModel::layoutChanged, this, resetModel); 0046 QObject::connect(model, &QAbstractItemModel::modelReset, this, resetModel); 0047 QObject::connect(model, &QAbstractItemModel::rowsInserted, this, resetModel); 0048 QObject::connect(model, &QAbstractItemModel::rowsMoved, this, resetModel); 0049 QObject::connect(model, &QAbstractItemModel::rowsRemoved, this, resetModel); 0050 endResetModel(); 0051 } 0052 0053 QModelIndex PeriodDayEventModel::index(int row, int column, const QModelIndex &parent) const 0054 { 0055 if (!hasIndex(row, column, parent)) { 0056 return {}; 0057 } 0058 0059 if (!parent.isValid()) { 0060 // Asking for a day 0061 return createIndex(row, column, DAY_ID); 0062 } 0063 0064 return {}; 0065 } 0066 0067 QModelIndex PeriodDayEventModel::parent(const QModelIndex &index) const 0068 { 0069 if (!index.isValid()) { 0070 return {}; 0071 } 0072 0073 if (index.internalId() == DAY_ID) { 0074 return {}; 0075 } 0076 0077 auto day = index.internalId(); 0078 0079 return this->index(day, 0); 0080 } 0081 0082 int PeriodDayEventModel::rowCount(const QModelIndex &parent) const 0083 { 0084 if (!parent.isValid() && mSourceModel) { 0085 return mSourceModel->length(); 0086 } 0087 return 0; 0088 } 0089 0090 int PeriodDayEventModel::columnCount(const QModelIndex &) const 0091 { 0092 return 1; 0093 } 0094 0095 QDateTime PeriodDayEventModel::getStartTimeOfDay(const QDateTime &dateTime, const QDate &today) const 0096 { 0097 if (dateTime.date() != today) { 0098 return QDateTime{today, QTime{0,0}}; 0099 } 0100 return dateTime; 0101 } 0102 0103 QDateTime PeriodDayEventModel::getEndTimeOfDay(const QDateTime &dateTime, const QDate &today) const 0104 { 0105 if (dateTime.date() != today) { 0106 return QDateTime{today, QTime{23, 59, 59}}; 0107 } 0108 return dateTime; 0109 } 0110 0111 QVariant PeriodDayEventModel::data(const QModelIndex &idx, int role) const 0112 { 0113 if (!mSourceModel) { 0114 return {}; 0115 } 0116 const auto dayOffset = idx.row(); 0117 const QDate startDate = mSourceModel->start(); 0118 const auto today = startDate.addDays(dayOffset); 0119 switch (role) { 0120 case Date: 0121 return today; 0122 case Events: { 0123 auto result = QVariantList{}; 0124 0125 QMultiMap<QTime, QModelIndex> sorted; 0126 //Sort events of the day by starting date 0127 for (int row = 0; row < mSourceModel->rowCount(); row++) { 0128 const auto srcIdx = mSourceModel->index(row, 0, {}); 0129 //filter all-day events (we don't display them here) 0130 if (srcIdx.data(EventOccurrenceModel::AllDay).toBool()) { 0131 continue; 0132 } 0133 const auto start = srcIdx.data(EventOccurrenceModel::StartTime).toDateTime().toLocalTime(); 0134 const auto end = srcIdx.data(EventOccurrenceModel::EndTime).toDateTime().toLocalTime(); 0135 //not today 0136 if (end.date() < today || start.date() > today) { 0137 continue; 0138 } 0139 sorted.insert(start.time(), srcIdx); 0140 } 0141 0142 QMultiMap<QTime, int> indentationStack; 0143 for (auto it = sorted.begin(); it != sorted.end(); it++) { 0144 const auto srcIdx = it.value(); 0145 0146 const auto start = getStartTimeOfDay(srcIdx.data(EventOccurrenceModel::StartTime).toDateTime().toLocalTime(), today); 0147 const auto startTime = start.time(); 0148 const auto end = getEndTimeOfDay(srcIdx.data(EventOccurrenceModel::EndTime).toDateTime().toLocalTime(), today); 0149 auto endTime = end.time(); 0150 if (!endTime.isValid() || endTime == startTime) { 0151 //Even without duration we still take some space visually 0152 endTime = startTime.addSecs(60 * 20); 0153 } 0154 const auto duration = startTime.secsTo(endTime) / 3600.0; 0155 SinkTrace() << "Appending event:" << srcIdx.data(EventOccurrenceModel::Summary) << start << end << duration; 0156 0157 //Remove all dates before startTime 0158 for (auto it = indentationStack.begin(); it != indentationStack.end();) { 0159 if (it.key() <= startTime) { 0160 it = indentationStack.erase(it); 0161 } else { 0162 ++it; 0163 } 0164 } 0165 const int indentation = indentationStack.size(); 0166 indentationStack.insert(endTime, 0); 0167 0168 0169 result.append(QVariantMap{ 0170 {"text", srcIdx.data(EventOccurrenceModel::Summary)}, 0171 {"startDate", srcIdx.data(EventOccurrenceModel::StartTime)}, 0172 {"description", srcIdx.data(EventOccurrenceModel::Description)}, 0173 {"starts", startTime.hour() + startTime.minute() / 60.}, 0174 {"duration", duration}, 0175 {"color", srcIdx.data(EventOccurrenceModel::Color)}, 0176 {"indentation", indentation}, 0177 {"eventOccurrence", srcIdx.data(EventOccurrenceModel::EventOccurrence)} 0178 }); 0179 } 0180 0181 return result; 0182 } 0183 default: 0184 Q_ASSERT(false); 0185 return {}; 0186 } 0187 } 0188 0189 QHash<int, QByteArray> PeriodDayEventModel::roleNames() const 0190 { 0191 return { 0192 {Events, "events"}, 0193 {Date, "date"} 0194 }; 0195 }