Kirigami-addons

infinitecalendarviewmodel.cpp
1// SPDX-FileCopyrightText: 2021 Claudio Cambra <claudio.cambra@gmail.com>
2// SPDX-License-Identifier: LGPL-2.1-or-later
3
4#include <QMetaEnum>
5#include <cmath>
6#include "infinitecalendarviewmodel.h"
7
8InfiniteCalendarViewModel::InfiniteCalendarViewModel(QObject *parent)
9 : QAbstractListModel(parent)
10{
11}
12
13void InfiniteCalendarViewModel::classBegin()
14{
15
16}
17
18void InfiniteCalendarViewModel::componentComplete()
19{
20 m_isCompleted = true;
21 setup();
22}
23
24void InfiniteCalendarViewModel::setup()
25{
26 if (!m_isCompleted) {
27 return;
28 }
29
30 if (!m_currentDate.isValid()) {
31 return;
32 }
33
34 switch (m_scale) {
35 case WeekScale: {
36 QDateTime firstDay = m_currentDate.addDays(-m_currentDate.date().dayOfWeek() + m_locale.firstDayOfWeek());
37 // We create dates before and after where our view will start from (which is m_currentDate)
38 firstDay = firstDay.addDays((-m_datesToAdd * 7) / 2);
39
40 addWeekDates(true, firstDay);
41 break;
42 }
43 case MonthScale: {
44 QDateTime firstDay(QDate(m_currentDate.date().year(), m_currentDate.date().month(), 1), {});
45 firstDay = firstDay.addMonths(-m_datesToAdd / 2);
46
47 addMonthDates(true, firstDay);
48 break;
49 }
50 case YearScale: {
51 QDateTime firstDay(QDate(m_currentDate.date().year(), m_currentDate.date().month(), 1), {});
52 firstDay = firstDay.addYears(-m_datesToAdd / 2);
53
54 addYearDates(true, firstDay);
55 break;
56 }
57 case DecadeScale: {
58 const int firstYear = ((floor(m_currentDate.date().year() / 10)) * 10) - 1; // E.g. For 2020 have view start at 2019...
59 QDateTime firstDay(QDate(firstYear, m_currentDate.date().month(), 1), {});
60 firstDay = firstDay.addYears(((-m_datesToAdd * 12) / 2) + 10); // 3 * 4 grid so 12 years, end at 2030, and align for mid index to be current decade
61
62 addDecadeDates(true, firstDay);
63 break;
64 }
65 }
66}
67
68QVariant InfiniteCalendarViewModel::data(const QModelIndex &idx, int role) const
69{
70 if (!hasIndex(idx.row(), idx.column())) {
71 return {};
72 }
73
74 if (m_scale == MonthScale && role != StartDateRole) {
75 const auto firstDay = m_firstDayOfMonthDates[idx.row()].date();
76
77 switch (role) {
78 case FirstDayOfMonthRole:
79 return firstDay.startOfDay();
80 case SelectedMonthRole:
81 return firstDay.month();
82 case SelectedYearRole:
83 return firstDay.year();
84 default:
85 qWarning() << "Unknown role for firstDay:" << QMetaEnum::fromType<Roles>().valueToKey(role);
86 return {};
87 }
88 }
89
90 const auto startDate = m_startDates[idx.row()].date();
91
92 switch (role) {
93 case FirstDayOfMonthRole:
94 return QDate(startDate.year(), startDate.month(), 1).startOfDay();
95 case StartDateRole:
96 return startDate.startOfDay();
97 case SelectedMonthRole:
98 return startDate.month();
99 case SelectedYearRole:
100 return startDate.year();
101 default:
102 qWarning() << "Unknown role for startdate:" << QMetaEnum::fromType<Roles>().valueToKey(role);
103 return {};
104 }
105}
106
107int InfiniteCalendarViewModel::rowCount(const QModelIndex &parent) const
108{
109 Q_UNUSED(parent)
110 return m_startDates.length();
111}
112
113QHash<int, QByteArray> InfiniteCalendarViewModel::roleNames() const
114{
115 return {
116 {StartDateRole, QByteArrayLiteral("startDate")},
117 {FirstDayOfMonthRole, QByteArrayLiteral("firstDay")},
118 {SelectedMonthRole, QByteArrayLiteral("selectedMonth")},
119 {SelectedYearRole, QByteArrayLiteral("selectedYear")},
120 };
121}
122
123QDateTime InfiniteCalendarViewModel::currentDate() const
124{
125 return m_currentDate;
126}
127
128void InfiniteCalendarViewModel::setCurrentDate(const QDateTime &currentDate)
129{
130 m_currentDate = currentDate;
131}
132
133QDateTime InfiniteCalendarViewModel::minimumDate() const
134{
135 return m_minimumDate;
136}
137
138void InfiniteCalendarViewModel::setMinimumDate(const QDateTime &minimumDate)
139{
140 if (m_minimumDate == minimumDate) {
141 return;
142 }
143 m_minimumDate = minimumDate;
144 Q_EMIT minimumDateChanged();
145}
146
147QDateTime InfiniteCalendarViewModel::maximumDate() const
148{
149 return m_maximumDate;
150}
151
152void InfiniteCalendarViewModel::setMaximumDate(const QDateTime &maximumDate)
153{
154 if (m_maximumDate == maximumDate) {
155 return;
156 }
157 m_maximumDate = maximumDate;
158 Q_EMIT maximumDateChanged();
159}
160
161void InfiniteCalendarViewModel::addDates(bool atEnd, const QDateTime startFrom)
162{
163 switch (m_scale) {
164 case WeekScale:
165 addWeekDates(atEnd, startFrom);
166 break;
167 case MonthScale:
168 addMonthDates(atEnd, startFrom);
169 break;
170 case YearScale:
171 addYearDates(atEnd, startFrom);
172 break;
173 case DecadeScale:
174 addDecadeDates(atEnd, startFrom);
175 break;
176 }
177}
178
179void InfiniteCalendarViewModel::addWeekDates(bool atEnd, const QDateTime &startFrom)
180{
181 const int newRow = atEnd ? rowCount() : 0;
182
183 beginInsertRows(QModelIndex(), newRow, newRow + m_datesToAdd - 1);
184
185 for (int i = 0; i < m_datesToAdd; i++) {
186 QDateTime startDate = startFrom.isValid() && i == 0 ? startFrom : atEnd ? m_startDates[rowCount() - 1].addDays(7) : m_startDates[0].addDays(-7);
187
188 if (startDate.date().dayOfWeek() != m_locale.firstDayOfWeek()) {
189 startDate = startDate.addDays(-startDate.date().dayOfWeek() + m_locale.firstDayOfWeek());
190 }
191
192 if (atEnd) {
193 m_startDates.append(startDate);
194 } else {
195 m_startDates.insert(0, startDate);
196 }
197 }
198
200}
201
202void InfiniteCalendarViewModel::addMonthDates(bool atEnd, const QDateTime &startFrom)
203{
204 QVector<QDateTime> startDates;
205
206 const int newRow = atEnd ? rowCount() : 0;
207
208 for (int i = 0; i < m_datesToAdd; i++) {
209 QDateTime firstDay;
210
211 if (startFrom.isValid() && i == 0) {
212 firstDay = startFrom;
213 } else if (atEnd) {
214 firstDay = m_firstDayOfMonthDates[newRow + startDates.length() - 1].addMonths(1);
215 } else {
216 firstDay = m_firstDayOfMonthDates[0].addMonths(-1);
217 }
218
219 QDateTime startDate = firstDay;
220
221 startDate = startDate.addDays(-startDate.date().dayOfWeek() + m_locale.firstDayOfWeek());
222 if (startDate >= firstDay) {
223 startDate = startDate.addDays(-7);
224 }
225
226 if (atEnd) {
227 if (m_maximumDate.isValid() && startDate > m_maximumDate) {
228 break;
229 }
230 m_firstDayOfMonthDates.append(firstDay);
231 startDates.append(startDate);
232 } else {
233 m_firstDayOfMonthDates.insert(0, firstDay);
234 startDates.insert(0, startDate);
235 }
236 }
237
238 beginInsertRows({}, newRow, newRow + startDates.length() - 1);
239
240 if (atEnd) {
241 m_startDates = m_startDates + startDates;
242 } else {
243 m_startDates = startDates + m_startDates;
244 }
245
247}
248
249void InfiniteCalendarViewModel::addYearDates(bool atEnd, const QDateTime &startFrom)
250{
251 const int newRow = atEnd ? rowCount() : 0;
252
253 beginInsertRows(QModelIndex(), newRow, newRow + m_datesToAdd - 1);
254
255 for (int i = 0; i < m_datesToAdd; i++) {
256 QDateTime startDate = startFrom.isValid() && i == 0 ? startFrom : atEnd ? m_startDates[rowCount() - 1].addYears(1) : m_startDates[0].addYears(-1);
257
258 if (atEnd) {
259 m_startDates.append(startDate);
260 } else {
261 m_startDates.insert(0, startDate);
262 }
263 }
264
266}
267
268void InfiniteCalendarViewModel::addDecadeDates(bool atEnd, const QDateTime &startFrom)
269{
270 const int newRow = atEnd ? rowCount() : 0;
271
272 beginInsertRows(QModelIndex(), newRow, newRow + m_datesToAdd - 1);
273
274 for (int i = 0; i < m_datesToAdd; i++) {
275 QDateTime startDate = startFrom.isValid() && i == 0 ? startFrom : atEnd ? m_startDates[rowCount() - 1].addYears(10) : m_startDates[0].addYears(-10);
276
277 if (atEnd) {
278 m_startDates.append(startDate);
279 } else {
280 m_startDates.insert(0, startDate);
281 }
282 }
283
285}
286
287int InfiniteCalendarViewModel::datesToAdd() const
288{
289 return m_datesToAdd;
290}
291
292void InfiniteCalendarViewModel::setDatesToAdd(int datesToAdd)
293{
294 m_datesToAdd = datesToAdd;
295 Q_EMIT datesToAddChanged();
296}
297
298int InfiniteCalendarViewModel::scale()
299{
300 return m_scale;
301}
302
303void InfiniteCalendarViewModel::setScale(int scale)
304{
306
307 m_startDates.clear();
308 m_firstDayOfMonthDates.clear();
309 m_scale = scale;
310 setup();
311 Q_EMIT scaleChanged();
312
314}
315
316#include "moc_infinitecalendarviewmodel.cpp"
void beginInsertRows(const QModelIndex &parent, int first, int last)
bool hasIndex(int row, int column, const QModelIndex &parent) const const
int dayOfWeek() const const
int month() const const
QDateTime startOfDay() const const
int year() const const
QDateTime addDays(qint64 ndays) const const
QDateTime addMonths(int nmonths) const const
QDateTime addYears(int nyears) const const
QDate date() const const
bool isValid() const const
void append(QList< T > &&value)
iterator insert(const_iterator before, parameter_type value)
qsizetype length() const const
Qt::DayOfWeek firstDayOfWeek() const const
QMetaEnum fromType()
const char * valueToKey(int value) const const
int column() const const
int row() const const
Q_EMITQ_EMIT
QObject * parent() const const
QTestData & newRow(const char *dataTag)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 17:03:50 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.