1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2017 The Qt Company Ltd. |
4 | ** Contact: http://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt Labs Calendar module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL3$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see http://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at http://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or later as published by the Free |
28 | ** Software Foundation and appearing in the file LICENSE.GPL included in |
29 | ** the packaging of this file. Please review the following information to |
30 | ** ensure the GNU General Public License version 2.0 requirements will be |
31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. |
32 | ** |
33 | ** $QT_END_LICENSE$ |
34 | ** |
35 | ****************************************************************************/ |
36 | |
37 | #include "qquickmonthmodel_p.h" |
38 | |
39 | #include <QtCore/private/qabstractitemmodel_p.h> |
40 | |
41 | namespace { |
42 | static const int daysInAWeek = 7; |
43 | static const int weeksOnACalendarMonth = 6; |
44 | static const int daysOnACalendarMonth = daysInAWeek * weeksOnACalendarMonth; |
45 | } |
46 | |
47 | QT_BEGIN_NAMESPACE |
48 | |
49 | class QQuickMonthModelPrivate : public QAbstractItemModelPrivate |
50 | { |
51 | Q_DECLARE_PUBLIC(QQuickMonthModel) |
52 | |
53 | public: |
54 | QQuickMonthModelPrivate() : dates(daysOnACalendarMonth) |
55 | { |
56 | today = QDate::currentDate(); |
57 | month = today.month(); |
58 | year = today.year(); |
59 | } |
60 | |
61 | bool populate(int month, int year, const QLocale &locale, bool force = false); |
62 | |
63 | int month; |
64 | int year; |
65 | QString title; |
66 | QLocale locale; |
67 | QVector<QDate> dates; |
68 | QDate today; |
69 | }; |
70 | |
71 | bool QQuickMonthModelPrivate::populate(int m, int y, const QLocale &l, bool force) |
72 | { |
73 | Q_Q(QQuickMonthModel); |
74 | if (!force && m == month && y == year && l.firstDayOfWeek() == locale.firstDayOfWeek()) |
75 | return false; |
76 | |
77 | // The actual first (1st) day of the month. |
78 | QDate firstDayOfMonthDate(y, m, 1); |
79 | int difference = ((firstDayOfMonthDate.dayOfWeek() - l.firstDayOfWeek()) + 7) % 7; |
80 | // The first day to display should never be the 1st of the month, as we want some days from |
81 | // the previous month to be visible. |
82 | if (difference == 0) |
83 | difference += 7; |
84 | QDate firstDateToDisplay = firstDayOfMonthDate.addDays(days: -difference); |
85 | |
86 | today = QDate::currentDate(); |
87 | for (int i = 0; i < daysOnACalendarMonth; ++i) |
88 | dates[i] = firstDateToDisplay.addDays(days: i); |
89 | |
90 | q->setTitle(l.standaloneMonthName(m) + QStringLiteral(" " ) + QString::number(y)); |
91 | |
92 | return true; |
93 | } |
94 | |
95 | QQuickMonthModel::QQuickMonthModel(QObject *parent) : |
96 | QAbstractListModel(*(new QQuickMonthModelPrivate), parent) |
97 | { |
98 | Q_D(QQuickMonthModel); |
99 | d->populate(m: d->month, y: d->year, l: d->locale, force: true); |
100 | } |
101 | |
102 | int QQuickMonthModel::month() const |
103 | { |
104 | Q_D(const QQuickMonthModel); |
105 | return d->month; |
106 | } |
107 | |
108 | void QQuickMonthModel::setMonth(int month) |
109 | { |
110 | Q_D(QQuickMonthModel); |
111 | if (d->month != month) { |
112 | if (d->populate(m: month, y: d->year, l: d->locale)) |
113 | emit dataChanged(topLeft: index(row: 0, column: 0), bottomRight: index(row: daysOnACalendarMonth - 1, column: 0)); |
114 | d->month = month; |
115 | emit monthChanged(); |
116 | } |
117 | } |
118 | |
119 | int QQuickMonthModel::year() const |
120 | { |
121 | Q_D(const QQuickMonthModel); |
122 | return d->year; |
123 | } |
124 | |
125 | void QQuickMonthModel::setYear(int year) |
126 | { |
127 | Q_D(QQuickMonthModel); |
128 | if (d->year != year) { |
129 | if (d->populate(m: d->month, y: year, l: d->locale)) |
130 | emit dataChanged(topLeft: index(row: 0, column: 0), bottomRight: index(row: daysOnACalendarMonth - 1, column: 0)); |
131 | d->year = year; |
132 | emit yearChanged(); |
133 | } |
134 | } |
135 | |
136 | QLocale QQuickMonthModel::locale() const |
137 | { |
138 | Q_D(const QQuickMonthModel); |
139 | return d->locale; |
140 | } |
141 | |
142 | void QQuickMonthModel::setLocale(const QLocale &locale) |
143 | { |
144 | Q_D(QQuickMonthModel); |
145 | if (d->locale != locale) { |
146 | if (d->populate(m: d->month, y: d->year, l: locale)) |
147 | emit dataChanged(topLeft: index(row: 0, column: 0), bottomRight: index(row: daysOnACalendarMonth - 1, column: 0)); |
148 | d->locale = locale; |
149 | emit localeChanged(); |
150 | } |
151 | } |
152 | |
153 | QString QQuickMonthModel::title() const |
154 | { |
155 | Q_D(const QQuickMonthModel); |
156 | return d->title; |
157 | } |
158 | |
159 | void QQuickMonthModel::setTitle(const QString &title) |
160 | { |
161 | Q_D(QQuickMonthModel); |
162 | if (d->title != title) { |
163 | d->title = title; |
164 | emit titleChanged(); |
165 | } |
166 | } |
167 | |
168 | QDate QQuickMonthModel::dateAt(int index) const |
169 | { |
170 | Q_D(const QQuickMonthModel); |
171 | return d->dates.value(i: index); |
172 | } |
173 | |
174 | int QQuickMonthModel::indexOf(const QDate &date) const |
175 | { |
176 | Q_D(const QQuickMonthModel); |
177 | if (date < d->dates.first() || date > d->dates.last()) |
178 | return -1; |
179 | return qMax(a: qint64(0), b: d->dates.first().daysTo(date)); |
180 | } |
181 | |
182 | QVariant QQuickMonthModel::data(const QModelIndex &index, int role) const |
183 | { |
184 | Q_D(const QQuickMonthModel); |
185 | if (index.isValid() && index.row() < daysOnACalendarMonth) { |
186 | const QDate date = d->dates.at(i: index.row()); |
187 | switch (role) { |
188 | case DateRole: |
189 | return date; |
190 | case DayRole: |
191 | return date.day(); |
192 | case TodayRole: |
193 | return date == d->today; |
194 | case WeekNumberRole: |
195 | return date.weekNumber(); |
196 | case MonthRole: |
197 | return date.month() - 1; |
198 | case YearRole: |
199 | return date.year(); |
200 | default: |
201 | break; |
202 | } |
203 | } |
204 | return QVariant(); |
205 | } |
206 | |
207 | int QQuickMonthModel::rowCount(const QModelIndex &parent) const |
208 | { |
209 | if (parent.isValid()) |
210 | return 0; |
211 | return daysOnACalendarMonth; |
212 | } |
213 | |
214 | QHash<int, QByteArray> QQuickMonthModel::roleNames() const |
215 | { |
216 | QHash<int, QByteArray> roles; |
217 | roles[DateRole] = QByteArrayLiteral("date" ); |
218 | roles[DayRole] = QByteArrayLiteral("day" ); |
219 | roles[TodayRole] = QByteArrayLiteral("today" ); |
220 | roles[WeekNumberRole] = QByteArrayLiteral("weekNumber" ); |
221 | roles[MonthRole] = QByteArrayLiteral("month" ); |
222 | roles[YearRole] = QByteArrayLiteral("year" ); |
223 | return roles; |
224 | } |
225 | |
226 | QT_END_NAMESPACE |
227 | |