1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qquickmonthmodel_p.h"
5
6#include <QtCore/private/qabstractitemmodel_p.h>
7
8namespace {
9 static const int daysInAWeek = 7;
10 static const int weeksOnACalendarMonth = 6;
11 static const int daysOnACalendarMonth = daysInAWeek * weeksOnACalendarMonth;
12}
13
14QT_BEGIN_NAMESPACE
15
16class QQuickMonthModelPrivate : public QAbstractItemModelPrivate
17{
18 Q_DECLARE_PUBLIC(QQuickMonthModel)
19
20public:
21 QQuickMonthModelPrivate() : dates(daysOnACalendarMonth)
22 {
23 today = QDate::currentDate();
24 month = today.month();
25 year = today.year();
26 }
27
28 bool populate(int month, int year, const QLocale &locale, bool force = false);
29
30 int month;
31 int year;
32 QString title;
33 QLocale locale;
34 QVector<QDate> dates;
35 QDate today;
36};
37
38bool QQuickMonthModelPrivate::populate(int m, int y, const QLocale &l, bool force)
39{
40 Q_Q(QQuickMonthModel);
41 if (!force && m == month && y == year && l.firstDayOfWeek() == locale.firstDayOfWeek())
42 return false;
43
44 // The actual first (1st) day of the month.
45 QDate firstDayOfMonthDate(y, m, 1);
46 int difference = ((firstDayOfMonthDate.dayOfWeek() - l.firstDayOfWeek()) + 7) % 7;
47 // The first day to display should never be the 1st of the month, as we want some days from
48 // the previous month to be visible.
49 if (difference == 0)
50 difference += 7;
51 QDate firstDateToDisplay = firstDayOfMonthDate.addDays(days: -difference);
52
53 today = QDate::currentDate();
54 for (int i = 0; i < daysOnACalendarMonth; ++i)
55 dates[i] = firstDateToDisplay.addDays(days: i);
56
57 q->setTitle(l.standaloneMonthName(m) + QStringLiteral(" ") + QString::number(y));
58
59 return true;
60}
61
62QQuickMonthModel::QQuickMonthModel(QObject *parent) :
63 QAbstractListModel(*(new QQuickMonthModelPrivate), parent)
64{
65 Q_D(QQuickMonthModel);
66 d->populate(m: d->month, y: d->year, l: d->locale, force: true);
67}
68
69int QQuickMonthModel::month() const
70{
71 Q_D(const QQuickMonthModel);
72 return d->month;
73}
74
75void QQuickMonthModel::setMonth(int month)
76{
77 Q_D(QQuickMonthModel);
78 if (d->month != month) {
79 if (d->populate(m: month, y: d->year, l: d->locale))
80 emit dataChanged(topLeft: index(row: 0, column: 0), bottomRight: index(row: daysOnACalendarMonth - 1, column: 0));
81 d->month = month;
82 emit monthChanged();
83 }
84}
85
86int QQuickMonthModel::year() const
87{
88 Q_D(const QQuickMonthModel);
89 return d->year;
90}
91
92void QQuickMonthModel::setYear(int year)
93{
94 Q_D(QQuickMonthModel);
95 if (d->year != year) {
96 if (d->populate(m: d->month, y: year, l: d->locale))
97 emit dataChanged(topLeft: index(row: 0, column: 0), bottomRight: index(row: daysOnACalendarMonth - 1, column: 0));
98 d->year = year;
99 emit yearChanged();
100 }
101}
102
103QLocale QQuickMonthModel::locale() const
104{
105 Q_D(const QQuickMonthModel);
106 return d->locale;
107}
108
109void QQuickMonthModel::setLocale(const QLocale &locale)
110{
111 Q_D(QQuickMonthModel);
112 if (d->locale != locale) {
113 if (d->populate(m: d->month, y: d->year, l: locale))
114 emit dataChanged(topLeft: index(row: 0, column: 0), bottomRight: index(row: daysOnACalendarMonth - 1, column: 0));
115 d->locale = locale;
116 emit localeChanged();
117 }
118}
119
120QString QQuickMonthModel::title() const
121{
122 Q_D(const QQuickMonthModel);
123 return d->title;
124}
125
126void QQuickMonthModel::setTitle(const QString &title)
127{
128 Q_D(QQuickMonthModel);
129 if (d->title != title) {
130 d->title = title;
131 emit titleChanged();
132 }
133}
134
135QDate QQuickMonthModel::dateAt(int index) const
136{
137 Q_D(const QQuickMonthModel);
138 return d->dates.value(i: index);
139}
140
141int QQuickMonthModel::indexOf(const QDate &date) const
142{
143 Q_D(const QQuickMonthModel);
144 if (date < d->dates.first() || date > d->dates.last())
145 return -1;
146 return qMax(a: qint64(0), b: d->dates.first().daysTo(d: date));
147}
148
149QVariant QQuickMonthModel::data(const QModelIndex &index, int role) const
150{
151 Q_D(const QQuickMonthModel);
152 if (index.isValid() && index.row() < daysOnACalendarMonth) {
153 const QDate date = d->dates.at(i: index.row());
154 switch (role) {
155 case DateRole:
156 return date;
157 case DayRole:
158 return date.day();
159 case TodayRole:
160 return date == d->today;
161 case WeekNumberRole:
162 return date.weekNumber();
163 case MonthRole:
164 return date.month() - 1;
165 case YearRole:
166 return date.year();
167 default:
168 break;
169 }
170 }
171 return QVariant();
172}
173
174int QQuickMonthModel::rowCount(const QModelIndex &parent) const
175{
176 if (parent.isValid())
177 return 0;
178 return daysOnACalendarMonth;
179}
180
181QHash<int, QByteArray> QQuickMonthModel::roleNames() const
182{
183 QHash<int, QByteArray> roles;
184 roles[DateRole] = QByteArrayLiteral("date");
185 roles[DayRole] = QByteArrayLiteral("day");
186 roles[TodayRole] = QByteArrayLiteral("today");
187 roles[WeekNumberRole] = QByteArrayLiteral("weekNumber");
188 roles[MonthRole] = QByteArrayLiteral("month");
189 roles[YearRole] = QByteArrayLiteral("year");
190 return roles;
191}
192
193QT_END_NAMESPACE
194
195#include "moc_qquickmonthmodel_p.cpp"
196

source code of qtdeclarative/src/quicktemplates/qquickmonthmodel.cpp