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
8QT_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
35class QQuickCalendarModelPrivate : public QAbstractItemModelPrivate
36{
37 Q_DECLARE_PUBLIC(QQuickCalendarModel)
38
39public:
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.
57int 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
74void 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
91QQuickCalendarModel::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*/
101QDate QQuickCalendarModel::from() const
102{
103 Q_D(const QQuickCalendarModel);
104 return d->from;
105}
106
107void 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*/
123QDate QQuickCalendarModel::to() const
124{
125 Q_D(const QQuickCalendarModel);
126 return d->to;
127}
128
129void 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*/
145int 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*/
156int 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*/
167int 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*/
178int QQuickCalendarModel::indexOf(int year, int month) const
179{
180 return indexOf(date: QDate(year, month + 1, 1));
181}
182
183QVariant 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
199int 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
207QHash<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
215void QQuickCalendarModel::classBegin()
216{
217}
218
219void QQuickCalendarModel::componentComplete()
220{
221 Q_D(QQuickCalendarModel);
222 d->complete = true;
223 d->populate(f: d->from, t: d->to, force: true);
224}
225
226QT_END_NAMESPACE
227
228#include "moc_qquickcalendarmodel_p.cpp"
229

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