Kirigami-addons

monthmodel.cpp
1// SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org>
2// SPDX-License-Identifier: LGPL-2.1-or-later
3
4#include "monthmodel.h"
5#include <QRandomGenerator>
6
7class MonthModel::Private {
8public:
9 int year;
10 int month;
11 QCalendar calendar = QCalendar();
12 QDate selected;
13};
14
15MonthModel::MonthModel(QObject *parent)
16 : QAbstractListModel(parent)
17 , d(new MonthModel::Private())
18{
19 goToday();
20 d->selected = QDate::currentDate();
21}
22
23MonthModel::~MonthModel()
24{
25}
26
27int MonthModel::year() const
28{
29 return d->year;
30}
31
32void MonthModel::setYear(int year)
33{
34 if (d->year == year) {
35 return;
36 }
37 d->year = year;
38 Q_EMIT yearChanged();
39 Q_EMIT dataChanged(index(0, 0), index(41, 0));
40 setSelected(QDate(year, d->selected.month(), qMin(d->selected.day(), d->calendar.daysInMonth(d->selected.month(), year))));
41}
42
43int MonthModel::month() const
44{
45 return d->month;
46}
47
48void MonthModel::setMonth(int month)
49{
50 if (d->month == month) {
51 return;
52 }
53 d->month = month;
54 Q_EMIT monthChanged();
55 Q_EMIT dataChanged(index(0, 0), index(41, 0));
56 setSelected(QDate(d->selected.year(), d->month, qMin(d->selected.day(), d->calendar.daysInMonth(d->month, d->selected.year()))));
57}
58
60{
61 return d->selected;
62}
63
64void MonthModel::setSelected(const QDate &selected)
65{
66 if (d->selected == selected) {
67 return;
68 }
69 d->selected = selected;
70 Q_EMIT selectedChanged();
71 Q_EMIT dataChanged(index(0, 0), index(41, 0), {Roles::IsSelected});
72}
73
75{
76 QLocale locale;
77 QStringList daysName;
78 for (int i = 0; i < 7; i++) {
79 int day = locale.firstDayOfWeek() + i;
80 if (day > 7) {
81 day -= 7;
82 }
83 if (day == 7) {
84 day = 0;
85 }
86 daysName.append(locale.standaloneDayName(day == 0 ? Qt::Sunday : day, QLocale::NarrowFormat));
87 }
88 return daysName;
89}
90
92{
93 if (d->month == 1) {
94 setYear(d->year - 1);
95 setMonth(d->calendar.monthsInYear(d->year) - 1);
96 } else {
97 setMonth(d->month - 1);
98 }
99}
100
101void MonthModel::next()
102{
103 if (d->calendar.monthsInYear(d->year) == d->month) {
104 setMonth(1);
105 setYear(d->year + 1);
106 } else {
107 setMonth(d->month + 1);
108 }
109}
110
112{
113 const auto today = QDate::currentDate();
114 setMonth(today.month());
115 setYear(today.year());
116}
117
118QVariant MonthModel::data(const QModelIndex &index, int role) const
119{
120 if (!index.isValid()) {
121 return {};
122 }
123
124 const int row = index.row();
125
126 if (!index.parent().isValid()) {
127 // Fetch days in month
128 int prefix = d->calendar.dayOfWeek(QDate(d->year, d->month, 1)) - m_locale.firstDayOfWeek();
129
130 if (prefix <= 1) {
131 prefix += 7;
132 } else if (prefix > 7) {
133 prefix -= 7;
134 }
135
136 switch (role) {
137 case Qt::DisplayRole:
138 case DayNumber:
139 case IsSelected:
140 case IsToday:
141 case Date: {
142 int day = -1;
143 int month = d->month;
144 int year = d->year;
145 const int daysInMonth = d->calendar.daysInMonth(d->month, d->year);
146 if (row >= prefix && row - prefix < daysInMonth) {
147 // This month
148 day = row - prefix + 1;
149 } else if (row - prefix >= daysInMonth) {
150 // Next month
151 month = d->calendar.monthsInYear(d->year) == d->month ? 1 : d->month + 1;
152 year = d->calendar.monthsInYear(d->year) == d->month ? d->year + 1 : d->year;
153 day = row - daysInMonth - prefix + 1;
154 } else {
155 // Previous month
156 year = d->month > 1 ? d->year : d->year - 1;
157 month = d->month > 1 ? d->month - 1 : d->calendar.monthsInYear(year);
158 int daysInPreviousMonth = d->calendar.daysInMonth(month, year);
159 day = daysInPreviousMonth - prefix + row + 1;
160 }
161
162 if (role == DayNumber || role == Qt::DisplayRole) {
163 return day;
164 }
165 const QDate date(year, month, day);
166 if (role == Date) {
167 return date.startOfDay();
168 // Ensure the date doesn't get mangled into a different date by QML date conversion
169 }
170
171 if (role == IsSelected) {
172 return d->selected == date;
173 }
174 if (role == IsToday) {
175 return date == QDate::currentDate();
176 }
177 return {};
178 }
179 case SameMonth: {
180 const int daysInMonth = d->calendar.daysInMonth(d->month, d->year);
181 return row >= prefix && row - prefix < daysInMonth;
182 }
183 }
184 }
185 return {};
186}
187
188int MonthModel::rowCount(const QModelIndex &parent) const
189{
190 Q_UNUSED(parent);
191 return 42; // Display 6 weeks with each 7 days
192}
193
194QHash<int, QByteArray> MonthModel::roleNames() const
195{
196 return {
197 {Qt::DisplayRole, QByteArrayLiteral("display")},
198 {Roles::DayNumber, QByteArrayLiteral("dayNumber")},
199 {Roles::SameMonth, QByteArrayLiteral("sameMonth")},
200 {Roles::Date, QByteArrayLiteral("date")},
201 {Roles::IsSelected, QByteArrayLiteral("isSelected")},
202 {Roles::IsToday, QByteArrayLiteral("isToday")},
203 };
204}
205
206#include "moc_monthmodel.cpp"
Q_INVOKABLE void next()
Q_INVOKABLE void previous()
QDate selected
Definition monthmodel.h:26
QStringList weekDays
Definition monthmodel.h:24
Q_INVOKABLE void goToday()
QML_ELEMENTint year
Definition monthmodel.h:20
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList< int > &roles)
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const override
QDate currentDate()
void append(QList< T > &&value)
Qt::DayOfWeek firstDayOfWeek() const const
QString standaloneDayName(int day, FormatType type) const const
bool isValid() const const
QModelIndex parent() const const
int row() const const
Q_EMITQ_EMIT
QObject * parent() const const
DisplayRole
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.