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 const QDateTime startDate = m_startDates[idx.row()];
75
76 if (m_scale == MonthScale && role != StartDateRole) {
77 const QDateTime firstDay = m_firstDayOfMonthDates[idx.row()];
78
79 switch (role) {
80 case FirstDayOfMonthRole:
81 return firstDay.date().startOfDay();
82 case SelectedMonthRole:
83 return firstDay.date().month();
84 case SelectedYearRole:
85 return firstDay.date().year();
86 default:
87 qWarning() << "Unknown role for startdate:" << QMetaEnum::fromType<Roles>().valueToKey(role);
88 return {};
89 }
90 }
91
92 switch (role) {
93 case StartDateRole:
94 return startDate.date().startOfDay();
95 case SelectedMonthRole:
96 return startDate.date().month();
97 case SelectedYearRole:
98 return startDate.date().year();
99 default:
100 qWarning() << "Unknown role for startdate:" << QMetaEnum::fromType<Roles>().valueToKey(role);
101 return {};
102 }
103}
104
105int InfiniteCalendarViewModel::rowCount(const QModelIndex &parent) const
106{
107 Q_UNUSED(parent)
108 return m_startDates.length();
109}
110
111QHash<int, QByteArray> InfiniteCalendarViewModel::roleNames() const
112{
113 return {
114 {StartDateRole, QByteArrayLiteral("startDate")},
115 {FirstDayOfMonthRole, QByteArrayLiteral("firstDay")},
116 {SelectedMonthRole, QByteArrayLiteral("selectedMonth")},
117 {SelectedYearRole, QByteArrayLiteral("selectedYear")},
118 };
119}
120
121QDateTime InfiniteCalendarViewModel::currentDate() const
122{
123 return m_currentDate;
124}
125
126void InfiniteCalendarViewModel::setCurrentDate(const QDateTime &currentDate)
127{
128 m_currentDate = currentDate;
129}
130
131QDateTime InfiniteCalendarViewModel::minimumDate() const
132{
133 return m_minimumDate;
134}
135
136void InfiniteCalendarViewModel::setMinimumDate(const QDateTime &minimumDate)
137{
138 if (m_minimumDate == minimumDate) {
139 return;
140 }
141 m_minimumDate = minimumDate;
142 Q_EMIT minimumDateChanged();
143}
144
145QDateTime InfiniteCalendarViewModel::maximumDate() const
146{
147 return m_maximumDate;
148}
149
150void InfiniteCalendarViewModel::setMaximumDate(const QDateTime &maximumDate)
151{
152 if (m_maximumDate == maximumDate) {
153 return;
154 }
155 m_maximumDate = maximumDate;
156 Q_EMIT maximumDateChanged();
157}
158
159void InfiniteCalendarViewModel::addDates(bool atEnd, const QDateTime startFrom)
160{
161 switch (m_scale) {
162 case WeekScale:
163 addWeekDates(atEnd, startFrom);
164 break;
165 case MonthScale:
166 addMonthDates(atEnd, startFrom);
167 break;
168 case YearScale:
169 addYearDates(atEnd, startFrom);
170 break;
171 case DecadeScale:
172 addDecadeDates(atEnd, startFrom);
173 break;
174 }
175}
176
177void InfiniteCalendarViewModel::addWeekDates(bool atEnd, const QDateTime &startFrom)
178{
179 const int newRow = atEnd ? rowCount() : 0;
180
181 beginInsertRows(QModelIndex(), newRow, newRow + m_datesToAdd - 1);
182
183 for (int i = 0; i < m_datesToAdd; i++) {
184 QDateTime startDate = startFrom.isValid() && i == 0 ? startFrom : atEnd ? m_startDates[rowCount() - 1].addDays(7) : m_startDates[0].addDays(-7);
185
186 if (startDate.date().dayOfWeek() != m_locale.firstDayOfWeek()) {
187 startDate = startDate.addDays(-startDate.date().dayOfWeek() + m_locale.firstDayOfWeek());
188 }
189
190 if (atEnd) {
191 m_startDates.append(startDate);
192 } else {
193 m_startDates.insert(0, startDate);
194 }
195 }
196
198}
199
200void InfiniteCalendarViewModel::addMonthDates(bool atEnd, const QDateTime &startFrom)
201{
202 QVector<QDateTime> startDates;
203
204 const int newRow = atEnd ? rowCount() : 0;
205
206 for (int i = 0; i < m_datesToAdd; i++) {
207 QDateTime firstDay;
208
209 if (startFrom.isValid() && i == 0) {
210 firstDay = startFrom;
211 } else if (atEnd) {
212 firstDay = m_firstDayOfMonthDates[newRow + startDates.length() - 1].addMonths(1);
213 } else {
214 firstDay = m_firstDayOfMonthDates[0].addMonths(-1);
215 }
216
217 QDateTime startDate = firstDay;
218
219 startDate = startDate.addDays(-startDate.date().dayOfWeek() + m_locale.firstDayOfWeek());
220 if (startDate >= firstDay) {
221 startDate = startDate.addDays(-7);
222 }
223
224 if (atEnd) {
225 if (m_maximumDate.isValid() && startDate > m_maximumDate) {
226 break;
227 }
228 m_firstDayOfMonthDates.append(firstDay);
229 startDates.append(startDate);
230 } else {
231 m_firstDayOfMonthDates.insert(0, firstDay);
232 startDates.insert(0, startDate);
233 }
234 }
235
236 beginInsertRows({}, newRow, newRow + startDates.length() - 1);
237
238 if (atEnd) {
239 m_startDates = m_startDates + startDates;
240 } else {
241 m_startDates = startDates + m_startDates;
242 }
243
245}
246
247void InfiniteCalendarViewModel::addYearDates(bool atEnd, const QDateTime &startFrom)
248{
249 const int newRow = atEnd ? rowCount() : 0;
250
251 beginInsertRows(QModelIndex(), newRow, newRow + m_datesToAdd - 1);
252
253 for (int i = 0; i < m_datesToAdd; i++) {
254 QDateTime startDate = startFrom.isValid() && i == 0 ? startFrom : atEnd ? m_startDates[rowCount() - 1].addYears(1) : m_startDates[0].addYears(-1);
255
256 if (atEnd) {
257 m_startDates.append(startDate);
258 } else {
259 m_startDates.insert(0, startDate);
260 }
261 }
262
264}
265
266void InfiniteCalendarViewModel::addDecadeDates(bool atEnd, const QDateTime &startFrom)
267{
268 const int newRow = atEnd ? rowCount() : 0;
269
270 beginInsertRows(QModelIndex(), newRow, newRow + m_datesToAdd - 1);
271
272 for (int i = 0; i < m_datesToAdd; i++) {
273 QDateTime startDate = startFrom.isValid() && i == 0 ? startFrom : atEnd ? m_startDates[rowCount() - 1].addYears(10) : m_startDates[0].addYears(-10);
274
275 if (atEnd) {
276 m_startDates.append(startDate);
277 } else {
278 m_startDates.insert(0, startDate);
279 }
280 }
281
283}
284
285int InfiniteCalendarViewModel::datesToAdd() const
286{
287 return m_datesToAdd;
288}
289
290void InfiniteCalendarViewModel::setDatesToAdd(int datesToAdd)
291{
292 m_datesToAdd = datesToAdd;
293 Q_EMIT datesToAddChanged();
294}
295
296int InfiniteCalendarViewModel::scale()
297{
298 return m_scale;
299}
300
301void InfiniteCalendarViewModel::setScale(int scale)
302{
304
305 m_startDates.clear();
306 m_firstDayOfMonthDates.clear();
307 m_scale = scale;
308 setup();
309 Q_EMIT scaleChanged();
310
312}
313
314#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
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 Fri May 3 2024 11:46:57 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.