Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquickmonthgrid.cpp
Go to the documentation of this file.
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// Qt-Security score:significant reason:default
6
7#include <QtGui/qstylehints.h>
8#include <QtGui/qguiapplication.h>
9#include <QtQuickTemplates2/private/qquickcontrol_p_p.h>
10#include <QtQml/qqmlinfo.h>
11
13
14/*!
15 \qmltype MonthGrid
16 \inherits Control
17//! \nativetype QQuickMonthGrid
18 \inqmlmodule QtQuick.Controls
19 \brief A grid of days for a calendar month.
20
21 MonthGrid presents a calendar month in a grid. The contents are
22 calculated for a given \l month and \l year, using the specified
23 \l {Control::locale}{locale}.
24
25 \image qtquickcontrols-monthgrid.webp
26 \snippet qtquickcontrols-monthgrid.qml 1
27
28 MonthGrid can be used as a standalone control, but it is most often
29 used in conjunction with DayOfWeekRow and WeekNumberColumn. Regardless
30 of the use case, positioning of the grid is left to the user.
31
32 \image qtquickcontrols-monthgrid-layout.webp
33 \snippet qtquickcontrols-monthgrid-layout.qml 1
34
35 The visual appearance of MonthGrid can be changed by
36 implementing a \l {delegate}{custom delegate}.
37
38 When viewing any given month, MonthGrid shows days from the previous and
39 next month. This means it always shows six rows, even when first or last
40 row is entirely within an adjacent month.
41
42 \section1 Localizing days
43
44 To localize days, use \l {Locale::toString()}{Locale.toString()}.
45 For example, to display day numbers in an Arabic locale:
46
47 \snippet qtquickcontrols-monthgrid-localization.qml 1
48
49 \sa DayOfWeekRow, WeekNumberColumn, CalendarModel,
50 {Qt Quick Controls - Event Calendar}
51*/
52
53/*!
54 \qmlsignal QtQuick.Controls::MonthGrid::pressed(date date)
55
56 This signal is emitted when \a date is pressed.
57*/
58
59/*!
60 \qmlsignal QtQuick.Controls::MonthGrid::released(date date)
61
62 This signal is emitted when \a date is released.
63*/
64
65/*!
66 \qmlsignal QtQuick.Controls::MonthGrid::clicked(date date)
67
68 This signal is emitted when \a date is clicked.
69*/
70
71/*!
72 \qmlsignal QtQuick.Controls::MonthGrid::pressAndHold(date date)
73
74 This signal is emitted when \a date is pressed and held down.
75*/
76
78{
79 Q_DECLARE_PUBLIC(QQuickMonthGrid)
80
81public:
82 QQuickMonthGridPrivate() : pressTimer(0), pressedItem(nullptr), model(nullptr), delegate(nullptr) { }
83
85
86 QQuickItem *cellAt(const QPointF &pos) const;
87 QDateTime dateOf(QQuickItem *cell) const;
88
89 void updatePress(const QPointF &pos);
90 void clearPress(bool clicked);
91
92 bool handlePress(const QPointF &point, ulong timestamp) override;
93 bool handleMove(const QPointF &point, ulong timestamp) override;
94 bool handleRelease(const QPointF &point, ulong timestamp) override;
96
99
100 // Only the date matters, but we have to store it as QDateTime for compatibility
101 // with Date: QTBUG-72208. See QQuickMonthModelPrivate::populate for more info.
106 QQmlComponent *delegate;
107};
108
109void QQuickMonthGridPrivate::resizeItems()
110{
111 if (!contentItem)
112 return;
113
114 QSizeF itemSize;
115 itemSize.setWidth((contentItem->width() - 6 * spacing) / 7);
116 itemSize.setHeight((contentItem->height() - 5 * spacing) / 6);
117
118 const auto childItems = contentItem->childItems();
119 for (QQuickItem *item : childItems) {
120 if (!QQuickItemPrivate::get(item)->isTransparentForPositioner())
121 item->setSize(itemSize);
122 }
123}
124
125QQuickItem *QQuickMonthGridPrivate::cellAt(const QPointF &pos) const
126{
127 Q_Q(const QQuickMonthGrid);
128 if (contentItem) {
129 QPointF mapped = q->mapToItem(contentItem, pos);
130 return contentItem->childAt(mapped.x(), mapped.y());
131 }
132 return nullptr;
133}
134
136{
137 if (contentItem)
138 return model->dateAt(contentItem->childItems().indexOf(cell));
139 return {};
140}
141
142void QQuickMonthGridPrivate::updatePress(const QPointF &pos)
143{
144 Q_Q(QQuickMonthGrid);
145 clearPress(false);
146 pressedItem = cellAt(pos);
147 pressedDate = dateOf(pressedItem);
148 if (pressedDate.isValid())
149 emit q->pressed(pressedDate);
150}
151
153{
154 Q_Q(QQuickMonthGrid);
155 if (pressedDate.isValid()) {
156 emit q->released(pressedDate);
157 if (clicked)
158 emit q->clicked(pressedDate);
159 }
160 pressedDate = {};
161 pressedItem = nullptr;
162}
163
164bool QQuickMonthGridPrivate::handlePress(const QPointF &point, ulong timestamp)
165{
166 Q_Q(QQuickMonthGrid);
167 QQuickControlPrivate::handlePress(point, timestamp);
168 updatePress(point);
169 if (pressedDate.isValid())
170 pressTimer = q->startTimer(qGuiApp->styleHints()->mousePressAndHoldInterval());
171 return true;
172}
173
174bool QQuickMonthGridPrivate::handleMove(const QPointF &point, ulong timestamp)
175{
176 QQuickControlPrivate::handleMove(point, timestamp);
177 updatePress(point);
178 return true;
179}
180
181bool QQuickMonthGridPrivate::handleRelease(const QPointF &point, ulong timestamp)
182{
183 QQuickControlPrivate::handleRelease(point, timestamp);
184 clearPress(true);
185 return true;
186}
187
189{
190 QQuickControlPrivate::handleUngrab();
191 clearPress(false);
192}
193
194QQuickMonthGrid::QQuickMonthGrid(QQuickItem *parent) :
195 QQuickControl(*(new QQuickMonthGridPrivate), parent)
196{
197 Q_D(QQuickMonthGrid);
198 setFlag(ItemIsFocusScope);
199 setActiveFocusOnTab(true);
200 setAcceptedMouseButtons(Qt::LeftButton);
201#if QT_CONFIG(cursor)
202 setCursor(Qt::ArrowCursor);
203#endif
204
205 d->model = new QQuickMonthModel(this);
206 d->source = QVariant::fromValue(d->model);
207 connect(d->model, &QQuickMonthModel::monthChanged, this, &QQuickMonthGrid::monthChanged);
208 connect(d->model, &QQuickMonthModel::yearChanged, this, &QQuickMonthGrid::yearChanged);
209 connect(d->model, &QQuickMonthModel::titleChanged, this, &QQuickMonthGrid::titleChanged);
210}
211
212/*!
213 \qmlproperty int QtQuick.Controls::MonthGrid::month
214
215 This property holds the number of the month. The default value is the
216 current month.
217
218 \include zero-based-months.qdocinc
219
220 \sa Calendar
221*/
223{
224 Q_D(const QQuickMonthGrid);
225 return d->model->month() - 1;
226}
227
228void QQuickMonthGrid::setMonth(int month)
229{
230 Q_D(QQuickMonthGrid);
231 if (month < 0 || month > 11) {
232 qmlWarning(this) << "month " << month << " is out of range [0...11]";
233 return;
234 }
235 d->model->setMonth(month + 1);
236}
237
238/*!
239 \qmlproperty int QtQuick.Controls::MonthGrid::year
240
241 This property holds the number of the year.
242
243 The value must be in the range from \c -271820 to \c 275759. The default
244 value is the current year.
245*/
247{
248 Q_D(const QQuickMonthGrid);
249 return d->model->year();
250}
251
253{
254 Q_D(QQuickMonthGrid);
255 if (year < -271820 || year > 275759) {
256 qmlWarning(this) << "year " << year << " is out of range [-271820...275759]";
257 return;
258 }
259 d->model->setYear(year);
260}
261
262/*!
263 \internal
264 \qmlproperty model QtQuick.Controls::MonthGrid::source
265
266 This property holds the source model that is used as a data model
267 for the internal content column.
268*/
270{
271 Q_D(const QQuickMonthGrid);
272 return d->source;
273}
274
275void QQuickMonthGrid::setSource(const QVariant &source)
276{
277 Q_D(QQuickMonthGrid);
278 if (d->source != source) {
279 d->source = source;
280 emit sourceChanged();
281 }
282}
283
284/*!
285 \qmlproperty string QtQuick.Controls::MonthGrid::title
286
287 This property holds a title for the calendar.
288
289 This property is provided for convenience. MonthGrid itself does
290 not visualize the title. The default value consists of the month name,
291 formatted using \l {Control::locale}{locale}, and the year number.
292*/
294{
295 Q_D(const QQuickMonthGrid);
296 if (d->title.isNull())
297 return d->model->title();
298 return d->title;
299}
300
301void QQuickMonthGrid::setTitle(const QString &title)
302{
303 Q_D(QQuickMonthGrid);
304 if (d->title != title) {
305 d->title = title;
306 emit titleChanged();
307 }
308}
309
310/*!
311 \qmlproperty Component QtQuick.Controls::MonthGrid::delegate
312
313 This property holds the item delegate that visualizes each day.
314
315 In addition to the \c index property, a list of model data roles
316 are available in the context of each delegate:
317 \table
318 \row \li \b model.date : date \li The date of the cell
319 \row \li \b model.day : int \li The number of the day
320 \row \li \b model.today : bool \li Whether the delegate represents today
321 \row \li \b model.weekNumber : int \li The week number
322 \row \li \b model.month : int \li The number of the month
323 \row \li \b model.year : int \li The number of the year
324 \endtable
325
326 The following snippet presents the default implementation of the item
327 delegate. It can be used as a starting point for implementing custom
328 delegates.
329
330 \include delegate-ownership.qdocinc {no-ownership} {MonthGrid}
331
332 \snippet basic/MonthGrid.qml delegate
333*/
334QQmlComponent *QQuickMonthGrid::delegate() const
335{
336 Q_D(const QQuickMonthGrid);
337 return d->delegate;
338}
339
340void QQuickMonthGrid::setDelegate(QQmlComponent *delegate)
341{
342 Q_D(QQuickMonthGrid);
343 if (d->delegate != delegate) {
344 d->delegate = delegate;
345 emit delegateChanged();
346 }
347}
348
350{
351 Q_D(QQuickMonthGrid);
352 QQuickControl::componentComplete();
353 d->resizeItems();
354}
355
356void QQuickMonthGrid::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
357{
358 Q_D(QQuickMonthGrid);
359 QQuickControl::geometryChange(newGeometry, oldGeometry);
360 if (isComponentComplete())
361 d->resizeItems();
362}
363
364void QQuickMonthGrid::localeChange(const QLocale &newLocale, const QLocale &oldLocale)
365{
366 Q_D(QQuickMonthGrid);
367 QQuickControl::localeChange(newLocale, oldLocale);
368 d->model->setLocale(newLocale);
369}
370
371void QQuickMonthGrid::paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding)
372{
373 Q_D(QQuickMonthGrid);
374 QQuickControl::paddingChange(newPadding, oldPadding);
375 if (isComponentComplete())
376 d->resizeItems();
377}
378
380{
381 Q_D(QQuickMonthGrid);
382 QQuickControl::updatePolish();
383 d->resizeItems();
384}
385
386void QQuickMonthGrid::timerEvent(QTimerEvent *event)
387{
388 Q_D(QQuickMonthGrid);
389 if (event->timerId() == d->pressTimer) {
390 if (d->pressedDate.isValid())
391 emit pressAndHold(d->pressedDate);
392 killTimer(d->pressTimer);
393 }
394}
395
396QT_END_NAMESPACE
397
398#include "moc_qquickmonthgrid_p.cpp"
A grid of days for a calendar month.
bool handleRelease(const QPointF &point, ulong timestamp) override
bool handlePress(const QPointF &point, ulong timestamp) override
QQuickMonthModel * model
QQuickItem * cellAt(const QPointF &pos) const
QDateTime dateOf(QQuickItem *cell) const
bool handleMove(const QPointF &point, ulong timestamp) override
void clearPress(bool clicked)
void updatePress(const QPointF &pos)
void paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding) override
void localeChange(const QLocale &newLocale, const QLocale &oldLocale) override
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
int month() const
\qmlproperty int QtQuick.Controls::MonthGrid::month
void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override
void setTitle(const QString &title)
void timerEvent(QTimerEvent *event) override
This event handler can be reimplemented in a subclass to receive timer events for the object.
QQmlComponent * delegate() const
\qmlproperty Component QtQuick.Controls::MonthGrid::delegate
void setSource(const QVariant &source)
void setDelegate(QQmlComponent *delegate)
QString title() const
\qmlproperty string QtQuick.Controls::MonthGrid::title
void setMonth(int month)
void updatePolish() override
This function should perform any layout as required for this item.
QVariant source() const
void setYear(int year)
int year() const
\qmlproperty int QtQuick.Controls::MonthGrid::year