aboutsummaryrefslogtreecommitdiffstats
path: root/examples/labs
diff options
context:
space:
mode:
Diffstat (limited to 'examples/labs')
-rw-r--r--examples/labs/calendar/DateTimePicker.qml176
-rw-r--r--examples/labs/calendar/EventView.qml209
-rw-r--r--examples/labs/calendar/TumblerDelegate.qml55
-rw-r--r--examples/labs/calendar/calendar.pro19
-rw-r--r--examples/labs/calendar/calendar.qrc8
-rw-r--r--examples/labs/calendar/main.cpp233
-rw-r--r--examples/labs/calendar/main.qml221
-rw-r--r--examples/labs/labs.pro3
8 files changed, 924 insertions, 0 deletions
diff --git a/examples/labs/calendar/DateTimePicker.qml b/examples/labs/calendar/DateTimePicker.qml
new file mode 100644
index 00000000..96da4175
--- /dev/null
+++ b/examples/labs/calendar/DateTimePicker.qml
@@ -0,0 +1,176 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples 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 The Qt Company Ltd 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.6
+import Qt.labs.calendar 1.0
+import QtQuick.Controls 2.0
+import QtQuick.Templates 2.0 as T
+
+Item {
+ id: dateTimePicker
+ enabled: dateToShow.getFullYear() >= fromYear || dateToShow.getFullYear() <= toYear
+ implicitWidth: row.implicitWidth
+ implicitHeight: row.implicitHeight
+
+ readonly property var days: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
+
+ readonly property int fromYear: 2000
+ readonly property int toYear: 2020
+
+ readonly property alias chosenDate: dateTimePicker.__date
+ property var __date: new Date(
+ fromYear + yearTumbler.currentIndex,
+ monthTumbler.currentIndex,
+ dayTumbler.currentIndex + 1,
+ hoursTumbler.currentIndex + (amPmTumbler.currentIndex == 0 ? 0 : 12),
+ minutesTumbler.currentIndex);
+
+ property date dateToShow: new Date()
+ onDateToShowChanged: {
+ yearTumbler.currentIndex = dateToShow.getFullYear() - fromYear;
+ monthTumbler.currentIndex = dateToShow.getMonth();
+ dayTumbler.currentIndex = dateToShow.getDate() - 1;
+ }
+
+ FontMetrics {
+ id: fontMetrics
+ }
+
+ Row {
+ id: row
+ spacing: 2
+
+ Frame {
+ padding: 0
+
+ Row {
+ Tumbler {
+ id: dayTumbler
+
+ delegate: TumblerDelegate {
+ text: modelData
+ font.pixelSize: fontMetrics.font.pixelSize * (T.Tumbler.tumbler.activeFocus ? 2 : 1.25)
+ }
+
+ function updateModel() {
+ var previousIndex = dayTumbler.currentIndex;
+ var array = [];
+ var newDays = dateTimePicker.days[monthTumbler.currentIndex];
+ for (var i = 0; i < newDays; ++i) {
+ array.push(i + 1);
+ }
+ dayTumbler.model = array;
+ dayTumbler.currentIndex = Math.min(newDays - 1, previousIndex);
+ }
+
+ Component.onCompleted: updateModel()
+ }
+ Tumbler {
+ id: monthTumbler
+ model: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
+ delegate: TumblerDelegate {
+ text: modelData
+ font.pixelSize: fontMetrics.font.pixelSize * (T.Tumbler.tumbler.activeFocus ? 2 : 1.25)
+ }
+ onCurrentIndexChanged: dayTumbler.updateModel()
+ }
+ Tumbler {
+ id: yearTumbler
+ width: 80
+ model: {
+ var years = [];
+ for (var i = fromYear; i <= toYear; ++i) {
+ years.push(i);
+ }
+ return years;
+ }
+ delegate: TumblerDelegate {
+ text: modelData
+ font.pixelSize: fontMetrics.font.pixelSize * (T.Tumbler.tumbler.activeFocus ? 2 : 1.25)
+ }
+ }
+ }
+ }
+
+ Frame {
+ padding: 0
+
+ Row {
+ Tumbler {
+ id: hoursTumbler
+ model: 12
+ delegate: TumblerDelegate {
+ text: modelData.toString().length < 2 ? "0" + modelData : modelData
+ font.pixelSize: fontMetrics.font.pixelSize * (T.Tumbler.tumbler.activeFocus ? 2 : 1.25)
+ }
+ }
+
+ Tumbler {
+ id: minutesTumbler
+ model: 60
+ delegate: TumblerDelegate {
+ text: modelData.toString().length < 2 ? "0" + modelData : modelData
+ font.pixelSize: fontMetrics.font.pixelSize * (T.Tumbler.tumbler.activeFocus ? 2 : 1.25)
+ }
+ }
+
+ Tumbler {
+ id: amPmTumbler
+ model: ["AM", "PM"]
+ delegate: TumblerDelegate {
+ font.pixelSize: fontMetrics.font.pixelSize * (T.Tumbler.tumbler.activeFocus ? 2 : 1.25)
+ }
+
+ contentItem: ListView {
+ anchors.fill: parent
+ model: amPmTumbler.model
+ delegate: amPmTumbler.delegate
+
+ snapMode: ListView.SnapToItem
+ highlightRangeMode: ListView.StrictlyEnforceRange
+ preferredHighlightBegin: height / 2 - (height / 3 / 2)
+ preferredHighlightEnd: height / 2 + (height / 3 / 2)
+ clip: true
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/examples/labs/calendar/EventView.qml b/examples/labs/calendar/EventView.qml
new file mode 100644
index 00000000..3991e5eb
--- /dev/null
+++ b/examples/labs/calendar/EventView.qml
@@ -0,0 +1,209 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples 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 The Qt Company Ltd 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.6
+import QtQuick.Controls 2.0
+
+Rectangle {
+ border.color: Theme.frameColor
+
+ property date selectedDate
+ property var locale
+ property var eventModel
+
+ signal addEventClicked
+
+ Component {
+ id: eventListHeader
+
+ Row {
+ id: eventDateRow
+ width: parent.width
+ height: eventDayLabel.height
+ spacing: 10
+
+ Label {
+ id: eventDayLabel
+ text: selectedDate.getDate()
+ font.pointSize: 35
+ }
+
+ Column {
+ height: eventDayLabel.height
+
+ Label {
+ readonly property var options: { weekday: "long" }
+ text: Qt.locale().standaloneDayName(selectedDate.getDay(), Locale.LongFormat)
+ font.pointSize: 18
+ }
+ Label {
+ text: Qt.locale().standaloneMonthName(selectedDate.getMonth())
+ + selectedDate.toLocaleDateString(Qt.locale(), " yyyy")
+ font.pointSize: 12
+ }
+ }
+ }
+ }
+
+ ListView {
+ id: eventsListView
+ spacing: 4
+ clip: true
+ header: eventListHeader
+ anchors.fill: parent
+ anchors.margins: 10
+ model: eventModel
+
+ delegate: Rectangle {
+ width: eventsListView.width
+ height: eventItemColumn.height
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ Rectangle {
+ width: parent.width
+ height: 1
+ color: "#eee"
+ }
+
+ Column {
+ id: eventItemColumn
+ x: 4
+ y: 4
+ width: parent.width - 8
+ height: timeRow.height + descriptionLabel.height + 8
+
+ Label {
+ id: descriptionLabel
+ width: parent.width
+ wrapMode: Text.Wrap
+ text: description
+ }
+ Row {
+ id: timeRow
+ width: parent.width
+ Label {
+ text: start.toLocaleTimeString(locale, Locale.ShortFormat)
+ color: "#aaa"
+ }
+ Label {
+ text: "-" + end.toLocaleTimeString(locale, Locale.ShortFormat)
+ visible: start.getTime() !== end.getTime() && start.getDate() === end.getDate()
+ color: "#aaa"
+ }
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onPressAndHold: removeButton.opacity = 1
+ onClicked: removeButton.opacity = 0
+ }
+
+ Button {
+ id: removeButton
+ opacity: 0
+
+ Behavior on opacity {
+ NumberAnimation {
+ duration: 150
+ }
+ }
+
+ anchors.right: parent.right
+ anchors.rightMargin: 12
+ anchors.verticalCenter: parent.verticalCenter
+
+ onClicked: eventModel.removeEvent(index)
+
+ background: Rectangle {
+ implicitWidth: 32
+ implicitHeight: 32
+
+ radius: width / 2
+ color: Qt.tint(!addButton.enabled ? addButton.Theme.disabledColor :
+ addButton.activeFocus ? addButton.Theme.focusColor : "red",
+ addButton.pressed ? addButton.Theme.pressColor : "transparent")
+ }
+ }
+
+ // Don't want the white icon to change opacity.
+ Rectangle {
+ anchors.centerIn: removeButton
+ width: 18
+ height: 4
+ radius: 1
+ }
+ }
+ }
+
+ Button {
+ id: addButton
+
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ anchors.margins: 12
+
+ onClicked: addEventClicked()
+
+ background: Rectangle {
+ implicitWidth: 32
+ implicitHeight: 32
+
+ radius: width / 2
+ color: Qt.tint(!addButton.enabled ? addButton.Theme.disabledColor :
+ addButton.activeFocus ? addButton.Theme.focusColor : addButton.Theme.accentColor,
+ addButton.pressed ? addButton.Theme.pressColor : "transparent")
+ }
+
+ Rectangle {
+ anchors.centerIn: parent
+ width: 4
+ height: 18
+ radius: 1
+ }
+
+ Rectangle {
+ anchors.centerIn: parent
+ width: 18
+ height: 4
+ radius: 1
+ }
+ }
+}
diff --git a/examples/labs/calendar/TumblerDelegate.qml b/examples/labs/calendar/TumblerDelegate.qml
new file mode 100644
index 00000000..e9c7a143
--- /dev/null
+++ b/examples/labs/calendar/TumblerDelegate.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples 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 The Qt Company Ltd 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.6
+import QtQuick.Controls 2.0
+import QtQuick.Templates 2.0 as T
+
+Text {
+ text: isNaN(modelData) ? modelData : modelData + 1
+ color: "#666666"
+ opacity: 0.4 + Math.max(0, 1 - Math.abs(T.Tumbler.displacement)) * 0.6
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+
+ Behavior on font.pixelSize {
+ NumberAnimation {}
+ }
+}
diff --git a/examples/labs/calendar/calendar.pro b/examples/labs/calendar/calendar.pro
new file mode 100644
index 00000000..105e7fc9
--- /dev/null
+++ b/examples/labs/calendar/calendar.pro
@@ -0,0 +1,19 @@
+TEMPLATE = app
+TARGET = calendar
+QT += quick sql
+
+SOURCES += \
+ main.cpp
+
+OTHER_FILES += \
+ main.qml
+
+RESOURCES += \
+ calendar.qrc
+
+target.path = $$[QT_INSTALL_EXAMPLES]/quickcalendar2/calendar
+INSTALLS += target
+
+DISTFILES += \
+ DateTimePicker.qml \
+ EventView.qml
diff --git a/examples/labs/calendar/calendar.qrc b/examples/labs/calendar/calendar.qrc
new file mode 100644
index 00000000..d0f67b26
--- /dev/null
+++ b/examples/labs/calendar/calendar.qrc
@@ -0,0 +1,8 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ <file>DateTimePicker.qml</file>
+ <file>TumblerDelegate.qml</file>
+ <file>EventView.qml</file>
+ </qresource>
+</RCC>
diff --git a/examples/labs/calendar/main.cpp b/examples/labs/calendar/main.cpp
new file mode 100644
index 00000000..651a51ec
--- /dev/null
+++ b/examples/labs/calendar/main.cpp
@@ -0,0 +1,233 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples 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 The Qt Company Ltd 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$
+**
+****************************************************************************/
+
+#include <QtGui>
+#include <QtQml>
+#include <QtSql>
+
+class Event : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString description MEMBER description NOTIFY descriptionChanged)
+ Q_PROPERTY(QDateTime start MEMBER start NOTIFY startChanged)
+ Q_PROPERTY(QDateTime end MEMBER end NOTIFY endChanged)
+
+public:
+ explicit Event(const QString &description, QObject *parent = 0) :
+ QObject(parent),
+ description(description)
+ {
+
+ }
+
+ QString description;
+ QDateTime start;
+ QDateTime end;
+
+signals:
+ void descriptionChanged();
+ void startChanged();
+ void endChanged();
+};
+
+static void addEvent(const QString &description, const QDateTime &start, qint64 duration = 0)
+{
+ QSqlQuery query;
+ QDateTime end = start.addSecs(duration);
+ if (!query.exec(QStringLiteral("INSERT INTO Event (description, start, end) VALUES ('%1', %2, %3)")
+ .arg(description).arg(start.toMSecsSinceEpoch()).arg(end.toMSecsSinceEpoch()))) {
+ qWarning() << query.lastError();
+ }
+}
+
+// create an in-memory SQLITE database
+static void createDatabase()
+{
+ QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
+ db.setDatabaseName(":memory:");
+ if (!db.open()) {
+ qFatal("Cannot open database");
+ return;
+ }
+
+ QSqlQuery query;
+ query.exec("CREATE TABLE IF NOT EXISTS Event (description TEXT, start BIGINT, end BIGINT)");
+
+ const QDate current = QDate::currentDate();
+ addEvent("Job interview", QDateTime(current.addDays(-19), QTime(12, 0)));
+ addEvent("Grocery shopping", QDateTime(current.addDays(-14), QTime(18, 0)));
+ addEvent("Ice skating", QDateTime(current.addDays(-14), QTime(20, 0)), 5400);
+ addEvent("Dentist''s appointment", QDateTime(current.addDays(-8), QTime(14, 0)), 1800);
+ addEvent("Cross-country skiing", QDateTime(current.addDays(1), QTime(19, 30)), 3600);
+ addEvent("Conference", QDateTime(current.addDays(10), QTime(9, 0)), 432000);
+ addEvent("Hairdresser", QDateTime(current.addDays(19), QTime(13, 0)));
+ addEvent("Doctor''s appointment", QDateTime(current.addDays(21), QTime(16, 0)));
+ addEvent("Vacation", QDateTime(current.addDays(35), QTime(0, 0)), 604800);
+}
+
+class SqlEventModel : public QSqlTableModel
+{
+ Q_OBJECT
+ Q_PROPERTY(QDate min READ min CONSTANT)
+ Q_PROPERTY(QDate max READ max CONSTANT)
+ Q_PROPERTY(QDate date READ date WRITE setDate NOTIFY dateChanged FINAL)
+ Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged)
+
+public:
+ SqlEventModel(QObject *parent = 0) :
+ QSqlTableModel(parent, QSqlDatabase::database(":memory:"))
+ {
+ connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SIGNAL(rowCountChanged()));
+ connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SIGNAL(rowCountChanged()));
+
+ setTable("Event");
+ setEditStrategy(QSqlTableModel::OnManualSubmit);
+ select();
+
+ setDate(QDate::currentDate());
+ }
+
+ QDate min() const
+ {
+ QSqlQuery query(QStringLiteral("SELECT MIN(start) FROM Event"));
+ if (query.next())
+ return QDateTime::fromMSecsSinceEpoch(query.value(0).toLongLong()).date();
+ return QDate();
+ }
+
+ QDate max() const
+ {
+ QSqlQuery query(QStringLiteral("SELECT MAX(end) FROM Event"));
+ if (query.next())
+ return QDateTime::fromMSecsSinceEpoch(query.value(0).toLongLong()).date();
+ return QDate();
+ }
+
+ QDate date() const
+ {
+ return mDate;
+ }
+
+ void setDate(const QDate &date)
+ {
+ if (date != mDate) {
+ mDate = date;
+
+ qint64 from = QDateTime(mDate, QTime(0, 0)).toMSecsSinceEpoch();
+ qint64 to = QDateTime(mDate, QTime(23, 59)).toMSecsSinceEpoch();
+
+ setFilter(QStringLiteral("start <= %1 AND end >= %2").arg(to).arg(from));
+
+ emit dateChanged();
+ }
+ }
+
+ enum {
+ DescriptionRole = Qt::UserRole,
+ StartDateRole,
+ EndDateRole
+ };
+
+ QHash<int,QByteArray> roleNames() const Q_DECL_OVERRIDE
+ {
+ QHash<int,QByteArray> names;
+ names[DescriptionRole] = "description";
+ names[StartDateRole] = "start";
+ names[EndDateRole] = "end";
+ return names;
+ }
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE
+ {
+ if (role < Qt::UserRole)
+ return QSqlTableModel::data(index, role);
+
+ int columnIndex = role - DescriptionRole;
+ QModelIndex modelIndex = this->index(index.row(), columnIndex);
+ QVariant eventData = QSqlTableModel::data(modelIndex, Qt::DisplayRole);
+ if (role == DescriptionRole)
+ return eventData;
+
+ return QDateTime::fromMSecsSinceEpoch(eventData.toLongLong());
+ }
+
+ Q_INVOKABLE void addEvent(const QString &description, const QDateTime &date)
+ {
+ const int row = rowCount();
+ insertRows(row, 1);
+ setData(index(row, 0), description);
+ setData(index(row, 1), date.toMSecsSinceEpoch());
+ setData(index(row, 2), date.toMSecsSinceEpoch());
+ submitAll();
+ }
+
+ Q_INVOKABLE void removeEvent(int modelRow)
+ {
+ if (modelRow < 0 || modelRow >= rowCount()) {
+ qWarning() << "Invalid model row:" << modelRow;
+ return;
+ }
+
+ removeRows(modelRow, 1);
+ submitAll();
+ }
+
+signals:
+ void dateChanged();
+ void rowCountChanged();
+
+private:
+ // The date to show events for.
+ QDate mDate;
+};
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+ createDatabase();
+ qmlRegisterType<SqlEventModel>("io.qt.examples.calendar", 1, 0, "SqlEventModel");
+ QQmlApplicationEngine engine;
+ engine.load(QUrl("qrc:/main.qml"));
+ if (engine.rootObjects().isEmpty())
+ return -1;
+ return app.exec();
+}
+
+#include "main.moc"
diff --git a/examples/labs/calendar/main.qml b/examples/labs/calendar/main.qml
new file mode 100644
index 00000000..ca23b166
--- /dev/null
+++ b/examples/labs/calendar/main.qml
@@ -0,0 +1,221 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples 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 The Qt Company Ltd 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.6
+import QtQuick.Controls 2.0
+import Qt.labs.calendar 1.0
+import QtQuick.Templates 2.0 as T
+import QtQuick.Layouts 1.0
+import io.qt.examples.calendar 1.0
+
+ApplicationWindow {
+ id: window
+ width: 640
+ height: 400
+ minimumWidth: 400
+ minimumHeight: 300
+ color: "#f4f4f4"
+ visible: true
+ title: "Qt Labs Calendar - Example"
+
+ SqlEventModel {
+ id: eventModel
+ date: calendar.selectedDate
+ }
+
+ StackView {
+ id: stackView
+ anchors.fill: parent
+ anchors.margins: 20
+
+ initialItem: flow
+ }
+
+ Flow {
+ id: flow
+ spacing: 10
+ layoutDirection: Qt.RightToLeft
+
+ ListView {
+ id: calendar
+ property date selectedDate: new Date()
+
+ clip: true
+ width: (parent.width > parent.height ? (parent.width - parent.spacing) * 0.6 : parent.width)
+ height: (parent.height > parent.width ? (parent.height - parent.spacing) * 0.6 : parent.height)
+
+ model: CalendarModel {
+ id: model
+ from: eventModel.min
+ to: eventModel.max
+ }
+
+ focus: true
+ currentIndex: model.indexOf(selectedDate.getFullYear(), selectedDate.getMonth() + 1)
+ snapMode: ListView.SnapOneItem
+ highlightMoveDuration: 250
+ highlightRangeMode: ListView.StrictlyEnforceRange
+ orientation: parent.width > parent.height ? ListView.Vertical : ListView.Horizontal
+
+ delegate: CalendarView {
+ id: delegate
+
+ width: calendar.width
+ height: calendar.height
+
+ month: model.month
+ year: model.year
+
+ topPadding: title.height
+ Column {
+ id: title
+ x: delegate.contentItem.x
+ width: delegate.contentItem.width
+ spacing: 6
+ Text {
+ width: parent.width
+ height: implicitHeight * 2
+ text: delegate.title
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ font.pointSize: 18
+ }
+ DayOfWeekRow {
+ width: parent.width
+ }
+ }
+
+ leftPadding: weekNumbers.width
+ WeekNumberColumn {
+ id: weekNumbers
+ month: model.month
+ year: model.year
+ y: delegate.contentItem.y
+ height: delegate.contentItem.height
+ }
+
+ onClicked: calendar.selectedDate = date
+
+ delegate: Text {
+ text: model.day
+ opacity: model.month === delegate.month ? 1 : 0
+ color: model.today ? Theme.accentColor : Theme.textColor
+ minimumPointSize: 8
+ fontSizeMode: Text.Fit
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ Rectangle {
+ z: -1
+ anchors.centerIn: parent
+ width: Math.min(parent.width * 0.6, parent.width * 0.6)
+ height: width
+ radius: width / 2
+ opacity: 0.5
+ color: pressed ? Theme.pressColor : "transparent";
+
+ SqlEventModel {
+ id: delegateEventModel
+ }
+
+ border.color: delegateEventModel.rowCount > 0 ? Theme.accentColor : "transparent"
+ }
+ }
+ }
+ Rectangle {
+ z: -1
+ parent: calendar
+ anchors.fill: parent
+ border.color: Theme.frameColor
+ }
+ }
+
+ EventView {
+ width: (parent.width > parent.height ? (parent.width - parent.spacing) * 0.4 : parent.width)
+ height: (parent.height > parent.width ? (parent.height - parent.spacing) * 0.4 : parent.height)
+ selectedDate: calendar.selectedDate
+ eventModel: eventModel
+ locale: calendar.locale
+
+ onAddEventClicked: stackView.push(createEventComponent)
+ }
+ }
+
+ Component {
+ id: createEventComponent
+
+ ColumnLayout {
+ spacing: 10
+ visible: T.StackView.index === stackView.currentIndex
+
+ DateTimePicker {
+ id: dateTimePicker
+ anchors.horizontalCenter: parent.horizontalCenter
+ dateToShow: calendar.selectedDate
+ }
+ Frame {
+ Layout.fillWidth: true
+
+ TextArea {
+ id: descriptionField
+ placeholder.text: "Description"
+ anchors.fill: parent
+ }
+ }
+ RowLayout {
+ Layout.fillWidth: true
+
+ Button {
+ text: "Cancel"
+ Layout.fillWidth: true
+ onClicked: stackView.pop()
+ }
+ Button {
+ text: "Create"
+ enabled: dateTimePicker.enabled
+ Layout.fillWidth: true
+ onClicked: {
+ eventModel.addEvent(descriptionField.text, dateTimePicker.chosenDate);
+ stackView.pop();
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/examples/labs/labs.pro b/examples/labs/labs.pro
new file mode 100644
index 00000000..88683726
--- /dev/null
+++ b/examples/labs/labs.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS += \
+ calendar