diff options
author | Mitch Curtis <mitch.curtis@theqtcompany.com> | 2015-07-16 12:00:55 +0200 |
---|---|---|
committer | Mitch Curtis <mitch.curtis@theqtcompany.com> | 2015-08-06 11:43:48 +0000 |
commit | 293fc5e8f7df1b60a07d2e7e489e57059bb021bc (patch) | |
tree | 7ea3921797c2541c379cc91eb1f0c4f30d575fbc /examples | |
parent | 1448ee0d1c02280aa33424f992b2f26d74615a43 (diff) |
Add support for ListView to Tumbler.
This enables creation of non-wrapping Tumblers.
Change-Id: I0e21b860b84c456c0651923e87217cafc42c69b7
Reviewed-by: Mitch Curtis <mitch.curtis@theqtcompany.com>
Diffstat (limited to 'examples')
-rw-r--r-- | examples/quick/calendar/DateTimePicker.qml | 176 | ||||
-rw-r--r-- | examples/quick/calendar/EventView.qml | 209 | ||||
-rw-r--r-- | examples/quick/calendar/TumblerDelegate.qml | 54 | ||||
-rw-r--r-- | examples/quick/calendar/calendar.pro | 4 | ||||
-rw-r--r-- | examples/quick/calendar/calendar.qrc | 3 | ||||
-rw-r--r-- | examples/quick/calendar/main.cpp | 178 | ||||
-rw-r--r-- | examples/quick/calendar/main.qml | 139 |
7 files changed, 632 insertions, 131 deletions
diff --git a/examples/quick/calendar/DateTimePicker.qml b/examples/quick/calendar/DateTimePicker.qml new file mode 100644 index 00000000..88238048 --- /dev/null +++ b/examples/quick/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 QtQuick.Calendar 2.0 +import QtQuick.Controls 2.0 +import QtQuick.Extras 2.0 + +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 * (AbstractTumbler.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 * (AbstractTumbler.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 * (AbstractTumbler.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 * (AbstractTumbler.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 * (AbstractTumbler.tumbler.activeFocus ? 2 : 1.25) + } + } + + Tumbler { + id: amPmTumbler + model: ["AM", "PM"] + delegate: TumblerDelegate { + font.pixelSize: fontMetrics.font.pixelSize * (AbstractTumbler.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/quick/calendar/EventView.qml b/examples/quick/calendar/EventView.qml new file mode 100644 index 00000000..3991e5eb --- /dev/null +++ b/examples/quick/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/quick/calendar/TumblerDelegate.qml b/examples/quick/calendar/TumblerDelegate.qml new file mode 100644 index 00000000..60d71f21 --- /dev/null +++ b/examples/quick/calendar/TumblerDelegate.qml @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** 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.Extras 2.0 + +Text { + text: isNaN(modelData) ? modelData : modelData + 1 + color: "#666666" + opacity: 0.4 + Math.max(0, 1 - Math.abs(AbstractTumbler.displacement)) * 0.6 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + + Behavior on font.pixelSize { + NumberAnimation {} + } +} diff --git a/examples/quick/calendar/calendar.pro b/examples/quick/calendar/calendar.pro index f81d9e5a..105e7fc9 100644 --- a/examples/quick/calendar/calendar.pro +++ b/examples/quick/calendar/calendar.pro @@ -13,3 +13,7 @@ RESOURCES += \ target.path = $$[QT_INSTALL_EXAMPLES]/quickcalendar2/calendar INSTALLS += target + +DISTFILES += \ + DateTimePicker.qml \ + EventView.qml diff --git a/examples/quick/calendar/calendar.qrc b/examples/quick/calendar/calendar.qrc index 5f6483ac..d0f67b26 100644 --- a/examples/quick/calendar/calendar.qrc +++ b/examples/quick/calendar/calendar.qrc @@ -1,5 +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/quick/calendar/main.cpp b/examples/quick/calendar/main.cpp index ae41bdf0..1d739add 100644 --- a/examples/quick/calendar/main.cpp +++ b/examples/quick/calendar/main.cpp @@ -45,31 +45,84 @@ class Event : public QObject { Q_OBJECT - Q_PROPERTY(QString name MEMBER name NOTIFY nameChanged) + 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 &name, QObject *parent = 0) : QObject(parent), name(name) { } + explicit Event(const QString &description, QObject *parent = 0) : + QObject(parent), + description(description) + { + + } - QString name; + QString description; QDateTime start; QDateTime end; signals: - void nameChanged(); + void descriptionChanged(); void startChanged(); void endChanged(); }; -class SqlEventModel : public QSqlQueryModel +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) : QSqlQueryModel(parent) { } + 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 { @@ -87,58 +140,83 @@ public: return QDate(); } - Q_INVOKABLE QList<QObject*> eventsForDate(const QDate &date) + QDate date() const + { + return mDate; + } + + void setDate(const QDate &date) { - qint64 from = QDateTime(date, QTime(0, 0)).toMSecsSinceEpoch(); - qint64 to = QDateTime(date, QTime(23, 59)).toMSecsSinceEpoch(); - - QSqlQuery query; - if (!query.exec(QStringLiteral("SELECT * FROM Event WHERE start <= %1 AND end >= %2").arg(to).arg(from))) - qFatal("Query failed"); - - QList<QObject*> events; - while (query.next()) { - Event *event = new Event(query.value("name").toString(), this); - event->start = QDateTime::fromMSecsSinceEpoch(query.value("start").toLongLong()); - event->end = QDateTime::fromMSecsSinceEpoch(query.value("end").toLongLong()); - events.append(event); + 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(); } - return events; } -}; -// create an in-memory SQLITE database -static bool addEvent(QSqlQuery* query, const QString &name, const QDateTime &start, qint64 duration = 0) -{ - QDateTime end = start.addSecs(duration); - return query->exec(QStringLiteral("insert into Event values('%1', %2, %3)").arg(name) - .arg(start.toMSecsSinceEpoch()) - .arg(end.toMSecsSinceEpoch())); -} + enum { + DescriptionRole = Qt::UserRole, + StartDateRole, + EndDateRole + }; -static void createDatabase() -{ - QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); - db.setDatabaseName(":memory:"); - if (!db.open()) { - qFatal("Cannot open database"); - return; + QHash<int,QByteArray> roleNames() const Q_DECL_OVERRIDE + { + QHash<int,QByteArray> names; + names[DescriptionRole] = "description"; + names[StartDateRole] = "start"; + names[EndDateRole] = "end"; + return names; } - QSqlQuery query; - query.exec("create table if not exists Event (name TEXT, start BIGINT, end BIGINT)"); + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE + { + if (role < Qt::UserRole) + return QSqlTableModel::data(index, role); - const QDate current = QDate::currentDate(); - addEvent(&query, "Job interview", QDateTime(current.addDays(-19), QTime(12, 0))); - addEvent(&query, "Grocery shopping", QDateTime(current.addDays(-14), QTime(18, 0))); - addEvent(&query, "Ice skating", QDateTime(current.addDays(-14), QTime(20, 0)), 5400); - addEvent(&query, "Dentist's appointment", QDateTime(current.addDays(-8), QTime(14, 0)), 1800); - addEvent(&query, "Cross-country skiing", QDateTime(current.addDays(1), QTime(19, 30)), 3600); - addEvent(&query, "Conference", QDateTime(current.addDays(10), QTime(9, 0)), 432000); - addEvent(&query, "Hairdresser", QDateTime(current.addDays(19), QTime(13, 0))); - addEvent(&query, "Doctor's appointment", QDateTime(current.addDays(21), QTime(16, 0))); - addEvent(&query, "Vacation", QDateTime(current.addDays(35), QTime(0, 0)), 604800); -} + 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[]) { diff --git a/examples/quick/calendar/main.qml b/examples/quick/calendar/main.qml index db7c2561..3b36272f 100644 --- a/examples/quick/calendar/main.qml +++ b/examples/quick/calendar/main.qml @@ -41,6 +41,7 @@ import QtQuick 2.6 import QtQuick.Controls 2.0 import QtQuick.Calendar 2.0 +import QtQuick.Layouts 1.0 import io.qt.examples.calendar 1.0 ApplicationWindow { @@ -55,12 +56,19 @@ ApplicationWindow { SqlEventModel { id: eventModel + date: calendar.selectedDate } - Flow { - id: row + StackView { + id: stackView anchors.fill: parent anchors.margins: 20 + + initialItem: flow + } + + Flow { + id: flow spacing: 10 layoutDirection: Qt.RightToLeft @@ -79,7 +87,7 @@ ApplicationWindow { } focus: true - currentIndex: -1 + currentIndex: model.indexOf(selectedDate.getFullYear(), selectedDate.getMonth() + 1) snapMode: ListView.SnapOneItem highlightMoveDuration: 250 highlightRangeMode: ListView.StrictlyEnforceRange @@ -139,8 +147,13 @@ ApplicationWindow { height: width radius: width / 2 opacity: 0.5 - color: pressed ? Theme.pressColor : "transparent" - border.color: eventModel.eventsForDate(model.date).length > 0 ? Theme.accentColor : "transparent" + color: pressed ? Theme.pressColor : "transparent"; + + SqlEventModel { + id: delegateEventModel + } + + border.color: delegateEventModel.rowCount > 0 ? Theme.accentColor : "transparent" } } } @@ -152,89 +165,53 @@ ApplicationWindow { } } - Component { - id: eventListHeader - - Row { - id: eventDateRow - width: parent.width - height: eventDayLabel.height - spacing: 10 - - Label { - id: eventDayLabel - text: calendar.selectedDate.getDate() - font.pointSize: 35 - } - - Column { - height: eventDayLabel.height + 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 - Label { - readonly property var options: { weekday: "long" } - text: Qt.locale().standaloneDayName(calendar.selectedDate.getDay(), Locale.LongFormat) - font.pointSize: 18 - } - Label { - text: Qt.locale().standaloneMonthName(calendar.selectedDate.getMonth()) - + calendar.selectedDate.toLocaleDateString(Qt.locale(), " yyyy") - font.pointSize: 12 - } - } - } + onAddEventClicked: stackView.push(createEventComponent) } + } - Rectangle { - 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) - border.color: Theme.frameColor + Component { + id: createEventComponent - ListView { - id: eventsListView - spacing: 4 - clip: true - header: eventListHeader - anchors.fill: parent - anchors.margins: 10 - model: eventModel.eventsForDate(calendar.selectedDate) + ColumnLayout { + spacing: 10 + visible: AbstractStackView.index === stackView.currentIndex - delegate: Rectangle { - width: eventsListView.width - height: eventItemColumn.height - anchors.horizontalCenter: parent.horizontalCenter + DateTimePicker { + id: dateTimePicker + anchors.horizontalCenter: parent.horizontalCenter + dateToShow: calendar.selectedDate + } + Frame { + Layout.fillWidth: true - Rectangle { - width: parent.width - height: 1 - color: "#eee" - } + TextArea { + id: descriptionField + placeholder.text: "Description" + anchors.fill: parent + } + } + RowLayout { + Layout.fillWidth: true - Column { - id: eventItemColumn - x: 4 - y: 4 - width: parent.width - 8 - height: timeRow.height + nameLabel.height + 8 - - Label { - id: nameLabel - width: parent.width - wrapMode: Text.Wrap - text: modelData.name - } - Row { - id: timeRow - width: parent.width - Label { - text: modelData.start.toLocaleTimeString(calendar.locale, Locale.ShortFormat) - color: "#aaa" - } - Label { - text: "-" + new Date(modelData.end).toLocaleTimeString(calendar.locale, Locale.ShortFormat) - visible: modelData.start.getTime() !== modelData.end.getTime() && modelData.start.getDate() === modelData.end.getDate() - color: "#aaa" - } - } + 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(); } } } |