diff options
author | Mitch Curtis <mitch.curtis@digia.com> | 2013-07-15 22:57:52 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-02-14 13:13:53 +0100 |
commit | e023dd212c81a2ad4ba4b4db22df9cde65a502e8 (patch) | |
tree | 2c3521e8a4154d65a55fc3032254b58b181d957e /src/controls/Private | |
parent | e88bdffe644e53912dfbce95117555cb6a87bfd2 (diff) | |
download | qtquickcontrols-e023dd212c81a2ad4ba4b4db22df9cde65a502e8.tar.gz |
Add Calendar to Qt Quick Controls.
Task-number: QTBUG-29948
[ChangeLog][QtQuickControls] Calendar was added. Calendar allows
selection of dates from a grid of days, similar to
QCalendarWidget.
Change-Id: I279130e704bc0dfd8dfe114ec9b6b49e111faf96
Reviewed-by: Jens Bache-Wiig <jens.bache-wiig@digia.com>
Diffstat (limited to 'src/controls/Private')
-rw-r--r-- | src/controls/Private/CalendarHeaderModel.qml | 84 | ||||
-rw-r--r-- | src/controls/Private/CalendarUtils.js | 132 | ||||
-rw-r--r-- | src/controls/Private/private.pri | 6 | ||||
-rw-r--r-- | src/controls/Private/qmldir | 2 | ||||
-rw-r--r-- | src/controls/Private/qquickcalendarmodel.cpp | 264 | ||||
-rw-r--r-- | src/controls/Private/qquickcalendarmodel_p.h | 101 | ||||
-rw-r--r-- | src/controls/Private/qquickrangeddate.cpp | 115 | ||||
-rw-r--r-- | src/controls/Private/qquickrangeddate_p.h | 88 |
8 files changed, 792 insertions, 0 deletions
diff --git a/src/controls/Private/CalendarHeaderModel.qml b/src/controls/Private/CalendarHeaderModel.qml new file mode 100644 index 00000000..ef57e65b --- /dev/null +++ b/src/controls/Private/CalendarHeaderModel.qml @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 + +/* + CalendarHeaderModel contains a list of the days of a week, + according to a \l locale. The \l locale affects which day of the week + is first in the model. + + The only role provided by the model is \c dayOfWeek, which is one of the + following JavaScript values: + + \list + \li \c Locale.Sunday + \li \c Locale.Monday + \li \c Locale.Tuesday + \li \c Locale.Wednesday + \li \c Locale.Thursday + \li \c Locale.Friday + \li \c Locale.Saturday + \endlist + */ + +ListModel { + id: root + + /* + The locale that this model should be based on. + This affects which day of the week is first in the model. + */ + property var locale + + Component.onCompleted: { + var daysOfWeek = [Locale.Sunday, Locale.Monday, Locale.Tuesday, + Locale.Wednesday, Locale.Thursday, Locale.Friday, Locale.Saturday]; + var firstDayOfWeek = root.locale.firstDayOfWeek; + + var shifted = daysOfWeek.splice(firstDayOfWeek, daysOfWeek.length - firstDayOfWeek); + daysOfWeek = shifted.concat(daysOfWeek) + + for (var i = 0; i < daysOfWeek.length; ++i) { + var element = { dayOfWeek: daysOfWeek[i] } + root.append(element); + } + } +} diff --git a/src/controls/Private/CalendarUtils.js b/src/controls/Private/CalendarUtils.js new file mode 100644 index 00000000..c055118e --- /dev/null +++ b/src/controls/Private/CalendarUtils.js @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +.pragma library + +var daysInAWeek = 7; +var monthsInAYear = 12; + +// Not the number of weeks per month, but the number of weeks that are +// shown on a typical calendar. +var weeksOnACalendarMonth = 6; + +// Can't create year 1 directly... +var minimumCalendarDate = new Date(-1, 0, 1); +minimumCalendarDate.setFullYear(minimumCalendarDate.getFullYear() + 2); +var maximumCalendarDate = new Date(275759, 9, 25); + +function daysInMonth(date) { + // Passing 0 as the day will give us the previous month, which will be + // date.getMonth() since we added 1 to it. + return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate(); +} + +/*! + Returns a copy of \a date with its month set to \a month, keeping the same + day if possible. Does not modify \a date. +*/ +function setMonth(date, month) { + var oldDay = date.getDate(); + var newDate = new Date(date); + // Set the day first, because setting the month could cause it to skip ahead + // a month if the day is larger than the latest day in that month. + newDate.setDate(1); + newDate.setMonth(month); + // We'd like to have the previous day still selected when we change + // months, but it might not be possible, so use the smallest of the two. + newDate.setDate(Math.min(oldDay, daysInMonth(newDate))); + return newDate; +} + +function cellRectAt(index, columns, rows, availableWidth, availableHeight) { + var col = Math.floor(index % columns); + var row = Math.floor(index / columns); + + var remainingHorizontalSpace = Math.floor(availableWidth % columns); + var remainingVerticalSpace = Math.floor(availableHeight % rows); + var baseCellWidth = Math.floor(availableWidth / columns); + var baseCellHeight = Math.floor(availableHeight / rows); + + var rect = Qt.rect(0, 0, 0, 0); + + rect.x = baseCellWidth * col; + rect.width = baseCellWidth; + if (remainingHorizontalSpace > 0) { + if (col < remainingHorizontalSpace) { + ++rect.width; + } + + // This cell's x position should be increased by 1 for every column above it. + rect.x += Math.min(remainingHorizontalSpace, col); + } + + rect.y = baseCellHeight * row; + rect.height = baseCellHeight; + if (remainingVerticalSpace > 0) { + if (row < remainingVerticalSpace) { + ++rect.height; + } + + // This cell's y position should be increased by 1 for every row above it. + rect.y += Math.min(remainingVerticalSpace, row); + } + + return rect; +} + +function cellIndexAt(x, y, columns, rows, availableWidth, availableHeight) { + var remainingHorizontalSpace = Math.floor(availableWidth % columns); + var remainingVerticalSpace = Math.floor(availableHeight % rows); + var baseCellWidth = Math.floor(availableWidth / columns); + var baseCellHeight = Math.floor(availableHeight / rows); + + // TODO: improve this. + for (var row = 0; row < rows; ++row) { + for (var col = 0; col < columns; ++col) { + var index = row * columns + col; + var rect = cellRectAt(index, columns, rows, availableWidth, availableHeight); + if (x >= rect.x && x < rect.x + rect.width && y >= rect.y && y < rect.y + rect.height) { + return index; + } + } + } + + return -1; +} diff --git a/src/controls/Private/private.pri b/src/controls/Private/private.pri index b12cabd7..49227c9d 100644 --- a/src/controls/Private/private.pri +++ b/src/controls/Private/private.pri @@ -1,8 +1,10 @@ HEADERS += \ + $$PWD/qquickcalendarmodel_p.h \ $$PWD/qquicktooltip_p.h \ $$PWD/qquickspinboxvalidator_p.h \ $$PWD/qquickrangemodel_p.h \ $$PWD/qquickrangemodel_p_p.h \ + $$PWD/qquickrangeddate_p.h \ $$PWD/qquickcontrolsettings_p.h \ $$PWD/qquickwheelarea_p.h \ $$PWD/qquickabstractstyle_p.h \ @@ -10,9 +12,11 @@ HEADERS += \ $$PWD/qquickcontrolsprivate_p.h SOURCES += \ + $$PWD/qquickcalendarmodel.cpp \ $$PWD/qquicktooltip.cpp \ $$PWD/qquickspinboxvalidator.cpp \ $$PWD/qquickrangemodel.cpp \ + $$PWD/qquickrangeddate.cpp \ $$PWD/qquickcontrolsettings.cpp \ $$PWD/qquickwheelarea.cpp \ $$PWD/qquickabstractstyle.cpp @@ -30,6 +34,8 @@ PRIVATE_QML_FILES += \ $$PWD/TabBar.qml \ $$PWD/BasicButton.qml \ $$PWD/Control.qml \ + $$PWD/CalendarHeaderModel.qml \ + $$PWD/CalendarUtils.js \ $$PWD/FastGlow.qml \ $$PWD/SourceProxy.qml\ $$PWD/Style.qml \ diff --git a/src/controls/Private/qmldir b/src/controls/Private/qmldir index 7536b7e6..99740190 100644 --- a/src/controls/Private/qmldir +++ b/src/controls/Private/qmldir @@ -1,6 +1,8 @@ module QtQuick.Controls.Private AbstractCheckable 1.0 AbstractCheckable.qml +CalendarHeaderModel 1.0 CalendarHeaderModel.qml Control 1.0 Control.qml +CalendarUtils 1.0 CalendarUtils.js FocusFrame 1.0 FocusFrame.qml Margins 1.0 Margins.qml BasicButton 1.0 BasicButton.qml diff --git a/src/controls/Private/qquickcalendarmodel.cpp b/src/controls/Private/qquickcalendarmodel.cpp new file mode 100644 index 00000000..83c2885c --- /dev/null +++ b/src/controls/Private/qquickcalendarmodel.cpp @@ -0,0 +1,264 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickcalendarmodel_p.h" + +namespace { + static const int daysInAWeek = 7; + + /* + Not the number of weeks per month, but the number of weeks that are + shown on a typical calendar. + */ + static const int weeksOnACalendarMonth = 6; + + /* + The amount of days to populate the calendar with. + */ + static const int daysOnACalendarMonth = daysInAWeek * weeksOnACalendarMonth; +} + +QT_BEGIN_NAMESPACE + +/*! + QQuickCalendarModel provides a model for the Calendar control. + It is responsible for populating itself with dates based on a given month + and year. + + The model stores a list of dates whose indices map directly to the Calendar. + For example, the model would store the following dates when any day in + January 2015 is selected on the Calendar: + + [30/12/2014][31/12/2014][01/01/2015]...[31/01/2015][01/02/2015]...[09/02/2015] + + The Calendar would then display the dates in the same order within a grid: + + January 2015 + + [30][31][01][02][03][04][05] + [06][07][08][09][10][11][12] + [13][14][15][16][17][18][19] + [20][21][22][23][24][25][26] + [27][28][29][30][31][01][02] + [03][04][05][06][07][08][09] +*/ + +QQuickCalendarModel::QQuickCalendarModel(QObject *parent) : + QAbstractListModel(parent) +{ +} + +/*! + The date that determines which dates are stored. + + We store all of the days in the month of visibleDate, as well as any days + in the previous or following month if there is enough space. +*/ +QDate QQuickCalendarModel::visibleDate() const +{ + return mVisibleDate; +} + +/*! + Sets the visible date to \a visibleDate. + + If \a visibleDate is a valid date and is different than the previously + visible date, the visible date is changed and + populateFromVisibleDate() called. +*/ +void QQuickCalendarModel::setVisibleDate(const QDate &date) +{ + if (date != mVisibleDate && date.isValid()) { + const QDate previousDate = mVisibleDate; + mVisibleDate = date; + populateFromVisibleDate(previousDate); + emit visibleDateChanged(date); + } +} + +/*! + The locale set on the Calendar. + + This affects which dates are stored for visibleDate(). For example, if + the locale is en_US, the first day of the week is Sunday. Therefore, if + visibleDate() is some day in January 2014, there will be three days + displayed before the 1st of January: + + + January 2014 + + [SO][MO][TU][WE][TH][FR][SA] + [29][30][31][01][02][03][04] + ... + + If the locale is then changed to en_GB (with the same visibleDate()), + there will be 2 days before the 1st of January, because Monday is the + first day of the week for that locale: + + January 2014 + + [MO][TU][WE][TH][FR][SA][SO] + [30][31][01][02][03][04][05] + ... +*/ +QLocale QQuickCalendarModel::locale() const +{ + return mLocale; +} + +/*! + Sets the locale to \a locale. +*/ +void QQuickCalendarModel::setLocale(const QLocale &locale) +{ + if (locale != mLocale) { + Qt::DayOfWeek previousFirstDayOfWeek = mLocale.firstDayOfWeek(); + mLocale = locale; + emit localeChanged(mLocale); + if (mLocale.firstDayOfWeek() != previousFirstDayOfWeek) { + // We don't have a previousDate, so just use our current one... + // it's ignored anyway, since we're forcing the repopulation. + populateFromVisibleDate(mVisibleDate, true); + } + } +} + +QVariant QQuickCalendarModel::data(const QModelIndex &index, int role) const +{ + if (role == DateRole) + return mVisibleDates.at(index.row()); + return QVariant(); +} + +int QQuickCalendarModel::rowCount(const QModelIndex &) const +{ + return mVisibleDates.isEmpty() ? 0 : weeksOnACalendarMonth * daysInAWeek; +} + +QHash<int, QByteArray> QQuickCalendarModel::roleNames() const +{ + QHash<int, QByteArray> names; + names[DateRole] = QByteArrayLiteral("date"); + return names; +} + +/*! + Returns the date at \a index, or an invalid date if \a index is invalid. +*/ +QDate QQuickCalendarModel::dateAt(int index) const +{ + return index >= 0 && index < mVisibleDates.size() ? mVisibleDates.at(index) : QDate(); +} + +/*! + Returns the index for \a date, or -1 if \a date is outside of our range. +*/ +int QQuickCalendarModel::indexAt(const QDate &date) +{ + if (mVisibleDates.size() == 0 || date < mFirstVisibleDate || date > mLastVisibleDate) + return -1; + + // The index of the visible date will be the days from the + // previous month that we had to display before it, plus the + // day of the visible date itself. + return qMax(qint64(0), mFirstVisibleDate.daysTo(date)); +} + +/*! + Returns the week number for the first day of the week corresponding to \a row, + or -1 if \a row is outside of our range. +*/ +int QQuickCalendarModel::weekNumberAt(int row) const +{ + const int index = row * daysInAWeek; + const QDate date = dateAt(index); + if (date.isValid()) + return date.weekNumber(); + return -1; +} + +/*! + Called before visibleDateChanged() is emitted. + + This function is called even when just the day has changed, in which case + it does nothing. + + The \a force parameter is used when the locale has changed; the month + shown doesn't change, but the days displayed do. + The \a previousDate parameter is ignored when \a force is true. +*/ +void QQuickCalendarModel::populateFromVisibleDate(const QDate &previousDate, bool force) +{ + // We don't need to populate if the year and month haven't changed. + if (!force && mVisibleDate.year() == previousDate.year() && mVisibleDate.month() == previousDate.month()) + return; + + // Since our model is of a fixed size, we fill it once and assign values each time + // the month changes, instead of clearing and appending each time. + bool isEmpty = mVisibleDates.isEmpty(); + if (isEmpty) { + beginResetModel(); + mVisibleDates.fill(QDate(), daysOnACalendarMonth); + } + + // The actual first (1st) day of the month. + QDate firstDayOfMonthDate(mVisibleDate.year(), mVisibleDate.month(), 1); + int difference = ((firstDayOfMonthDate.dayOfWeek() - mLocale.firstDayOfWeek()) + 7) % 7; + // The first day to display should never be the 1st of the month, as we want some days from + // the previous month to be visible. + if (difference == 0) + difference += daysInAWeek; + QDate firstDateToDisplay = firstDayOfMonthDate.addDays(-difference); + for (int i = 0; i < daysOnACalendarMonth; ++i) + mVisibleDates[i] = firstDateToDisplay.addDays(i); + + mFirstVisibleDate = mVisibleDates.at(0); + mLastVisibleDate = mVisibleDates.at(mVisibleDates.size() - 1); + + if (!isEmpty) { + emit dataChanged(index(0, 0), index(rowCount() - 1, 0)); + } else { + endResetModel(); + emit countChanged(rowCount()); + } +} + +QT_END_NAMESPACE diff --git a/src/controls/Private/qquickcalendarmodel_p.h b/src/controls/Private/qquickcalendarmodel_p.h new file mode 100644 index 00000000..3505f3a4 --- /dev/null +++ b/src/controls/Private/qquickcalendarmodel_p.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKCALENDARMODEL_H +#define QQUICKCALENDARMODEL_H + +#include <QObject> +#include <QAbstractListModel> +#include <QLocale> +#include <QVariant> +#include <QDate> + +QT_BEGIN_NAMESPACE + +class QQuickCalendarModel : public QAbstractListModel +{ + Q_OBJECT + Q_PROPERTY(QDate visibleDate READ visibleDate WRITE setVisibleDate NOTIFY visibleDateChanged) + Q_PROPERTY(QLocale locale READ locale WRITE setLocale NOTIFY localeChanged) + Q_PROPERTY(int count READ rowCount NOTIFY countChanged) + +public: + explicit QQuickCalendarModel(QObject *parent = 0); + + enum { + // If this class is made public, this will have to be changed. + DateRole = Qt::UserRole + 1 + }; + + QDate visibleDate() const; + void setVisibleDate(const QDate &visibleDate); + + QLocale locale() const; + void setLocale(const QLocale &locale); + + QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; + + int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + + QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE; + + Q_INVOKABLE QDate dateAt(int index) const; + Q_INVOKABLE int indexAt(const QDate &visibleDate); + Q_INVOKABLE int weekNumberAt(int row) const; + +Q_SIGNALS: + void visibleDateChanged(const QDate &visibleDate); + void localeChanged(const QLocale &locale); + void countChanged(int count); + +protected: + void populateFromVisibleDate(const QDate &previousDate, bool force = false); + + QDate mVisibleDate; + QDate mFirstVisibleDate; + QDate mLastVisibleDate; + QVector<QDate> mVisibleDates; + QLocale mLocale; +}; + +QT_END_NAMESPACE + +#endif // QQUICKCALENDARMODEL_H diff --git a/src/controls/Private/qquickrangeddate.cpp b/src/controls/Private/qquickrangeddate.cpp new file mode 100644 index 00000000..e76e3cfb --- /dev/null +++ b/src/controls/Private/qquickrangeddate.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickrangeddate_p.h" + +QT_BEGIN_NAMESPACE + +// JavaScript Date > QDate conversion is not correct for large negative dates. +Q_GLOBAL_STATIC_WITH_ARGS(const QDate, jsMinimumDate, (QDate(1, 1, 1))) +Q_GLOBAL_STATIC_WITH_ARGS(const QDate, jsMaximumDate, (QDate(275759, 10, 25))) + +QQuickRangedDate::QQuickRangedDate() : + QObject(0), + mDate(QDate::currentDate()), + mMinimumDate(*jsMinimumDate), + mMaximumDate(*jsMaximumDate) +{ +} + +/*! \internal + \qmlproperty date QQuickRangedDate::date +*/ +void QQuickRangedDate::setDate(const QDate &date) +{ + if (date == mDate) + return; + + if (date < mMinimumDate) { + mDate = mMinimumDate; + } else if (date > mMaximumDate) { + mDate = mMaximumDate; + } else { + mDate = date; + } + + emit dateChanged(); +} + +/*! \internal + \qmlproperty date QQuickRangedDate::minimumDate +*/ +void QQuickRangedDate::setMinimumDate(const QDate &minimumDate) +{ + if (minimumDate == mMinimumDate) + return; + + mMinimumDate = qMax(minimumDate, *jsMinimumDate); + emit minimumDateChanged(); + + // If the new minimumDate makes date invalid, clamp date to it. + if (mDate < mMinimumDate) { + mDate = mMinimumDate; + emit dateChanged(); + } +} + +/*! \internal + \qmlproperty date QQuickRangedDate::maximumDate +*/ +void QQuickRangedDate::setMaximumDate(const QDate &maximumDate) +{ + if (maximumDate == mMaximumDate) + return; + + // If the new maximumDate is smaller than minimumDate, clamp maximumDate to it. + // If the new maximumDate is larger than jsMaximumDate, also clamp it. + mMaximumDate = maximumDate < mMinimumDate ? mMinimumDate : qMin(maximumDate, *jsMaximumDate); + emit maximumDateChanged(); + + // If the new maximumDate makes the date invalid, clamp it. + if (mDate > mMaximumDate) { + mDate = mMaximumDate; + emit dateChanged(); + } +} + +QT_END_NAMESPACE diff --git a/src/controls/Private/qquickrangeddate_p.h b/src/controls/Private/qquickrangeddate_p.h new file mode 100644 index 00000000..975bd27b --- /dev/null +++ b/src/controls/Private/qquickrangeddate_p.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKRANGEDDATE_H +#define QQUICKRANGEDDATE_H + +#include <QDate> + +#include <QtQml/qqml.h> + +QT_BEGIN_NAMESPACE + +class QQuickRangedDate : public QObject +{ + Q_OBJECT + Q_PROPERTY(QDate date READ date WRITE setDate NOTIFY dateChanged RESET resetDate) + Q_PROPERTY(QDate minimumDate READ minimumDate WRITE setMinimumDate NOTIFY minimumDateChanged RESET resetMinimumDate) + Q_PROPERTY(QDate maximumDate READ maximumDate WRITE setMaximumDate NOTIFY maximumDateChanged RESET resetMaximumDate) +public: + QQuickRangedDate(); + ~QQuickRangedDate() {} + + QDate date() const { return mDate; } + void setDate(const QDate &date); + void resetDate() {} + + QDate minimumDate() const { return mMinimumDate; } + void setMinimumDate(const QDate &minimumDate); + void resetMinimumDate() {} + + QDate maximumDate() const { return mMaximumDate; } + void setMaximumDate(const QDate &maximumDate); + void resetMaximumDate() {} + +Q_SIGNALS: + void dateChanged(); + void minimumDateChanged(); + void maximumDateChanged(); + +private: + QDate mDate; + QDate mMinimumDate; + QDate mMaximumDate; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickRangedDate) + +#endif // QQUICKRANGEDDATE_H |