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 "qquickcalendarmodel_p.h" |
5 | |
6 | #include <QtCore/private/qabstractitemmodel_p.h> |
7 | |
8 | QT_BEGIN_NAMESPACE |
9 | |
10 | /*! |
11 | \qmltype CalendarModel |
12 | \inherits QAbstractListModel |
13 | //! \instantiates QQuickCalendarModel |
14 | \inqmlmodule QtQuick.Controls |
15 | \brief A calendar model. |
16 | |
17 | CalendarModel provides a way of creating a range of MonthGrid |
18 | instances. It is typically used as a model for a ListView that uses |
19 | MonthGrid as a delegate. |
20 | |
21 | \snippet qtquickcontrols-calendarmodel.qml 1 |
22 | |
23 | In addition to the \c index property, a list of model data roles |
24 | are available in the context of each delegate: |
25 | \table |
26 | \row \li \b model.month : int \li The number of the month |
27 | \row \li \b model.year : int \li The number of the year |
28 | \endtable |
29 | |
30 | \include zero-based-months.qdocinc |
31 | |
32 | \sa MonthGrid, Calendar |
33 | */ |
34 | |
35 | class QQuickCalendarModelPrivate : public QAbstractItemModelPrivate |
36 | { |
37 | Q_DECLARE_PUBLIC(QQuickCalendarModel) |
38 | |
39 | public: |
40 | QQuickCalendarModelPrivate() : complete(false), |
41 | from(1,1,1), to(275759, 9, 25), count(0) |
42 | { |
43 | } |
44 | |
45 | static int getCount(QDate from, QDate to); |
46 | |
47 | void populate(QDate from, QDate to, bool force = false); |
48 | |
49 | bool complete; |
50 | QDate from; |
51 | QDate to; |
52 | int count; |
53 | }; |
54 | |
55 | // Returns the number of months we need to display for both from and to to be shown, |
56 | // or zero if from is in a later month than to, or either is invalid. |
57 | int QQuickCalendarModelPrivate::getCount(QDate from, QDate to) |
58 | { |
59 | if (!from.isValid() || !to.isValid()) |
60 | return 0; |
61 | |
62 | const QCalendar gregorian; |
63 | Q_ASSERT(gregorian.isGregorian()); |
64 | const QCalendar::YearMonthDay &f = gregorian.partsFromDate(date: from); |
65 | const QCalendar::YearMonthDay &t = gregorian.partsFromDate(date: to); |
66 | Q_ASSERT(f.isValid() && t.isValid()); // ... because from and to are valid. |
67 | if (f.year > t.year || (f.year == t.year && f.month > t.month)) |
68 | return 0; |
69 | |
70 | // Count from's month and every subsequent month until to's: |
71 | return 1 + t.month + 12 * (t.year - f.year) - f.month; |
72 | } |
73 | |
74 | void QQuickCalendarModelPrivate::populate(QDate f, QDate t, bool force) |
75 | { |
76 | Q_Q(QQuickCalendarModel); |
77 | if (!force && f == from && t == to) |
78 | return; |
79 | |
80 | int c = getCount(from, to); |
81 | if (c != count) { |
82 | q->beginResetModel(); |
83 | count = c; |
84 | q->endResetModel(); |
85 | emit q->countChanged(); |
86 | } else { |
87 | emit q->dataChanged(topLeft: q->index(row: 0, column: 0), bottomRight: q->index(row: c - 1, column: 0)); |
88 | } |
89 | } |
90 | |
91 | QQuickCalendarModel::QQuickCalendarModel(QObject *parent) : |
92 | QAbstractListModel(*(new QQuickCalendarModelPrivate), parent) |
93 | { |
94 | } |
95 | |
96 | /*! |
97 | \qmlproperty date QtQuick.Controls::CalendarModel::from |
98 | |
99 | This property holds the start date. |
100 | */ |
101 | QDate QQuickCalendarModel::from() const |
102 | { |
103 | Q_D(const QQuickCalendarModel); |
104 | return d->from; |
105 | } |
106 | |
107 | void QQuickCalendarModel::setFrom(const QDate &from) |
108 | { |
109 | Q_D(QQuickCalendarModel); |
110 | if (d->from != from) { |
111 | if (d->complete) |
112 | d->populate(f: from, t: d->to); |
113 | d->from = from; |
114 | emit fromChanged(); |
115 | } |
116 | } |
117 | |
118 | /*! |
119 | \qmlproperty date QtQuick.Controls::CalendarModel::to |
120 | |
121 | This property holds the end date. |
122 | */ |
123 | QDate QQuickCalendarModel::to() const |
124 | { |
125 | Q_D(const QQuickCalendarModel); |
126 | return d->to; |
127 | } |
128 | |
129 | void QQuickCalendarModel::setTo(const QDate &to) |
130 | { |
131 | Q_D(QQuickCalendarModel); |
132 | if (d->to != to) { |
133 | if (d->complete) |
134 | d->populate(f: d->from, t: to); |
135 | d->to = to; |
136 | emit toChanged(); |
137 | } |
138 | } |
139 | |
140 | /*! |
141 | \qmlmethod int QtQuick.Controls::CalendarModel::monthAt(int index) |
142 | |
143 | Returns the month number at the specified model \a index. |
144 | */ |
145 | int QQuickCalendarModel::monthAt(int index) const |
146 | { |
147 | Q_D(const QQuickCalendarModel); |
148 | return d->from.addMonths(months: index).month() - 1; |
149 | } |
150 | |
151 | /*! |
152 | \qmlmethod int QtQuick.Controls::CalendarModel::yearAt(int index) |
153 | |
154 | Returns the year number at the specified model \a index. |
155 | */ |
156 | int QQuickCalendarModel::yearAt(int index) const |
157 | { |
158 | Q_D(const QQuickCalendarModel); |
159 | return d->from.addMonths(months: index).year(); |
160 | } |
161 | |
162 | /*! |
163 | \qmlmethod int QtQuick.Controls::CalendarModel::indexOf(Date date) |
164 | |
165 | Returns the model index of the specified \a date. |
166 | */ |
167 | int QQuickCalendarModel::indexOf(const QDate &date) const |
168 | { |
169 | Q_D(const QQuickCalendarModel); |
170 | return d->getCount(from: d->from, to: date) - 1; |
171 | } |
172 | |
173 | /*! |
174 | \qmlmethod int QtQuick.Controls::CalendarModel::indexOf(int year, int month) |
175 | |
176 | Returns the model index of the specified \a year and \a month. |
177 | */ |
178 | int QQuickCalendarModel::indexOf(int year, int month) const |
179 | { |
180 | return indexOf(date: QDate(year, month + 1, 1)); |
181 | } |
182 | |
183 | QVariant QQuickCalendarModel::data(const QModelIndex &index, int role) const |
184 | { |
185 | Q_D(const QQuickCalendarModel); |
186 | if (index.isValid() && index.row() < d->count) { |
187 | switch (role) { |
188 | case MonthRole: |
189 | return monthAt(index: index.row()); |
190 | case YearRole: |
191 | return yearAt(index: index.row()); |
192 | default: |
193 | break; |
194 | } |
195 | } |
196 | return QVariant(); |
197 | } |
198 | |
199 | int QQuickCalendarModel::rowCount(const QModelIndex &parent) const |
200 | { |
201 | Q_D(const QQuickCalendarModel); |
202 | if (!parent.isValid()) |
203 | return d->count; |
204 | return 0; |
205 | } |
206 | |
207 | QHash<int, QByteArray> QQuickCalendarModel::roleNames() const |
208 | { |
209 | QHash<int, QByteArray> roles; |
210 | roles[MonthRole] = QByteArrayLiteral("month" ); |
211 | roles[YearRole] = QByteArrayLiteral("year" ); |
212 | return roles; |
213 | } |
214 | |
215 | void QQuickCalendarModel::classBegin() |
216 | { |
217 | } |
218 | |
219 | void QQuickCalendarModel::componentComplete() |
220 | { |
221 | Q_D(QQuickCalendarModel); |
222 | d->complete = true; |
223 | d->populate(f: d->from, t: d->to, force: true); |
224 | } |
225 | |
226 | QT_END_NAMESPACE |
227 | |
228 | #include "moc_qquickcalendarmodel_p.cpp" |
229 | |