diff options
author | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2013-12-06 14:20:59 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-12-06 20:26:58 +0100 |
commit | ef22abaf91de79b9b47f20e71305a1cdea177da0 (patch) | |
tree | 36860f6a248c233213537b9a729e253a409115ac /examples/enginio | |
parent | f4875461a7133f5978b460940812d9c569a26c23 (diff) | |
download | qtenginio-ef22abaf91de79b9b47f20e71305a1cdea177da0.tar.gz |
Move examples into enginio directory
Change-Id: Ifd57d60f449c4654133a1f68c74f1f01b91fa2f0
Reviewed-by: Jędrzej Nowacki <jedrzej.nowacki@digia.com>
Diffstat (limited to 'examples/enginio')
81 files changed, 5892 insertions, 0 deletions
diff --git a/examples/enginio/common/backendhelper/BackendHelper.qml b/examples/enginio/common/backendhelper/BackendHelper.qml new file mode 100644 index 0000000..d490f4f --- /dev/null +++ b/examples/enginio/common/backendhelper/BackendHelper.qml @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 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.0 + +Rectangle { + id: backendHelper + anchors.fill: parent + anchors.margins: 4 + color: "white" + + property string backendId: "" + + Behavior on opacity { + NumberAnimation { duration: 100 } + } + + function capitalise(string) + { + return string.charAt(0).toUpperCase() + string.slice(1); + } + + Column { + anchors.fill: parent + spacing: 5 + Image { + source: "qrc:images/enginio.png" + width: parent.width + fillMode: Image.PreserveAspectFit + } + + Text { + width: parent.width + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + + font.pixelSize: 22 + font.bold: true + text: capitalise(enginioBackendContext.exampleName) + " example" + } + + Text { + id: info + width: parent.width + verticalAlignment: Text.AlignVCenter + font.pixelSize: 20 + + text: "<html><head/><body><p>For the Enginio Examples to work the backend ID is needed. Please copy them from your <a href=\"http://engin.io\"><span style=\" text-decoration: underline; color:#0000ff;\">Enginio Dashboard.</span></a></p><p>Make sure to have the right type of backend or configure it manually according to the example's documentation. </p></body></html>" + color: "black" + + wrapMode: Text.Wrap + } + + Text { + width: parent.width + verticalAlignment: Text.AlignVCenter + font.pixelSize: 22 + text: capitalise(enginioBackendContext.exampleName) + " example backend id:" + } + + TextInput { + width: parent.width + height: 50 + + focus: true + + verticalAlignment: Text.AlignVCenter + font.pixelSize: 22 + text: enginioBackendContext.backendId + + onAccepted: { + backendId = text + enginioBackendContext.backendId = text + backendHelper.opacity = 0 + backendHelper.enabled = false + } + + Text { + id: placeholderText + anchors.fill: parent + verticalAlignment: Text.AlignVCenter + visible: !(parent.text.length || parent.inputMethodComposing) + font: parent.font + text: "Place " + capitalise(enginioBackendContext.exampleName) + " example backend id here" + color: "#aaa" + } + } + } +} diff --git a/examples/enginio/common/backendhelper/backendhelper.cpp b/examples/enginio/common/backendhelper/backendhelper.cpp new file mode 100644 index 0000000..b31e5f0 --- /dev/null +++ b/examples/enginio/common/backendhelper/backendhelper.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 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$ +** +****************************************************************************/ + +#include <Enginio/enginioclient.h> +#include <QtWidgets> +#include "backendhelper.h" +#include "ui_helperdialog.h" + +const QString backendIdKey = QStringLiteral("backendId"); +const QString showAgainKey = QStringLiteral("showAgain"); + +QByteArray backendId(const QString &exampleName) +{ + + QString fileName = QStringLiteral("EnginioExamples.conf"); + for (int i = 0; i < 4; ++i) { + if (QFile::exists(fileName)) + break; + fileName = fileName.prepend("../"); + } + + QFileInfo settingsFile = QFileInfo(fileName); + + QScopedPointer<QSettings> settings(settingsFile.exists() + ? new QSettings(settingsFile.absoluteFilePath(), QSettings::IniFormat) + : new QSettings("com.digia", "EnginioExamples")); + + settings->beginGroup(exampleName); + QByteArray id = settings->value(backendIdKey).toByteArray(); + bool askAgain = settings->value(showAgainKey, true).toBool(); + + if (askAgain || id.isEmpty()) { + Ui::Dialog dialog; + QDialog d; + dialog.setupUi(&d); + dialog.exampleName->setText(exampleName); + dialog.backendId->setText(id); + + if (d.exec() == QDialog::Accepted) { + id = dialog.backendId->text().toLocal8Bit(); + askAgain = !dialog.askAgain->isChecked(); + settings->setValue(backendIdKey, id); + settings->setValue(showAgainKey, askAgain); + } + } + + settings->endGroup(); + settings->sync(); + + return id; +} + diff --git a/examples/enginio/common/backendhelper/backendhelper.h b/examples/enginio/common/backendhelper/backendhelper.h new file mode 100644 index 0000000..568f501 --- /dev/null +++ b/examples/enginio/common/backendhelper/backendhelper.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 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$ +** +****************************************************************************/ + +#ifndef ENGINIO_EXAMPLE_BACKEND_HELPER +#define ENGINIO_EXAMPLE_BACKEND_HELPER + +#include <QtCore> + +QByteArray backendId(const QString &exampleName); + +#endif diff --git a/examples/enginio/common/backendhelper/backendhelper.pri b/examples/enginio/common/backendhelper/backendhelper.pri new file mode 100644 index 0000000..855202f --- /dev/null +++ b/examples/enginio/common/backendhelper/backendhelper.pri @@ -0,0 +1,6 @@ +QT += widgets + +INCLUDEPATH += $$PWD +HEADERS += $$PWD/backendhelper.h +SOURCES += $$PWD/backendhelper.cpp +FORMS += $$PWD/helperdialog.ui diff --git a/examples/enginio/common/backendhelper/helperdialog.ui b/examples/enginio/common/backendhelper/helperdialog.ui new file mode 100644 index 0000000..4b97f64 --- /dev/null +++ b/examples/enginio/common/backendhelper/helperdialog.ui @@ -0,0 +1,115 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Dialog</class> + <widget class="QDialog" name="Dialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>412</width> + <height>257</height> + </rect> + </property> + <property name="windowTitle"> + <string>Enginio Backend Configuration</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string><html><head/><body><p>For the Enginio Examples to work the backend ID is needed. Please copy them from your <a href="http://engin.io"><span style=" text-decoration: underline; color:#0000ff;">Enginio Dashboard.</span></a></p><p>Make sure to have the right type of backend or configure it manually according to the example's documentation. </p></body></html></string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + <property name="openExternalLinks"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <layout class="QFormLayout" name="formLayout"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::AllNonFixedFieldsGrow</enum> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="exampleNameLabel"> + <property name="text"> + <string>Example name:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="exampleName"> + <property name="text"> + <string>...</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Backend ID:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="backendId"/> + </item> + </layout> + </item> + <item> + <widget class="QCheckBox" name="askAgain"> + <property name="text"> + <string>Do not show this dialog again</string> + </property> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>Dialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>Dialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/examples/enginio/common/backendhelper/qmlbackendhelper.pri b/examples/enginio/common/backendhelper/qmlbackendhelper.pri new file mode 100644 index 0000000..9debd13 --- /dev/null +++ b/examples/enginio/common/backendhelper/qmlbackendhelper.pri @@ -0,0 +1 @@ +RESOURCES += $$PWD/qmlbackendhelper.qrc diff --git a/examples/enginio/common/backendhelper/qmlbackendhelper.qrc b/examples/enginio/common/backendhelper/qmlbackendhelper.qrc new file mode 100644 index 0000000..af762d6 --- /dev/null +++ b/examples/enginio/common/backendhelper/qmlbackendhelper.qrc @@ -0,0 +1,8 @@ +<RCC> + <qresource prefix="/"> + <file alias="BackendHelper.qml">../../common/backendhelper/BackendHelper.qml</file> + </qresource> + <qresource prefix="/images"> + <file alias="enginio.png">../../common/images/enginio.png</file> + </qresource> +</RCC> diff --git a/examples/enginio/common/icons/add_icon.png b/examples/enginio/common/icons/add_icon.png Binary files differnew file mode 100644 index 0000000..cfd6fc5 --- /dev/null +++ b/examples/enginio/common/icons/add_icon.png diff --git a/examples/enginio/common/icons/add_icon_pressed.png b/examples/enginio/common/icons/add_icon_pressed.png Binary files differnew file mode 100644 index 0000000..2d7fe82 --- /dev/null +++ b/examples/enginio/common/icons/add_icon_pressed.png diff --git a/examples/enginio/common/icons/back_icon.png b/examples/enginio/common/icons/back_icon.png Binary files differnew file mode 100644 index 0000000..5340209 --- /dev/null +++ b/examples/enginio/common/icons/back_icon.png diff --git a/examples/enginio/common/icons/delete_icon.png b/examples/enginio/common/icons/delete_icon.png Binary files differnew file mode 100644 index 0000000..59abea8 --- /dev/null +++ b/examples/enginio/common/icons/delete_icon.png diff --git a/examples/enginio/common/icons/delete_icon_pressed.png b/examples/enginio/common/icons/delete_icon_pressed.png Binary files differnew file mode 100644 index 0000000..991dda1 --- /dev/null +++ b/examples/enginio/common/icons/delete_icon_pressed.png diff --git a/examples/enginio/common/icons/reload_icon.png b/examples/enginio/common/icons/reload_icon.png Binary files differnew file mode 100644 index 0000000..cfd6fc5 --- /dev/null +++ b/examples/enginio/common/icons/reload_icon.png diff --git a/examples/enginio/common/icons/reload_icon_pressed.png b/examples/enginio/common/icons/reload_icon_pressed.png Binary files differnew file mode 100644 index 0000000..cfd6fc5 --- /dev/null +++ b/examples/enginio/common/icons/reload_icon_pressed.png diff --git a/examples/enginio/common/icons/share_icon.png b/examples/enginio/common/icons/share_icon.png Binary files differnew file mode 100644 index 0000000..f0f2084 --- /dev/null +++ b/examples/enginio/common/icons/share_icon.png diff --git a/examples/enginio/common/icons/share_icon_pressed.png b/examples/enginio/common/icons/share_icon_pressed.png Binary files differnew file mode 100644 index 0000000..70421b6 --- /dev/null +++ b/examples/enginio/common/icons/share_icon_pressed.png diff --git a/examples/enginio/common/images/checkbox.png b/examples/enginio/common/images/checkbox.png Binary files differnew file mode 100644 index 0000000..81d5743 --- /dev/null +++ b/examples/enginio/common/images/checkbox.png diff --git a/examples/enginio/common/images/checkbox_checked.png b/examples/enginio/common/images/checkbox_checked.png Binary files differnew file mode 100644 index 0000000..a551018 --- /dev/null +++ b/examples/enginio/common/images/checkbox_checked.png diff --git a/examples/enginio/common/images/delegate.png b/examples/enginio/common/images/delegate.png Binary files differnew file mode 100644 index 0000000..0166ddf --- /dev/null +++ b/examples/enginio/common/images/delegate.png diff --git a/examples/enginio/common/images/delegate_pressed.png b/examples/enginio/common/images/delegate_pressed.png Binary files differnew file mode 100644 index 0000000..eba3c11 --- /dev/null +++ b/examples/enginio/common/images/delegate_pressed.png diff --git a/examples/enginio/common/images/enginio.png b/examples/enginio/common/images/enginio.png Binary files differnew file mode 100644 index 0000000..7d286a1 --- /dev/null +++ b/examples/enginio/common/images/enginio.png diff --git a/examples/enginio/common/images/shadow.png b/examples/enginio/common/images/shadow.png Binary files differnew file mode 100644 index 0000000..d3eb97f --- /dev/null +++ b/examples/enginio/common/images/shadow.png diff --git a/examples/enginio/common/images/textfield.png b/examples/enginio/common/images/textfield.png Binary files differnew file mode 100644 index 0000000..65dc759 --- /dev/null +++ b/examples/enginio/common/images/textfield.png diff --git a/examples/enginio/enginio.pro b/examples/enginio/enginio.pro new file mode 100644 index 0000000..eb699a0 --- /dev/null +++ b/examples/enginio/enginio.pro @@ -0,0 +1,8 @@ +TEMPLATE = subdirs + +qtHaveModule(widgets) { + SUBDIRS += widgets + qtHaveModule(quick) { + SUBDIRS += quick + } +} diff --git a/examples/enginio/quick/image-gallery/doc/images/image-gallery.png b/examples/enginio/quick/image-gallery/doc/images/image-gallery.png Binary files differnew file mode 100644 index 0000000..ed4cc1c --- /dev/null +++ b/examples/enginio/quick/image-gallery/doc/images/image-gallery.png diff --git a/examples/enginio/quick/image-gallery/doc/src/image-gallery.qdoc b/examples/enginio/quick/image-gallery/doc/src/image-gallery.qdoc new file mode 100644 index 0000000..56816b0 --- /dev/null +++ b/examples/enginio/quick/image-gallery/doc/src/image-gallery.qdoc @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ +/*! + \title Enginio QML Examples - Image Gallery + \example image-gallery + \brief This is an example that demonstrates uploading and downloading of files in Enginio. + \ingroup enginio-examples + \inmodule enginio-qml + + The user interface is a list of images with their meta-information + and a button to upload more images. + \image image-gallery.png + + \section1 Backend configuration + The Enginio backend needs to be set up to get this example working. + + Go to the Enginio Dashboard and create a new backend with 'Image Gallery' template. + + The template will construct a new custom backend by executing steps: + \list + \li Create a new object type "objects.image" (on the Object Types page). + + Add two properties to the image object: + name:"name", type: "String" and name: "file", type: "Ref" with target "files". + + \li Add a file processor by clicking the "file" property. + Choose "Image processor" and in "Variants" enter: + \code + { + "thumbnail": { "crop":"100x100" } + } + \endcode + This JSON snippet triggers the server to generate thumbnails for all uploaded images. + In the image gallery, the thumbnails will be used in the list view. The full image will be shown + when the thumbnail is clicked. + \endlist + + Copy the backend Id from the Enginio dashboard. + They need to be entered into the example when it is executed for the first time. + + \section1 The example code + + The first step is to set up the \l Enginio1::EnginioClient client. + \snippet image-gallery/image-gallery.qml client + + The model gets initialized with the client declared above. + \snippet image-gallery/image-gallery.qml model + + A delegate is needed to present the images nicely. + The model is used to get the list of image objects, but the images + are only attached to the objects as file references. + Thus the image's thumbnail is fetched by each delegate. + \note in a real application it might be necessary to cache the images. + + The Component.onCompleted function is used to fetch the image. + When the delegate is created, it has the JSON image object data. + The information needed is the "file.id" reference. + The "file" property was introduced in the backend setup section. Every + object (files are just objects) contains an ID that uniquely identifies the image file. + The image's thumbnail-url is retrieved using the ID ("variant": "thumbnail"). + \snippet image-gallery/image-gallery.qml image-fetch + + The meta-information about each image is displayed in simple Text elements. + For the filename, it is possible to directly reference the \c name property as + defined in the JSON. + \qml + Text { text: name } + \endqml + +*/ diff --git a/examples/enginio/quick/image-gallery/gallery.qrc b/examples/enginio/quick/image-gallery/gallery.qrc new file mode 100644 index 0000000..35ad914 --- /dev/null +++ b/examples/enginio/quick/image-gallery/gallery.qrc @@ -0,0 +1,16 @@ +<RCC> + <qresource prefix="/"> + <file>image-gallery.qml</file> + </qresource> + <qresource prefix="/icons"> + <file alias="delete_icon.png">../../common/icons/delete_icon.png</file> + <file alias="add_icon.png">../../common/icons/add_icon.png</file> + <file alias="add_icon_pressed.png">../../common/icons/add_icon_pressed.png</file> + <file alias="delete_icon_pressed.png">../../common/icons/delete_icon_pressed.png</file> + </qresource> + <qresource prefix="/images"> + <file alias="delegate.png">../../common/images/delegate.png</file> + <file alias="delegate_pressed.png">../../common/images/delegate_pressed.png</file> + <file alias="shadow.png">../../common/images/shadow.png</file> + </qresource> +</RCC> diff --git a/examples/enginio/quick/image-gallery/image-gallery.pro b/examples/enginio/quick/image-gallery/image-gallery.pro new file mode 100644 index 0000000..7cac108 --- /dev/null +++ b/examples/enginio/quick/image-gallery/image-gallery.pro @@ -0,0 +1,15 @@ +TEMPLATE = app + +DEFINES += ENGINIO_SAMPLE_NAME=\\\"image-gallery\\\" + +include(../../common/backendhelper/qmlbackendhelper.pri) + +QT += quick qml enginio +SOURCES += ../main.cpp + +mac: CONFIG -= app_bundle + +OTHER_FILES += *.qml + +RESOURCES += \ + gallery.qrc diff --git a/examples/enginio/quick/image-gallery/image-gallery.qml b/examples/enginio/quick/image-gallery/image-gallery.qml new file mode 100644 index 0000000..2397083 --- /dev/null +++ b/examples/enginio/quick/image-gallery/image-gallery.qml @@ -0,0 +1,466 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 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.0 +import Enginio 1.0 + +import QtQuick.Dialogs 1.0 +import QtQuick.Controls 1.0 +import QtQuick.Layouts 1.0 + +/* + * Enginio image gallery example. + * + * Main window contains list of enginioModel on the backend and button for uploading + * new enginioModel. Image list contains image thumbnail (generated by Enginio + * backend) and some image metadata. Clicking list items downloads image file + * and displays it in dialog window. Clicking the red x deletes enginioModel from + * backend. + * + * In the backend enginioModel are represented as objects of type "objects.image". These + * objects contain a property "file" which is a reference to the actual binary file. + */ + +Item { + id: main + width: 460 + height: 640 + + BackendHelper{ + id: backendHelper + } + + property var imagesUrl: new Object + Rectangle { + id: root + anchors.fill: parent + opacity: 1 - backendHelper.opacity + color: "#f4f4f4" + + + // Enginio client specifies the backend to be used + //! [client] + EnginioClient { + id: client + backendId: backendHelper.backendId + onError: console.log("Enginio error: " + reply.errorCode + ": " + reply.errorString) + } + //! [client] + + //! [model] + EnginioModel { + id: enginioModel + client: client + query: { // query for all objects of type "objects.image" and include not null references to files + "objectType": "objects.image", + "include": {"file": {}}, + "query" : { "file": { "$ne": null } } + } + } + //! [model] + + // Delegate for displaying individual rows of the model + Component { + id: imageListDelegate + + BorderImage { + height: 120 + width: parent.width + border.top: 4 + border.bottom: 4 + source: hitbox.pressed ? "qrc:images/delegate_pressed.png" : "qrc:images/delegate.png" + + Image { + id: shadow + anchors.top: parent.bottom + width: parent.width + visible: !hitbox.pressed + source: "qrc:images/shadow.png" + } + + //! [image-fetch] + Image { + id: image + x: 10 + width: 100 + height: 100 + anchors.verticalCenter: parent.verticalCenter + opacity: image.status == Image.Ready ? 1 : 0 + Behavior on opacity { NumberAnimation { duration: 100 } } + Component.onCompleted: { + if (id in imagesUrl) { + image.source = imagesUrl[id] + } else { + var data = { "id": file.id, + "variant": "thumbnail"} + var reply = client.downloadUrl(data) + reply.finished.connect(function() { + imagesUrl[id] = reply.data.expiringUrl + if (image && reply.data.expiringUrl) // It may be deleted as it is delegate + image.source = reply.data.expiringUrl + }) + } + } + } + Rectangle { + color: "transparent" + anchors.fill: image + border.color: "#aaa" + Rectangle { + id: progressBar + property real value: image.progress + anchors.bottom: parent.bottom + width: image.width * value + height: 4 + color: "#49f" + opacity: image.status != Image.Ready ? 1 : 0 + Behavior on opacity {NumberAnimation {duration: 100}} + } + } + //! [image-fetch] + + Column { + anchors.left: image.right + anchors.right: deleteIcon.left + anchors.margins: 12 + y: 10 + Text { + height: 33 + width: parent.width + verticalAlignment: Text.AlignVCenter + font.pixelSize: height * 0.5 + text: name ? name : "" + elide: Text.ElideRight + } + Text { + height: 33 + width: parent.width + verticalAlignment: Text.AlignVCenter + font.pixelSize: height * 0.5 + text: sizeStringFromFile(file) + elide:Text.ElideRight + color: "#555" + } + Text { + height: 33 + width: parent.width + verticalAlignment: Text.AlignVCenter + font.pixelSize: height * 0.5 + text: timeStringFromFile(file) + elide:Text.ElideRight + color: "#555" + } + } + + // Clicking list item opens full size image in separate dialog + MouseArea { + id: hitbox + anchors.fill: parent + onClicked: { + imageDialog.fileId = file.id; + imageDialog.visible = true + root.state = "view" + } + } + + // Delete button + Image { + id: deleteIcon + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.rightMargin: 18 + source: removeMouseArea.pressed ?"qrc:icons/delete_icon_pressed.png" : "qrc:icons/delete_icon.png" + MouseArea { + id: removeMouseArea + anchors.fill: parent + anchors.margins: -10 + onClicked: enginioModel.remove(index) + } + } + } + } + + // A simple layout: + // a listview and a line edit with button to add to the list + Rectangle { + id: header + anchors.top: parent.top + width: parent.width + height: 70 + color: "white" + + Row { + id: logo + anchors.centerIn: parent + anchors.horizontalCenterOffset: -4 + spacing: 6 + Image { + source: "qrc:images/enginio.png" + width:160 ; height: 60 + fillMode:Image.PreserveAspectFit + } + Text { + text: "Gallery" + anchors.verticalCenter: parent.verticalCenter + anchors.verticalCenterOffset: -3 + font.bold: true + font.pixelSize: 46 + color: "#555" + } + } + Rectangle { + width: parent.width ; height: 1 + anchors.bottom: parent.bottom + color: "#bbb" + } + } + + Row { + id: listLayout + + Behavior on x {NumberAnimation{ duration: 400 ; easing.type: "InOutCubic"}} + anchors.top: header.bottom + anchors.bottom: footer.top + + ListView { + id: imageListView + model: enginioModel // get the data from EnginioModel + delegate: imageListDelegate + clip: true + width: root.width + height: parent.height + // Animations + add: Transition { NumberAnimation { properties: "y"; from: root.height; duration: 250 } } + removeDisplaced: Transition { NumberAnimation { properties: "y"; duration: 150 } } + remove: Transition { NumberAnimation { property: "opacity"; to: 0; duration: 150 } } + } + + // Dialog for showing full size image + Rectangle { + id: imageDialog + width: root.width + height: parent.height + property string fileId + color: "#333" + + onFileIdChanged: { + image.source = "" + // Download the full image, not the thumbnail + var data = { "id": fileId } + var reply = client.downloadUrl(data) + reply.finished.connect(function() { + image.source = reply.data.expiringUrl + }) + } + Label { + id: label + text: "Loading ..." + font.pixelSize: 28 + color: "white" + anchors.centerIn: parent + visible: image.status != Image.Ready + } + Rectangle { + property real value: image.progress + anchors.bottom: parent.bottom + width: parent.width * value + height: 4 + color: "#49f" + Behavior on opacity {NumberAnimation {duration: 200}} + opacity: image.status !== Image.Ready ? 1 : 0 + } + Image { + id: image + anchors.fill: parent + anchors.margins: 10 + smooth: true + cache: false + fillMode: Image.PreserveAspectFit + Behavior on opacity { NumberAnimation { duration: 100 } } + opacity: image.status === Image.Ready ? 1 : 0 + } + MouseArea { + anchors.fill: parent + onClicked: root.state = "" + } + } + } + + BorderImage { + id: footer + + width: parent.width + anchors.bottom: parent.bottom + source: addMouseArea.pressed ? "qrc:images/delegate_pressed.png" : "qrc:images/delegate.png" + border.left: 5; border.top: 5 + border.right: 5; border.bottom: 5 + + Rectangle { + y: -1 ; height: 1 + width: parent.width + color: "#bbb" + } + Rectangle { + y: 0 ; height: 1 + width: parent.width + color: addMouseArea.pressed ? "transparent" : "white" + } + + //![append] + + Text { + text: "Click to upload..." + font.bold: true + font.pixelSize: 28 + color: "#444" + anchors.centerIn: parent + } + + Item { + id: addButton + width: 40 ; height: 40 + anchors.margins: 20 + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + Image { + id: removeIcon + source: addMouseArea.pressed ? "qrc:icons/add_icon_pressed.png" : "qrc:icons/add_icon.png" + anchors.centerIn: parent + } + } + + MouseArea { + id: addMouseArea + anchors.fill: parent + onClicked: fileDialog.visible = true; + } + Rectangle { + id: progressBar + property real value:0 + anchors.bottom: parent.bottom + width: parent.width * value + height: 4 + color: "#49f" + Behavior on opacity {NumberAnimation {duration: 100}} + } + } + + // File dialog for selecting image file from local file system + FileDialog { + id: fileDialog + title: "Select image file to upload" + nameFilters: [ "Image files (*.png *.jpg *.jpeg)", "All files (*)" ] + + onSelectionAccepted: { + var pathParts = fileUrl.toString().split("/"); + var fileName = pathParts[pathParts.length - 1]; + var fileObject = { + objectType: "objects.image", + name: fileName, + localPath: fileUrl.toString() + } + var reply = client.create(fileObject); + reply.finished.connect(function() { + var uploadData = { + file: { fileName: fileName }, + targetFileProperty: { + objectType: "objects.image", + id: reply.data.id, + propertyName: "file" + }, + }; + + imagesUrl[reply.data.id] = reply.data.localPath + + var uploadReply = client.uploadFile(uploadData, fileUrl) + progressBar.opacity = 1 + uploadReply.progress.connect(function(progress, total) { + progressBar.value = progress/total + }) + uploadReply.finished.connect(function() { + var tmp = enginioModel.query; enginioModel.query = null; enginioModel.query = tmp; + progressBar.opacity = 0 + }) + }) + } + } + + states: [ + State { + name: "view" + PropertyChanges { + target: listLayout + x: -root.width + } + } + ] + } + function sizeStringFromFile(fileData) { + var str = []; + if (fileData && fileData.fileSize) { + str.push("Size: "); + str.push(fileData.fileSize); + str.push(" bytes"); + } + return str.join(""); + } + + function doubleDigitNumber(number) { + if (number < 10) + return "0" + number; + return number; + } + + function timeStringFromFile(fileData) { + var str = []; + if (fileData && fileData.createdAt) { + var date = new Date(fileData.createdAt); + if (date) { + str.push("Uploaded: "); + str.push(date.toDateString()); + str.push(" "); + str.push(doubleDigitNumber(date.getHours())); + str.push(":"); + str.push(doubleDigitNumber(date.getMinutes())); + } + } + return str.join(""); + } +} diff --git a/examples/enginio/quick/image-gallery/image_gallery80.png b/examples/enginio/quick/image-gallery/image_gallery80.png Binary files differnew file mode 100644 index 0000000..6ad8096 --- /dev/null +++ b/examples/enginio/quick/image-gallery/image_gallery80.png diff --git a/examples/enginio/quick/main.cpp b/examples/enginio/quick/main.cpp new file mode 100644 index 0000000..7356a7a --- /dev/null +++ b/examples/enginio/quick/main.cpp @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 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$ +** +****************************************************************************/ + +#include <QGuiApplication> +#include <QQmlEngine> +#include <QQmlContext> +#include <QQuickView> +#include <QDir> +#include <QSettings> + +static QString backendIdKey = QStringLiteral("backendId"); + +class BackendHelperContext : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString exampleName READ exampleName CONSTANT) + Q_PROPERTY(QString backendId READ backendId WRITE setBackendId NOTIFY backendIdChanged) + + QString _backendId; + QScopedPointer<QSettings> _settings; + static QString _exampleName; + +public: + BackendHelperContext(QQuickView *parent) + : QObject(parent) + { + QString fileName = QStringLiteral("EnginioExamples.conf"); + for (int i = 0; i < 4; ++i) { + if (QFile::exists(fileName)) + break; + fileName = fileName.prepend("../"); + } + + QFileInfo settingsFile = QFileInfo(fileName); + _settings.reset(settingsFile.exists() + ? new QSettings(settingsFile.absoluteFilePath(), QSettings::IniFormat) + : new QSettings("com.digia", "EnginioExamples")); + + _settings->beginGroup(_exampleName); + _backendId = _settings->value(backendIdKey).toString(); + } + + ~BackendHelperContext() + { + _settings->setValue(backendIdKey, _backendId); + _settings->endGroup(); + _settings->sync(); + } + + QString backendId() const { return _backendId; } + void setBackendId(const QString &backendId) + { + if (_backendId == backendId) + return; + _backendId = backendId; + emit backendIdChanged(); + } + + QString exampleName() const { return _exampleName; } +signals: + void backendIdChanged(); +}; +QString BackendHelperContext::_exampleName = ENGINIO_SAMPLE_NAME; + +int main(int argc, char* argv[]) +{ + QGuiApplication app(argc,argv); + QQuickView view; + const QString appPath = QCoreApplication::applicationDirPath(); + + // This allows starting the example without previously defining QML2_IMPORT_PATH. + QDir qmlImportDir(appPath); +#if defined (Q_OS_WIN) + qmlImportDir.cd(".."); +#endif + qmlImportDir.cd("../../../qml"); + view.engine()->addImportPath(qmlImportDir.canonicalPath()); + QObject::connect(view.engine(), SIGNAL(quit()), &app, SLOT(quit())); + + BackendHelperContext *backendContext = new BackendHelperContext(&view); + + view.engine()->rootContext()->setContextProperty("enginioBackendContext", backendContext); + + view.setSource(QUrl("qrc:///" ENGINIO_SAMPLE_NAME ".qml")); + view.setResizeMode(QQuickView::SizeRootObjectToView); + view.show(); + return app.exec(); +} + +#include "main.moc" diff --git a/examples/enginio/quick/quick.pro b/examples/enginio/quick/quick.pro new file mode 100644 index 0000000..6433bbc --- /dev/null +++ b/examples/enginio/quick/quick.pro @@ -0,0 +1,7 @@ +TEMPLATE = subdirs + +SUBDIRS += \ + image-gallery \ + socialtodos \ + todos \ + users \ diff --git a/examples/enginio/quick/socialtodos/Header.qml b/examples/enginio/quick/socialtodos/Header.qml new file mode 100644 index 0000000..ac2d0f4 --- /dev/null +++ b/examples/enginio/quick/socialtodos/Header.qml @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtEnginio 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.1 + +Rectangle { + property alias text: t.text + property int rightMargin: 0 + + anchors.top: parent.top + width: parent.width + height: 70 * scaleFactor + color: "white" + + Item { + height: parent.height + width: parent.height + id: backButton + Image { + anchors.centerIn: parent + width: implicitWidth * scaleFactor + height: implicitHeight * scaleFactor + source: "qrc:icons/back_icon.png" + MouseArea { + anchors.fill: parent + anchors.margins: - 10 + onClicked: mainView.pop() + } + } + } + Text { + id: t + anchors.left: backButton.right + anchors.leftMargin: 10 * scaleFactor + anchors.right: parent.right + anchors.rightMargin: rightMargin + anchors.verticalCenter: parent.verticalCenter + anchors.verticalCenterOffset: -3 + elide: Text.ElideMiddle + font.bold: true + font.pixelSize: 36 * scaleFactor + color: "#555" + } + Rectangle { + width: parent.width; height: 1 + anchors.bottom: parent.bottom + color: "#bbb" + } +} diff --git a/examples/enginio/quick/socialtodos/List.qml b/examples/enginio/quick/socialtodos/List.qml new file mode 100644 index 0000000..9a4d6ed --- /dev/null +++ b/examples/enginio/quick/socialtodos/List.qml @@ -0,0 +1,239 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtEnginio 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.0 +import Enginio 1.0 + +Rectangle { + id: root + width: 400 + height: 640 + color: "#f4f4f4" + + property string listId + property string listName + property string listCreator + + EnginioModel { + id: enginioModel + client: enginioClient + query: {"objectType": "objects.todos", + "query": { "todoList": { "id": listId, "objectType": "objects.todoLists" } } + } + } + + Header { + id: header + text: listName + rightMargin: icon.width + + Item { + id: icon + height: parent.height + width: parent.height + anchors.right: parent.right + Image { + id: shareButton + anchors.centerIn: parent + source: mouse.pressed ? "qrc:icons/share_icon_pressed.png" : "qrc:icons/share_icon.png" + width: implicitWidth * scaleFactor + height: implicitHeight * scaleFactor + MouseArea { + id: mouse + anchors.fill: parent + onClicked: mainView.push({ item: shareItem, properties: { listId: listId, listName: listName }} ) + } + } + } + } + + Component { + id: shareItem + ShareDialog {} + } + + ListView { + id: listview + model: enginioModel + delegate: listItemDelegate + anchors.top: header.bottom + anchors.bottom: footer.top + width: parent.width + clip: true + + // Animations + add: Transition { NumberAnimation { properties: "y"; from: root.height; duration: 250 } } + removeDisplaced: Transition { NumberAnimation { properties: "y"; duration: 150 } } + remove: Transition { NumberAnimation { property: "opacity"; to: 0; duration: 150 } } + } + + BorderImage { + id: footer + + height: 70 * scaleFactor + width: parent.width + anchors.bottom: parent.bottom + source: "qrc:images/delegate.png" + border.left: 5; border.top: 5 + border.right: 5; border.bottom: 5 + + Rectangle { + y: -1 ; height: 1 + width: parent.width + color: "#bbb" + } + Rectangle { + y: 0 ; height: 1 + width: parent.width + color: "white" + } + + TextField { + id: textInput + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.right: addButton.left + anchors.margins: 16 * scaleFactor + placeholderText: "New todo..." + onAccepted: { + enginioModel.append({"title": textInput.text, "done": false, "todoList": { "id": listId, "objectType": "objects.todoLists" } } ) + textInput.text = "" + } + } + + Item { + id: addButton + + width: 40 * scaleFactor + height: 40 * scaleFactor + anchors.margins: 20 * scaleFactor + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + enabled: textInput.text.length + Image { + width: implicitWidth * scaleFactor + height: implicitHeight * scaleFactor + source: addMouseArea.pressed ? "qrc:icons/add_icon_pressed.png" : "qrc:icons/add_icon.png" + anchors.centerIn: parent + opacity: enabled ? 1 : 0.5 + } + MouseArea { + id: addMouseArea + anchors.fill: parent + onClicked: textInput.accepted() + } + } + } + + Component { + id: listItemDelegate + + BorderImage { + id: item + + width: parent.width ; height: 70 * scaleFactor + source: mouse.pressed ? "qrc:images/delegate_pressed.png" : "qrc:images/delegate.png" + border.left: 5; border.top: 5 + border.right: 5; border.bottom: 5 + + Image { + id: shadow + anchors.top: parent.bottom + width: parent.width + visible: !mouse.pressed + source: "qrc:images/shadow.png" + } + + MouseArea { + id: mouse + anchors.fill: parent + hoverEnabled: true + onClicked: { + if (index !== -1 && _synced) { + enginioModel.setProperty(index, "done", !done) + } + } + } + Image { + id: checkbox + anchors.left: parent.left + anchors.leftMargin: 16 * scaleFactor + height: width + width: 32 * scaleFactor + fillMode: Image.PreserveAspectFit + anchors.verticalCenter: parent.verticalCenter + source: done ? "qrc:images/checkmark.png" : "" + } + + Text { + id: todoText + text: title + font.pixelSize: 26 * scaleFactor + color: "#333" + + anchors.verticalCenter: parent.verticalCenter + anchors.left: checkbox.right + anchors.right: parent.right + anchors.leftMargin: 16 * scaleFactor + anchors.rightMargin: 40 * scaleFactor + elide: Text.ElideRight + } + + // Show a delete button when the mouse is over the delegate + Image { + id: removeIcon + + source: removeMouseArea.pressed ? "qrc:icons/delete_icon_pressed.png" : "qrc:icons/delete_icon.png" + width: implicitWidth * scaleFactor + height: implicitHeight * scaleFactor + anchors.margins: 20 * scaleFactor + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + opacity: enabled ? 1 : 0.5 + Behavior on opacity {NumberAnimation{duration: 100}} + MouseArea { + id: removeMouseArea + anchors.fill: parent + onClicked: enginioModel.remove(index) + } + } + } + } +} diff --git a/examples/enginio/quick/socialtodos/Login.qml b/examples/enginio/quick/socialtodos/Login.qml new file mode 100644 index 0000000..3211d31 --- /dev/null +++ b/examples/enginio/quick/socialtodos/Login.qml @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtEnginio 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.1 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.0 as Controls +import Enginio 1.0 + +Rectangle { + width: 400 + height: 600 + + Rectangle { + id: header + anchors.top: parent.top + width: parent.width + height: 70 * scaleFactor + color: "white" + + Row { + id: logo + anchors.centerIn: parent + anchors.horizontalCenterOffset: -4 + spacing: 4 + Image { + source: "qrc:images/enginio.png" + width: 160 * scaleFactor ; height: 60 * scaleFactor + fillMode: Image.PreserveAspectFit + } + Text { + text: "Todos" + anchors.verticalCenter: parent.verticalCenter + anchors.verticalCenterOffset: -3 + font.bold: true + font.pixelSize: 46 * scaleFactor + color: "#555" + } + } + Rectangle { + width: parent.width ; height: 1 + anchors.bottom: parent.bottom + color: "#bbb" + } + } + + BorderImage { + id: input + + width: parent.width + anchors.top: header.bottom + anchors.bottom: parent.bottom + source: "qrc:images/delegate.png" + border.left: 5; border.top: 5 + border.right: 5; border.bottom: 5 + + Rectangle { + y: -1 ; height: 1 + width: parent.width + color: "#bbb" + } + Rectangle { + y: 0 ; height: 1 + width: parent.width + color: "white" + } + } + + Column { + anchors.centerIn: parent + anchors.alignWhenCentered: true + width: 360 * scaleFactor + spacing: 14 * intScaleFactor + + TextField { + id: nameInput + onAccepted: passwordInput.forceActiveFocus() + placeholderText: "Username" + } + + TextField { + id: passwordInput + onAccepted: login() + placeholderText: "Password" + echoMode: TextInput.Password + } + + Row { + // button + spacing: 20 * scaleFactor + width: 360 * scaleFactor + anchors.horizontalCenter: parent.horizontalCenter + anchors.alignWhenCentered: true + TouchButton { + text: "Login" + baseColor: "#7a5" + width: (parent.width - parent.spacing)/2 + onClicked: login() + enabled: enginioClient.authenticationState !== Enginio.Authenticating && nameInput.text.length && passwordInput.text.length + } + TouchButton { + text: "Register" + onClicked: register() + width: (parent.width - parent.spacing)/2 + enabled: enginioClient.authenticationState !== Enginio.Authenticating && nameInput.text.length && passwordInput.text.length + } + } + } + + Text { + id: statusText + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottomMargin: 70 * scaleFactor + font.pixelSize: 18 * scaleFactor + color: "#444" + } + + Component.onCompleted: + enginioClient.sessionAuthenticationError.connect(function(reply){ + if (enginioClient.authenticationState === Enginio.AuthenticationFailure) + statusText.text = "Authentication failed: " + reply.errorString + } + ) + + Controls.Stack.onStatusChanged: { + if (Controls.Stack.status == Controls.Stack.Activating) { + nameInput.text = "" + passwordInput.text = "" + nameInput.forceActiveFocus() + } + } + + EnginioOAuth2Authentication { id: noAuth } + + function login() { + statusText.text = "Logging in..." + enginioClient.identity = noAuth + auth.user = nameInput.text + auth.password = passwordInput.text + enginioClient.identity = auth + } + + // Register a new user and add her to the group "myUsers" + function register() { + statusText.text = "Creating user account..." + var createAccount = enginioClient.create({ "username": nameInput.text, "password": passwordInput.text }, Enginio.UserOperation) + createAccount.finished.connect(function() { + if (createAccount.errorType !== EnginioReply.NoError) { + statusText.text = createAccount.errorString + } else { + //![queryUsergroup] + var groupQuery = enginioClient.query({ "query": { "name" : "myUsers" } }, Enginio.UsergroupOperation) + //![queryUsergroup] + + groupQuery.finished.connect(function() + { + if (groupQuery.errorType !== EnginioReply.NoError) { + statusText.text = groupQuery.errorString + } else { + var addUserToGroupData = { + "id": groupQuery.data.results[0].id, + "member" : { + "id": createAccount.data.id, + "objectType": "users" + } + } + var addUserToGroup = enginioClient.create(addUserToGroupData, Enginio.UsergroupMembersOperation) + addUserToGroup.finished.connect(function() + { + if (addUserToGroup.errorType !== EnginioReply.NoError) { + statusText.text = addUserToGroup.errorString + } else { + statusText.text = "Account Created." + login() + } + }) + } + }) + } + }) + } +} diff --git a/examples/enginio/quick/socialtodos/ShareDialog.qml b/examples/enginio/quick/socialtodos/ShareDialog.qml new file mode 100644 index 0000000..d9daa07 --- /dev/null +++ b/examples/enginio/quick/socialtodos/ShareDialog.qml @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtEnginio 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.1 +import QtQuick.Controls 1.0 +import Enginio 1.0 + +Rectangle { + property string listId + property string listName + property var aclData + + property var userNames: new Array + property var userData: new Object + + Component.onCompleted: { + var aclQuery = enginioClient.query({ "objectType": "objects.todoLists", "id": listId }, Enginio.AccessControlOperation) + aclQuery.finished.connect(function() { aclData = aclQuery.data } ) + + var usersQuery = enginioClient.query({ "objectType": "users", }, Enginio.UsersOperation) + usersQuery.finished.connect(function() { + var userNamesTmp = new Array + for (var i = 0; i < usersQuery.data.results.length; ++i) { + var user = usersQuery.data.results[i] + userNamesTmp.push(user["username"]) + userData[user["username"]] = user + } + + userNames = userNamesTmp + } ) + } + + Header { + id: header + text: "Share " + listName + } + + ListView { + id: nameView + model: userNames + anchors.top: header.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + + delegate: BorderImage { + id: item + + width: parent.width ; height: 40 * scaleFactor + source: mouse.pressed ? "qrc:images/delegate_pressed.png" : "qrc:images/delegate.png" + border.left: 5; border.top: 5 + border.right: 5; border.bottom: 5 + + Image { + id: shadow + anchors.top: parent.bottom + width: parent.width + visible: !mouse.pressed + source: "qrc:images/shadow.png" + } + + Item { + id: checkBox + height: 40 * scaleFactor + width: 42 * scaleFactor + Image { + anchors.centerIn: parent + fillMode: Image.PreserveAspectFit + source: sharedWithUser(userData[modelData].id) ? "qrc:images/checkmark.png" : "" + } + } + Text { + anchors.left: checkBox.right + anchors.verticalCenter: parent.verticalCenter + text: modelData + font.pixelSize: 22 * scaleFactor + } + + MouseArea { + anchors.fill: parent + onClicked: { + var id = userData[modelData].id + aclData["read"].push({ "id": id, "objectType": "users" }) + aclData["admin"].push({ "id": id, "objectType": "users" }) + console.log("\nUpdated JSON:", JSON.stringify(aclData)) + enginioClient.update( + { "id": listId, "objectType": "objects.todoLists", "access": aclData }, + Enginio.AccessControlOperation + ) + + // changing the contents of a JSON object does not emit + // the update signal for performance reasons + aclDataChanged() + } + } + } + } + + function sharedWithUser(userId) { + for (var i = 0; i < aclData["read"].length; ++i) + if (aclData["read"][i]["id"] === userId) + return true; + return false; + } +} diff --git a/examples/enginio/quick/socialtodos/TextField.qml b/examples/enginio/quick/socialtodos/TextField.qml new file mode 100644 index 0000000..372ec82 --- /dev/null +++ b/examples/enginio/quick/socialtodos/TextField.qml @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtEnginio 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.1 + +FocusScope { + id: textfield + + property alias text: textInput.text + property alias placeholderText: placeholder.text + property alias echoMode: textInput.echoMode + signal accepted + + activeFocusOnTab: true + + implicitHeight: Math.round(40 * scaleFactor) + implicitWidth: Math.round(parent.width) + + Rectangle { + anchors.fill: editbg + radius: editbg.radius + color: "#aaffffff" + anchors.bottomMargin: -1 + } + + Rectangle { + id: editbg + anchors.fill: parent + radius: height/2 + border.width: intScaleFactor + border.color: "#999" + + gradient: Gradient { + GradientStop {color: "#eee" ; position: 0} + GradientStop {color: "white" ; position: 0.1} + GradientStop {color: "white" ; position: 1} + } + + TextInput{ + id: textInput + anchors.fill: parent + clip: true + anchors.leftMargin: 16 * scaleFactor + anchors.rightMargin: 16 * scaleFactor + verticalAlignment: Text.AlignVCenter + font.pixelSize: 22 * scaleFactor + focus: true + onAccepted: textfield.accepted() + Text { + id: placeholder + anchors.fill: parent + verticalAlignment: Text.AlignVCenter + visible: !(parent.text.length || textInput.inputMethodComposing) + font: parent.font + color: "#aaa" + } + } + } + + onAccepted: { + Qt.inputMethod.commit(); + Qt.inputMethod.hide(); + } +} + diff --git a/examples/enginio/quick/socialtodos/TodoLists.qml b/examples/enginio/quick/socialtodos/TodoLists.qml new file mode 100644 index 0000000..40e36c2 --- /dev/null +++ b/examples/enginio/quick/socialtodos/TodoLists.qml @@ -0,0 +1,224 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtEnginio 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.1 +import QtQuick.Layouts 1.0 +import Enginio 1.0 + +Rectangle { + property string username + + width: parent.width + height: parent.height + + EnginioModel { + id: enginioModel + client: enginioClient + query: { + "objectType" : "objects.todoLists", + "include": { "creator": {} } + } + } + + Header { + id: header + text: "My Lists" + Item { + id: icon + height: parent.height + width: parent.height + anchors.right: parent.right + Image { + id: reloadButton + anchors.centerIn: parent + source: mouse.pressed ? "qrc:icons/reload_icon_pressed.png" : "qrc:icons/reload_icon.png" + width: implicitWidth * scaleFactor + height: implicitHeight * scaleFactor + MouseArea { + id: mouse + anchors.fill: parent + onClicked: { + var q = enginioModel.query + enginioModel.query = { "objectType": "objects.invalid" } + enginioModel.query = q + } + } + } + } + } + + ListView { + id: list + model: enginioModel + delegate: listDelegate + + anchors.top: header.bottom + width: parent.width + height: parent.height - 140 * scaleFactor + } + + BorderImage { + anchors.top: list.bottom + anchors.bottom: parent.bottom + width: parent.width + height: 70 * scaleFactor + + source: "qrc:images/delegate.png" + border.left: 5; border.top: 5 + border.right: 5; border.bottom: 5 + + Rectangle { + y: -1 ; height: 1 + width: parent.width + color: "#bbb" + } + Rectangle { + y: 0 ; height: 1 + width: parent.width + color: "white" + } + + TextField { + id: textInput + anchors.left: parent.left + anchors.right: addButton.left + anchors.verticalCenter: parent.verticalCenter + anchors.margins: 16 * scaleFactor + placeholderText: "New list..." + onAccepted: { + enginioModel.append({"name": textInput.text} ) + textInput.text = "" + } + + } + + Item { + id: addButton + + width: 40 * scaleFactor + height: 40 * scaleFactor + anchors.margins: 20 * scaleFactor + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + enabled: textInput.text.length + Image { + source: addMouseArea.pressed ? "qrc:icons/add_icon_pressed.png" : "qrc:icons/add_icon.png" + width: implicitWidth * scaleFactor + height: implicitHeight * scaleFactor + anchors.centerIn: parent + opacity: enabled ? 1 : 0.5 + } + MouseArea { + id: addMouseArea + anchors.fill: parent + onClicked: textInput.accepted() + } + } + } + + + Component { + id: todoListView + List {} + } + + Component { + id: listDelegate + BorderImage { + id: item + + width: parent.width ; height: 70 * scaleFactor + source: mouse.pressed ? "qrc:images/delegate_pressed.png" : "qrc:images/delegate.png" + border.left: 5; border.top: 5 + border.right: 5; border.bottom: 5 + + Image { + id: shadow + anchors.top: parent.bottom + width: parent.width + visible: !mouse.pressed + source: "qrc:images/shadow.png" + } + + MouseArea { + id: mouse + anchors.fill: parent + hoverEnabled: true + onClicked: { + mainView.push({item: todoListView, properties: {listId: id, listName: name, listCreator: ((model["creator"] && creator.username) ? creator.username : username)}}) + } + } + + Text { + id: todoText + text: name + " by " + ((model["creator"] && creator.username) ? creator.username : username) + font.pixelSize: 26 * scaleFactor + color: "#333" + + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: 16 * scaleFactor + anchors.rightMargin: 60 * scaleFactor + elide: Text.ElideRight + } + + // Show a delete button when the mouse is over the delegate + Image { + id: removeIcon + + source: removeMouseArea.pressed ? "qrc:icons/delete_icon_pressed.png" : "qrc:icons/delete_icon.png" + anchors.margins: 20 * scaleFactor + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + opacity: enabled ? 1 : 0.5 + width: implicitWidth * scaleFactor + height: implicitHeight * scaleFactor + Behavior on opacity {NumberAnimation{duration: 100}} + MouseArea { + id: removeMouseArea + anchors.fill: parent + onClicked: enginioModel.remove(index) + } + } + } + } +} + diff --git a/examples/enginio/quick/socialtodos/TouchButton.qml b/examples/enginio/quick/socialtodos/TouchButton.qml new file mode 100644 index 0000000..b148c89 --- /dev/null +++ b/examples/enginio/quick/socialtodos/TouchButton.qml @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtEnginio 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.1 + +Item { + id: button + signal clicked + property alias text: label.text + property color baseColor: "#555" + property color textColor: "#fff" + height: Math.round(40 * scaleFactor) + width: Math.round(160 * scaleFactor) + activeFocusOnTab: true + + + Rectangle { + anchors.fill: button + color: "#ffffff" + anchors.bottomMargin: intScaleFactor + radius: background.radius + } + + Keys.onReturnPressed: clicked() + + Rectangle { + id: background + opacity: enabled ? 1 : 0.7 + Behavior on opacity {NumberAnimation{}} + radius: height/2 + border.width: intScaleFactor * button.activeFocus ? 2 : 1 + border.color: Qt.darker(baseColor, 1.4) + anchors.fill: parent + gradient: Gradient { + GradientStop { color: mousearea.pressed ? baseColor : Qt.lighter(baseColor, 1.4) ; position: 0 } + GradientStop { color: baseColor ; position: 1 } + } + + Text { + id: label + anchors.centerIn: parent + font.pixelSize: 22 * scaleFactor + font.bold: true + color: textColor + style: Text.Raised + styleColor: "#44000000" + } + + MouseArea { + id: mousearea + onClicked: button.clicked() + anchors.fill: parent + } + } +} diff --git a/examples/enginio/quick/socialtodos/backendconfig/sharedtodo.zip b/examples/enginio/quick/socialtodos/backendconfig/sharedtodo.zip Binary files differnew file mode 100644 index 0000000..e13e388 --- /dev/null +++ b/examples/enginio/quick/socialtodos/backendconfig/sharedtodo.zip diff --git a/examples/enginio/quick/socialtodos/doc/src/socialtodos.qdoc b/examples/enginio/quick/socialtodos/doc/src/socialtodos.qdoc new file mode 100644 index 0000000..0699895 --- /dev/null +++ b/examples/enginio/quick/socialtodos/doc/src/socialtodos.qdoc @@ -0,0 +1,421 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ +/*! +\title Enginio QML Examples - Social Todos +\example socialtodos +\brief Social Todos is a todo list application with a social twist, +demonstrating the user management and access control features of Enginio. +\ingroup enginio-examples +\inmodule enginio-qml + + +\section1 Introduction + +Social Todos is a simple todo list application with a social twist, demonstrating the user management and access control features of the Enginio service. +The application allows the end-user to register a new user account, log in, and create and delete task lists, manage tasks on those lists and share lists with selected other users. + +The application data is modeled as \e {todo items} and \e {todo lists}. +\list + \li A \e {todo item} represents a single tasks which needs to be done. + Todo item contais a textual description of the task and a boolean status flag telling whether the task is completed or not. + \li A \e {todo list} represents a list of tasks. + Todo list contains zero or more todo items and each todo item belongs to just one todo list. + Todo lists are created by the application end-users and by default only the user who created a list can access it and its todo items. + However, the creator can share the list with other users. +\endlist + +The Social Todos example uses the following Enginio features: +\div {class="qt-enginio-example-2-col-desc-table"} + \table + \row + \li \b {User management with integrated Enginio accounts} + \li Enables end-users to register and login. + End-users are identified by user-name and password. + \row + \li \b {Object storage} + \li Provides shared persistent storage for task lists and tasks. + \row + \li \b {Data validation} + \li Enforces required data structure for task lists and tasks. + \row + \li \b {Access control mechanisms} + \li Restricts access to application data so that it is available only to authenticated (logged-in) end-users. + End-users can see and manipulate only those task lists and tasks which they are entitled to. + \endtable +\enddiv + + +To get the Social Todos application working correctly you will need to: +\list 1 + \li Create a new application backend via \l {https://dashboard.engin.io} {Enginio Dashboard}. + \li Configure the backend as instructed in the \l {Configure Backend} section. + \li And then run the application as explained in the \l {Configure and Run QML Application} section. + \li Finally you can check the QML application details in \l {QML Application Walk-through}. +\endlist + + +\section1 Configure Backend + +This section presents steps for configuring a fresh Enginio Backend for the Social Todos example. +A big part of the backend configuration is related to restricting who can create and access the application data. + +\div {class="qt-enginio-example-2-col-desc-table"} + \table + \row + \li \b {Data creation controls} + \li Todo list and todo item creation is allowed for registered application users only. + The protection is based on having a single usergroup (group name 'allUsers') in the backend configuration. + Todo list and todo item creation rights are granted to members of this group. + Application users are added to this usergroup when they use the QML application. + + For built-in users and usergroups the creation control is handled slightly differently. + New users can be freely created, anyone can register to use the application. + Usergroups creation is completely blocked, since the application uses just one fixed usergroup. + + \row + \li \b {Data access controls} + \li To todo lists and todo items the data access (and manipulation) is allowed only for logged-in users. + By default only the user who creates the todo list can access the list and its todo items. + + However, the creator can share the list with other users. + List sharing happens by granting to selected other users right to access the list. + + Access permissions are explicitly managed only for todo lists. + Todo items are configured to inherit permissions from the todo list which they belong to. + + For user objects, the access is allowed only to logged-in users which are members of 'allUsers' usergroup. + + For usergroups objects, the access is allowed so that everyone can see the single fixed 'allUsers' usergroup. + \endtable +\enddiv + + + +\section2 1. Create 'allUsers' Usergroup + +Create a new usergroup \c {allUsers}. +The usergroup will be used to restrict that only registered application end-users can store new todo lists and items to backend. +The usergroup itself is secured with suitable data access permissions. + + +First create the usergroup: +\list + \li In the Dashboard: Select \b {Usergroups}, click \b {Add}, enter name \c {allUsers} for the usergroup, and select \b {Save}. +\endlist + + +Then secure the usergroup by configuring suitable permission settings: +\list + \li In the Dashboard: Open \b {allUsers} usergroup for editing, apply the configurations below, and finally select \b {Save} in usergroup editor. +\endlist + + +\div {class="qt-enginio-example-3-col-conf-table"} + \table + \header + \li Setting area + \li Required configurations + \li + \row + \li \b {Object permissions} + \li Configure following permissions: + \list + \li Grant \c {read} permission to \c {all}. + \li Clear other permission grants. + \endlist + \li \e {Object permissions} control who can perform operations to \c {allUsers} usergroup. + + In this case read-only access is given to everybody, so the QML application can read the \c {allUsers} data even when the application doesn't have any logged in user. + \row + \li \b {Member management permissions} + \li Configure following permissions: + \list + \li Grant \c {create} permission to \c {all}. + \li Clear other permission grants. + \endlist + \li \e {Member management permissions} control who can add new memebrs to \c {allUsers} usergroup or remove existing ones. + + Now member add right is given to everybody and thus the QML application can add the end-user to \c {allUsers} usergroup. + However, since other permissions are not granted, usergroup members can not be listed or removed. + \endtable +\enddiv + + + +\section2 2. Create 'todoLists' Object Type + +Create a new object type \c {objects.todoLists}. +The object type defines data schema and other settings for todo list objects. + +Create the object type: +\list + \li In Dashboard: Select \b {Object Types}, click \b {Add}, enter name \c {objects.todoLists} for the object type, and select \b {Save}. +\endlist + + +Then configure the object type with needed details: +\list + \li In Dashboard: Open \b {objects.todoLists} object type for editing, apply the configurations below, and finally select \b {Save} in object type editor. +\endlist + + +\div {class="qt-enginio-example-3-col-conf-table"} + \table + \header + \li Setting area + \li Required configurations + \li + \row + \li \b {Properties} + \li Add following property: + \list + \li \c {name}, with data type \e {string} + \endlist + \li \e {Properties} are key/value pairs containing actual object data. + + The '\c {name}' property will hold the name of the todo list. + \row + \li \b {Data validators} + \li Setup following validators: + \list + \li \e {Required} validator for \c {name} property. + \li \e {Length} validator for \c {name} property with \e {minimum 5} and \e {maximum 20} limits. + \endlist + \li \e {Data validators} are used to enforce objects internal data structure and value constraints. + + \e {Required} validator enforces that \c {name} property has non-null value. + + \e {Length} validator enforces that \c {name} length is between given minimum and maximum limits. + \row + \li \b {Permissions} + \li Configure following permissions: + \list + \li Collection permissions + \list + \li Grant \e {read} and \e {create} permission to \c {allUsers} usergroup. + \li Clear other permission grants. + \endlist + \li Object permissions template + \list + \li Grant \e {admin} permission to \e {creator} subject. + \li Clear other permission grants. + \endlist + \endlist + \li \e {Collection permissions} control who is able to create new \c {objects.todoLists} objects or list existing ones. + Now those rights are granted to \c {allUsers} usergroup members. + + \e {Object permissions template} define how object level permissions will be initially set for created \c {objects.todoLists} objects. + Now \e {admin} permission will be granted to user who creates the \c {objects.todoLists} object. + + \e {Admin} right allows the user to perform all 'normal' operations to the \c {objects.todoLists} object (i.e. read, update and delete the object). + \e {Admin} right allows the user also to manage object's permissions (i.e. grant and withdraw rights for other users). + \endtable +\enddiv + + +\section2 3. Create 'todos' Object Type + +Create a new object type \c {objects.todos}. +The object type defines data schema and other settings for todo item objects. + + +Create the object type: +\list + \li In Dashboard: Select \b {Object Types}, click \b {Add}, enter name \c {objects.todos} for the object type, and select \b {Save}. +\endlist + + +Then configure the object type with needed details: +\list + \li In Dashboard: Open \b {objects.todos} object type for editing, apply the configurations below, and finally select \b {Save} in object type editor. +\endlist + + +\div {class="qt-enginio-example-3-col-conf-table"} +\table + \header + \li Setting area + \li Required configurations + \li + \row + \li \b {Properties} + \li Add following properties: + \list + \li \c {title}, with data type \e {string} + \li \c {done}, with data type \e {boolean} + \li \c {todoList}, with data type \e {ref} and target \c {objects.todoLists} + \endlist + \li \e {Properties} are key/value pairs containing actual object data. + + The '\c {title}' property will hold the textual content for the todo item. + + The '\c {done}' property is boolean status whether the item is done or not. + + The '\c {todoList}' is a reference to parent todo list, i.e. a link to todo list object to which this todo item belongs to. + \row + \li \b {Data validators} + \li Setup following validators: + \list + \li \e {Required} validator for properties \c {title}, \c {done} and \c {todoList}. + \li \e {Length} validator for \c {title} property with \e {minimum 5} and \e {maximum 40} limits. + \endlist + \li \e {Data validators} are used to enforce objects internal data structure and value constraints. + + \e {Required} validator enforces that \c {title}, \c {done} and \c {todoList} properties have non-null values. + + \e {Length} validator enforces that \c {title} property value length is between given minimum and maximum limits. + \row + \li \b {Reference constraints} + \li Configure following reference constraint action: + \list + \li For \c {todoList} reference, setup \e {cascade delete} action. + \endlist + + \li \e {Reference constraints} are mechanism to enforce "exists" relationships between objects. + \e {Action} specifies what is done when a referenced object is deleted. + \e {Cascade delete} selection means that the referencing \c {objects.todos} object is also deleted in this case. + \row + \li \b {Permissions} + \li Configure following permissions: + \list + \li Collection permissions + \list + \li Grant \e {read} and \e {create} permission to \c {allUsers} usergroup. + \li Clear other permission grants. + \endlist + \li Object permissions template + \list + \li Clear all permissions grants. + \endlist + \li Object permissions inheritance + \list + \li Enable object permissions inheritance for \c {todoList} reference. + \endlist + \endlist + \li \e {Collection permissions} control who is able to create new \c {objects.todos} objects or list existing ones. + Now those rights are granted to \c {allUsers} usergroup members. + + \e {Object permissions template} define how object level permissions will be initially set for created \c {objects.todos} objects. + Now object permissions template is left empty, because dynamic permission inheritance is used. + + Object permissions inheritance enables inheriting object level permissions dynamically from referenced objects. + Now permissions inheritance is enabled for \c {todoList} reference. Thus \c {objects.todos} object inherits its permissions from referenced \c {objects.todoLists} object. +\endtable +\enddiv + + +\section2 4. Configure 'users' Object Type + +Configure built-in \c {users} object type with needed security permissions. +The \c {users} object type defines data schema and other settings for user objects, modeling application end-users. + +\list + \li In Dashboard: select \b {Object Types}, open \b {users} object type for editing, apply the configurations below, and finally select \b {Save} in object type editor. +\endlist + + +\div {class="qt-enginio-example-3-col-conf-table"} + \table + \header + \li Setting area + \li Required configurations + \li + \row + \li \b {Permissions} + \li Configure permissions and dynamic rules: + \list + \li Collection permissions + \list + \li Grant \e {create} permission to \c {all}. + \li Grant \e {read} permission to \c {allUsers} usergroup. + \li Clear other permission grants. + \endlist + \li Object permissions template + \list + \li Grant \e {read} permission to \c {allUsers} usergroup. + \li Clear other permission grants. + \endlist + \endlist + \li \e {Collection permissions} control who is able to create new \c {users} objects or list existing ones. + In this case create right is granted to all, so anyone can freely register to application as a new user. + However, listing of existing users is granted only to members of \c {allUsers} usergroup. + + \e {Object permissions template} define how object level permissions will be initially set for created \c {users} objects. + Read-only right is given to \c {allUsers} usergroup members, so registered users are able to see each other details for sharing purposes. + \endtable +\enddiv + + + +\section2 5. Configure 'usergroups' Object Type + + +Configure built-in \c {usergroups} object type with needed security permissions. +The \c {usergroups} object type defines data schema and other settings for usergroups objects. + +\list + \li In Dashboard: select \b {Object Types}, open \b {usergroups} object type for editing, apply the configurations below, and finally select \b {Save} in object type editor. +\endlist + + +\div {class="qt-enginio-example-3-col-conf-table"} + \table + \header + \li Setting area + \li Required configurations + \li + \row + \li \b {Permissions} + \li Configure permissions and dynamic rules: + \list + \li Collection permissions + \list + \li Grant \e {read} permission to \c {all}. + \li Clear other permission grants. + \endlist + \li Object permissions template + \list + \li Clear all permission grants. + \endlist + \endlist + \li \e {Collection permissions} control who is able to create new \c {usergroups} objects or list existing ones. + In this case listing rights are granted for everyone (i.e. those are publicly readable). + Thus the QML application can locate \c {allUsers} usergoup in the application startup phase, even before the end-user logs-in to system. + However, since create right is not granted to anyone, new usergroups can not be created. + + \e {Object permissions template} define how object level permissions will be initially set for created \c {usergroups} objects. + Since new usergroups can't be created, also object permissions template is set empty. + \endtable +\enddiv + + +\section1 Configure and Run QML Application + +\section1 QML Application Walk-through + +*/ + diff --git a/examples/enginio/quick/socialtodos/socialtodos.pro b/examples/enginio/quick/socialtodos/socialtodos.pro new file mode 100644 index 0000000..e27f082 --- /dev/null +++ b/examples/enginio/quick/socialtodos/socialtodos.pro @@ -0,0 +1,21 @@ +TEMPLATE = app + +DEFINES += ENGINIO_SAMPLE_NAME=\\\"socialtodos\\\" + +include(../../common/backendhelper/qmlbackendhelper.pri) + +QT += quick qml enginio +SOURCES += ../main.cpp + +mac: CONFIG -= app_bundle + +OTHER_FILES += \ + Header.qml \ + List.qml \ + Login.qml \ + ShareDialog.qml \ + TextField.qml \ + TodoLists.qml \ + socialtodos.qml + +RESOURCES += socialtodos.qrc diff --git a/examples/enginio/quick/socialtodos/socialtodos.qml b/examples/enginio/quick/socialtodos/socialtodos.qml new file mode 100644 index 0000000..f1b7ed9 --- /dev/null +++ b/examples/enginio/quick/socialtodos/socialtodos.qml @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtEnginio 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.1 +import QtQuick.Controls 1.0 +import QtQuick.Window 2.1 +import Enginio 1.0 + +Item { + id: main + property real scaleFactor: Screen.pixelDensity / 5.0 + property int intScaleFactor: Math.max(1, scaleFactor) + + width: 400 * scaleFactor + height: 640 * scaleFactor + + BackendHelper{ + id: backendHelper + } + + Rectangle { + id: root + anchors.fill: parent + opacity: 1 - backendHelper.opacity + + color: "#f4f4f4" + + Component { + id: lists + TodoLists{} + } + + EnginioClient { + id: enginioClient + backendId: backendHelper.backendId + + onAuthenticationStateChanged: { + console.log("Auth state:", authenticationState) + if (authenticationState === 2) + mainView.push({ item: lists, properties: {"username": auth.user}}) + } + + onError: console.log(JSON.stringify(reply.data)) + } + + EnginioOAuth2Authentication { + id: auth + } + + StackView { + id: mainView + anchors.fill: parent + initialItem: Login{} + } + } +} diff --git a/examples/enginio/quick/socialtodos/socialtodos.qrc b/examples/enginio/quick/socialtodos/socialtodos.qrc new file mode 100644 index 0000000..36a4afc --- /dev/null +++ b/examples/enginio/quick/socialtodos/socialtodos.qrc @@ -0,0 +1,30 @@ +<RCC> + <qresource prefix="/icons"> + <file alias="delete_icon.png">../../common/icons/delete_icon.png</file> + <file alias="add_icon.png">../../common/icons/add_icon.png</file> + <file alias="add_icon_pressed.png">../../common/icons/add_icon_pressed.png</file> + <file alias="delete_icon_pressed.png">../../common/icons/delete_icon_pressed.png</file> + <file alias="back_icon.png">../../common/icons/back_icon.png</file> + <file alias="share_icon.png">../../common/icons/share_icon.png</file> + <file alias="share_icon_pressed.png">../../common/icons/share_icon_pressed.png</file> + <file alias="reload_icon.png">../../common/icons/reload_icon.png</file> + <file alias="reload_icon_pressed.png">../../common/icons/reload_icon_pressed.png</file> + </qresource> + <qresource prefix="/images"> + <file alias="delegate.png">../../common/images/delegate.png</file> + <file alias="delegate_pressed.png">../../common/images/delegate_pressed.png</file> + <file alias="shadow.png">../../common/images/shadow.png</file> + <file alias="textfield.png">../../common/images/textfield.png</file> + <file alias="checkmark.png">../../common/images/checkbox_checked.png</file> + </qresource> + <qresource prefix="/"> + <file>socialtodos.qml</file> + <file>Login.qml</file> + <file>TextField.qml</file> + <file>TodoLists.qml</file> + <file>List.qml</file> + <file>ShareDialog.qml</file> + <file>Header.qml</file> + <file>TouchButton.qml</file> + </qresource> +</RCC> diff --git a/examples/enginio/quick/todos/doc/images/todolist.png b/examples/enginio/quick/todos/doc/images/todolist.png Binary files differnew file mode 100644 index 0000000..4bc7849 --- /dev/null +++ b/examples/enginio/quick/todos/doc/images/todolist.png diff --git a/examples/enginio/quick/todos/doc/src/todos.qdoc b/examples/enginio/quick/todos/doc/src/todos.qdoc new file mode 100644 index 0000000..7d5d954 --- /dev/null +++ b/examples/enginio/quick/todos/doc/src/todos.qdoc @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ +/*! + \title Enginio QML Examples - Todos + \example todos + \brief The Todo example shows the EnginioModel usage in Qt Quick. + \ingroup enginio-examples + \inmodule enginio-qml + + In this example a simple list of objects is displayed in a ListView. + Each item in the list is a "To Do" object which can be "done" or "not yet done". + Todos can be added and removed (when hovering with the mouse). + \image todolist.png + + In this simple schema the objects will only have two properties that are added + to the default properties (such as creation date which always exists). + A string "title" and a bool "completed". The object type will be created + when a call to create, or, in this case, a call to \l{Enginio1::EnginioModel::append()}{EnginioModel::append()} is made. + + A todo object will look like this (in JSON): + \code +{ + "title": "Buy Milk", + "completed": false +} + \endcode + + The example uses Qt Quick Controls, Layouts, and Enginio. + \snippet todos/todo.qml imports + + The first step is to create an \l{Enginio1::EnginioModel} and + the Enginio instance with the backend configuration. + To get nice debug output in case something goes wrong, the onError signal in + Enginio is handled. Since the error is a JSON object, JSON.stringify is used + to format it to a string. + + \snippet todos/todo.qml model + + A ListView is used to display the list of Todos. In the delegate, the + properties of the Enginio objects are used. + \snippet todos/todo.qml view + + It is easy to add a new object to the model. + By using a TextField's onAccepted function, the data is + appended to the model. After appending the new Todo, the text gets cleared + so that a new Todo can be entered. + \snippet todos/todo.qml append + + Inside the delegate, the data for the index is available by using the property names (\e title and \e completed). + The \e title property is directly assigned to the text displayed on each list item. The \e completed + boolean is used to display the item with a strikeout font and a light color. + \snippet todos/todo.qml delegate-properties + + The \l Enginio1::EnginioModel::setProperty() function is called to update the data in the Enginio backend. + + \snippet todos/todo.qml setProperty + + The _synced property can be used to ascertain whether an item has been synced or not. + It is always available in the delegate, and may be used, for example, to disable the user interface + until syncing has completed. + + \snippet todos/todo.qml sync + + Finally, a remove button is visible when hovering over an item with the mouse. + Removal is implemented by calling \l{Enginio1::EnginioModel::remove()}{EnginioModel::remove()} with the row of the item. + \snippet todos/todo.qml remove +*/ diff --git a/examples/enginio/quick/todos/todo.qml b/examples/enginio/quick/todos/todo.qml new file mode 100644 index 0000000..becc267 --- /dev/null +++ b/examples/enginio/quick/todos/todo.qml @@ -0,0 +1,279 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 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.0 +//![imports] +import Enginio 1.0 +//![imports] + +Item { + width: 400 + height: 640 + BackendHelper{ + id: backendHelper + } + + Rectangle { + id: root + color: "#f4f4f4" + anchors.fill: parent + opacity: 1 - backendHelper.opacity + + //![model] + EnginioModel { + id: enginioModel + client: EnginioClient { + backendId: backendHelper.backendId + onError: console.log("Enginio error:", JSON.stringify(reply.data)) + } + query: {"objectType": "objects.todos" } + } + //![model] + + // A simple layout: + // a listview and a line edit with button to add to the list + Rectangle { + id: header + anchors.top: parent.top + width: parent.width + height: 70 + color: "white" + + Row { + id: logo + anchors.centerIn: parent + anchors.horizontalCenterOffset: -4 + spacing: 4 + Image { + source: "qrc:images/enginio.png" + width: 160 ; height: 60 + fillMode: Image.PreserveAspectFit + } + Text { + text: "Todos" + anchors.verticalCenter: parent.verticalCenter + anchors.verticalCenterOffset: -3 + font.bold: true + font.pixelSize: 46 + color: "#555" + } + } + Rectangle { + width: parent.width ; height: 1 + anchors.bottom: parent.bottom + color: "#bbb" + } + } + + //![view] + ListView { + id: listview + model: enginioModel + delegate: listItemDelegate + anchors.top: header.bottom + anchors.bottom: footer.top + width: parent.width + clip: true + + // Animations + add: Transition { NumberAnimation { properties: "y"; from: root.height; duration: 250 } } + removeDisplaced: Transition { NumberAnimation { properties: "y"; duration: 150 } } + remove: Transition { NumberAnimation { property: "opacity"; to: 0; duration: 150 } } + } + //![view] + + BorderImage { + id: footer + + width: parent.width + anchors.bottom: parent.bottom + source: "qrc:images/delegate.png" + border.left: 5; border.top: 5 + border.right: 5; border.bottom: 5 + + Rectangle { + y: -1 ; height: 1 + width: parent.width + color: "#bbb" + } + Rectangle { + y: 0 ; height: 1 + width: parent.width + color: "white" + } + + //![append] + + BorderImage { + + anchors.left: parent.left + anchors.right: addButton.left + anchors.verticalCenter: parent.verticalCenter + anchors.margins: 16 + source:"images/textfield.png" + border.left: 14 ; border.right: 14 ; border.top: 8 ; border.bottom: 8 + + TextInput{ + id: textInput + anchors.fill: parent + clip: true + anchors.leftMargin: 14 + anchors.rightMargin: 14 + verticalAlignment: Text.AlignVCenter + font.pixelSize: 22 + Text { + id: placeholderText + anchors.fill: parent + verticalAlignment: Text.AlignVCenter + visible: !(parent.text.length || parent.inputMethodComposing) + font: parent.font + text: "New todo..." + color: "#aaa" + } + onAccepted: { + enginioModel.append({"title": textInput.text, "completed": false}) + textInput.text = "" + } + } + } + + Item { + id: addButton + + width: 40 ; height: 40 + anchors.margins: 20 + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + enabled: textInput.text.length + Image { + source: addMouseArea.pressed ? "qrc:icons/add_icon_pressed.png" : "qrc:icons/add_icon.png" + anchors.centerIn: parent + opacity: enabled ? 1 : 0.5 + } + MouseArea { + id: addMouseArea + anchors.fill: parent + onClicked: textInput.accepted() + } + } + } + //![append] + + Component { + id: listItemDelegate + + BorderImage { + id: item + + width: parent.width ; height: 70 + source: mouse.pressed ? "qrc:images/delegate_pressed.png" : "qrc:images/delegate.png" + border.left: 5; border.top: 5 + border.right: 5; border.bottom: 5 + + Image { + id: shadow + anchors.top: parent.bottom + width: parent.width + visible: !mouse.pressed + source: "qrc:images/shadow.png" + } + + //![setProperty] + MouseArea { + id: mouse + anchors.fill: parent + hoverEnabled: true + onClicked: { + if (index !== -1 && _synced) { + enginioModel.setProperty(index, "completed", !completed) + } + } + } + //![setProperty] + Image { + id: checkbox + anchors.left: parent.left + anchors.leftMargin: 16 + width: 32 + fillMode: Image.PreserveAspectFit + anchors.verticalCenter: parent.verticalCenter + source: completed ? "qrc:images/checkmark.png" : "" + } + + //![delegate-properties] + Text { + id: todoText + text: title + font.pixelSize: 26 + color: "#333" + + anchors.verticalCenter: parent.verticalCenter + anchors.left: checkbox.right + anchors.right: parent.right + anchors.leftMargin: 12 + anchors.rightMargin: 40 + elide: Text.ElideRight + } + //![delegate-properties] + + // Show a delete button when the mouse is over the delegate + //![sync] + Image { + id: removeIcon + + source: removeMouseArea.pressed ? "qrc:icons/delete_icon_pressed.png" : "qrc:icons/delete_icon.png" + anchors.margins: 20 + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + opacity: enabled ? 1 : 0.5 + Behavior on opacity {NumberAnimation{duration: 100}} + //![remove] + MouseArea { + id: removeMouseArea + anchors.fill: parent + onClicked: enginioModel.remove(index) + } + //![remove] + } + //![sync] + } + } + } +} diff --git a/examples/enginio/quick/todos/todo.qrc b/examples/enginio/quick/todos/todo.qrc new file mode 100644 index 0000000..db4254a --- /dev/null +++ b/examples/enginio/quick/todos/todo.qrc @@ -0,0 +1,18 @@ +<RCC> + <qresource prefix="/icons"> + <file alias="delete_icon.png">../../common/icons/delete_icon.png</file> + <file alias="add_icon.png">../../common/icons/add_icon.png</file> + <file alias="add_icon_pressed.png">../../common/icons/add_icon_pressed.png</file> + <file alias="delete_icon_pressed.png">../../common/icons/delete_icon_pressed.png</file> + </qresource> + <qresource prefix="/images"> + <file alias="delegate.png">../../common/images/delegate.png</file> + <file alias="delegate_pressed.png">../../common/images/delegate_pressed.png</file> + <file alias="shadow.png">../../common/images/shadow.png</file> + <file alias="textfield.png">../../common/images/textfield.png</file> + <file alias="checkmark.png">../../common/images/checkbox_checked.png</file> + </qresource> + <qresource prefix="/"> + <file>todo.qml</file> + </qresource> +</RCC> diff --git a/examples/enginio/quick/todos/todos.pro b/examples/enginio/quick/todos/todos.pro new file mode 100644 index 0000000..7e1e486 --- /dev/null +++ b/examples/enginio/quick/todos/todos.pro @@ -0,0 +1,13 @@ +TEMPLATE = app + +DEFINES += ENGINIO_SAMPLE_NAME=\\\"todo\\\" + +include(../../common/backendhelper/qmlbackendhelper.pri) + +QT += quick qml enginio +SOURCES += ../main.cpp + +mac: CONFIG -= app_bundle + +OTHER_FILES += todo.qml +RESOURCES += todo.qrc diff --git a/examples/enginio/quick/users/Browse.qml b/examples/enginio/quick/users/Browse.qml new file mode 100644 index 0000000..4bc3bb5 --- /dev/null +++ b/examples/enginio/quick/users/Browse.qml @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtEnginio 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.1 +//![imports] +import Enginio 1.0 +import QtQuick.Controls 1.0 +import QtQuick.Layouts 1.0 +//![imports] + +ColumnLayout { + anchors.margins: 3 + spacing: 3 + TableView { + Layout.fillWidth: true + Layout.fillHeight: true + + //![columns] + TableViewColumn { title: "First name"; role: "firstName" } + TableViewColumn { title: "Last name"; role: "lastName" } + TableViewColumn { title: "Login"; role: "username" } + TableViewColumn { title: "Email"; role: "email" } + //![columns] + + //![browse] + model: EnginioModel { + id: enginioModel + client: enginioClient + operation: Enginio.UserOperation + query: {"objectType": "users" } + } + //![browse] + } + + Button { + text: "Refresh" + Layout.fillWidth: true + + onClicked: { + var tmp = enginioModel.query + enginioModel.query = null + enginioModel.query = tmp + } + } +} + diff --git a/examples/enginio/quick/users/Login.qml b/examples/enginio/quick/users/Login.qml new file mode 100644 index 0000000..1639653 --- /dev/null +++ b/examples/enginio/quick/users/Login.qml @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtEnginio 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.1 +import Enginio 1.0 +import QtQuick.Controls 1.0 +import QtQuick.Layouts 1.0 + +ColumnLayout { + //![identity] + EnginioOAuth2Authentication { + id: identity + user: login.text + password: password.text + } + //![identity] + anchors.fill: parent + anchors.margins: 3 + spacing: 3 + + TextField { + id: login + Layout.fillWidth: true + placeholderText: "Username" + enabled: enginioClient.authenticationState == Enginio.NotAuthenticated + } + + TextField { + id: password + Layout.fillWidth: true + placeholderText: "Password" + echoMode: TextInput.PasswordEchoOnEdit + enabled: enginioClient.authenticationState == Enginio.NotAuthenticated + } + + Button { + id: proccessButton + Layout.fillWidth: true + } + + TextArea { + id: data + text: "Not logged in.\n\n" + readOnly: true + Layout.fillHeight: true + Layout.fillWidth: true + + //![connections] + Connections { + target: enginioClient + onSessionAuthenticated: { + data.text = data.text + "User '"+ login.text +"' is logged in.\n\n" + JSON.stringify(reply.data, undefined, 2) + "\n\n" + } + onSessionAuthenticationError: { + data.text = data.text + "Authentication of user '"+ login.text +"' failed.\n\n" + JSON.stringify(reply.data, undefined, 2) + "\n\n" + } + onSessionTerminated: { + data.text = data.text + "Session closed.\n\n" + } + } + //![connections] + } + + states: [ + State { + name: "NotAuthenticated" + when: enginioClient.authenticationState == Enginio.NotAuthenticated + PropertyChanges { + target: proccessButton + text: "Login" + onClicked: { + //![assignIdentity] + enginioClient.identity = identity + //![assignIdentity] + } + } + }, + State { + name: "Authenticating" + when: enginioClient.authenticationState == Enginio.Authenticating + PropertyChanges { + target: proccessButton + text: "Authenticating..." + enabled: false + } + }, + State { + name: "AuthenticationFailure" + when: enginioClient.authenticationState == Enginio.AuthenticationFailure + PropertyChanges { + target: proccessButton + text: "Authentication failed, restart" + onClicked: { + enginioClient.identity = null + } + } + }, + State { + name: "Authenticated" + when: enginioClient.authenticationState == Enginio.Authenticated + PropertyChanges { + target: proccessButton + text: "Logout" + onClicked: { + //![assignNull] + enginioClient.identity = null + //![assignNull] + } + } + } + ] +} diff --git a/examples/enginio/quick/users/Register.qml b/examples/enginio/quick/users/Register.qml new file mode 100644 index 0000000..583dfa6 --- /dev/null +++ b/examples/enginio/quick/users/Register.qml @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** 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: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.1 +import Enginio 1.0 +import QtQuick.Controls 1.0 +import QtQuick.Layouts 1.0 + +ColumnLayout { + anchors.margins: 3 + spacing: 3 + + TextField { + id: login + Layout.fillWidth: true + placeholderText: "Username" + } + + TextField { + id: password + Layout.fillWidth: true + placeholderText: "Password" + echoMode: TextInput.PasswordEchoOnEdit + } + + TextField { + id: userFirstName + Layout.fillWidth: true + placeholderText: "First name" + } + + TextField { + id: userLastName + Layout.fillWidth: true + placeholderText: "Last name" + } + + TextField { + id: userEmail + Layout.fillWidth: true + placeholderText: "Email" + } + + Button { + id: proccessButton + Layout.fillWidth: true + enabled: login.text.length && password.text.length + text: "Register" + + states: [ + State { + name: "Registering" + PropertyChanges { + target: proccessButton + text: "Registering..." + enabled: false + } + } + ] + + onClicked: { + proccessButton.state = "Registering" + //![create] + var reply = enginioClient.create( + { "username": login.text, + "password": password.text, + "email": userEmail.text, + "firstName": userFirstName.text, + "lastName": userLastName.text + }, Enginio.UserOperation) + //![create] + reply.finished.connect(function() { + proccessButton.state = "" + if (reply.errorType !== EnginioReply.NoError) { + log.text = "Failed to create an account:\n" + JSON.stringify(reply.data, undefined, 2) + "\n\n" + } else { + log.text = "Account Created.\n" + } + }) + } + } + + TextArea { + id: log + readOnly: true + Layout.fillWidth: true + Layout.fillHeight: true + } +} diff --git a/examples/enginio/quick/users/doc/src/users.qdoc b/examples/enginio/quick/users/doc/src/users.qdoc new file mode 100644 index 0000000..f5436c5 --- /dev/null +++ b/examples/enginio/quick/users/doc/src/users.qdoc @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \title Enginio QML Examples - Users + \example users + \brief The Users example introduces user registration, authentication and browsing. + \ingroup enginio-examples + \inmodule enginio-qml + + \section1 Introduction + + This example will demonstrate how to register and authenticate a user, and what kind of information + is attached to an authenticated session. This is a simple example and data access rights + management is not covered here. For such information, please refer to the Social Todo example. + + There is no special need for the backend setup. This example will use only predefined + structures, which are the same for every backend. + + The example is an application that shows users registered in the backend, allows registration of + new users and shows how to login in separate tabs. + + Each backend contains the "users" object type, which defines a structure + that stores all basic data about an application's users. The collection of "users" is not + really different from any other collection, therefore we do not need any special + methods to manipulate it. Typical data associated with a user is: + \list + \li username - required name used for logging in. + \li email - unique email address of a user. + \li firstName, lastName - user's credentials (optional). + \li password - write-only property, this value is used during authentication. + \endlist + + The "users" object can be extended by custom properties, too. + + \note \e username and \e password are always required and cannot be empty. + + \section1 General example structure + This example uses QtEnginio library together with QtQuickControls, therefore both have + to be imported. + \snippet users/Browse.qml imports + We will also use a common \l {Enginio1::EnginioClient}{EnginioClient} connection as shown here: + \snippet users/users.qml client + + The example is organized into separate tabs by using \l TabView. Each tab shows different + functionality. + + \section1 Browsing users' data + The most convenient method to browse users is to use \l{Enginio1::EnginioModel}{EnginioModel}. The model can + automatically download all data that we need. It is sufficient to set three properties: + \l{Enginio1::EnginioModel::client}{client}, \l{Enginio1::EnginioModel::query}{query} + and \l{Enginio1::EnginioModel::operation}{operation} as shown below: + \snippet users/Browse.qml browse + + The model is used directly by TableView, in which we define data that will be shown. + \snippet users/Browse.qml columns + + \section1 User authentication + Authentication is quite easy. The only thing that needs to be done is to assign an identity, for example + \l{EnginioOAuth2Authentication}{EnginioOAuth2Authentication} object to \l{EnginioClient::identity}{EnginioClient::identity}. + After a while, \l{EnginioClient::authenticationState}{EnginioClient::authenticationState} will change and + \l{EnginioClient::sessionAuthenticated}{sessionAuthenticated} or \l{EnginioClient::sessionAuthenticationError}{sessionAuthenticationError} + will be emitted. + + The first thing we need to do is to create an identity object: \l{EnginioOAuth2Authentication}{EnginioOAuth2Authentication} + \snippet users/Login.qml identity + + Then, depending on the state of the application, we assign the object to + our enginioClient instance. There are four possible states, defined by + \l{EnginioClient::AuthenticationState}. After assigning the Identity object, + the state changes from the initial "NotAuthenticated" to "Authenticating". + \snippet users/Login.qml assignIdentity + + Once the authentication query finishes, the state changes to "Authenticated" or + "AuthenticationFailure" depending on the authentication result. Null + assignment to the \l{EnginioClient::identity}{identity} causes the session to terminate immediately: + \snippet users/Login.qml assignNull + + For educational purposes, in the example we also show a log window with data attached to + a session that is changing state. + \snippet users/Login.qml connections + + \section1 Registering a new user + Registration of a new user is as simple as adding a new object to the "users" collection. It can be achieved + by using the \l{EnginioClient::create}{create} function, as shown below: + \snippet users/Register.qml create + + We could also use the \l{Enginio1::EnginioModel::append}{EnginioModel::append} method in the browsing example + to accomplish the same task. +*/ diff --git a/examples/enginio/quick/users/users.pro b/examples/enginio/quick/users/users.pro new file mode 100644 index 0000000..12fef03 --- /dev/null +++ b/examples/enginio/quick/users/users.pro @@ -0,0 +1,13 @@ +TEMPLATE = app + +DEFINES += ENGINIO_SAMPLE_NAME=\\\"users\\\" + +include(../../common/backendhelper/qmlbackendhelper.pri) + +QT += quick qml enginio qml +SOURCES += ../main.cpp + +mac: CONFIG -= app_bundle + +OTHER_FILES += users.qml Browse.qml Login.qml Register.qml +RESOURCES += users.qrc
\ No newline at end of file diff --git a/examples/enginio/quick/users/users.qml b/examples/enginio/quick/users/users.qml new file mode 100644 index 0000000..3031d2d --- /dev/null +++ b/examples/enginio/quick/users/users.qml @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtEnginio 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.1 +import Enginio 1.0 +import QtQuick.Controls 1.0 +import QtQuick.Layouts 1.0 + +Item { + id: main + height: 800 + width: 600 + + BackendHelper{ + id: backendHelper + } + + Rectangle { + id: root + anchors.fill: parent + opacity: 1 - backendHelper.opacity + + color: "#f4f4f4" + + //![client] + EnginioClient { + id: enginioClient + backendId: backendHelper.backendId + + onError: console.debug(JSON.stringify(reply.data)) + } + //![client] + + TabView { + id: tabView + anchors.fill: parent + anchors.margins: 3 + + Tab { + title: "Users" + Browse { anchors.fill: parent } + } + + Tab { + title: "Login" + Login { anchors.fill: parent } + } + + Tab { + title: "Register" + Register { anchors.fill: parent } + } + } + } +} diff --git a/examples/enginio/quick/users/users.qrc b/examples/enginio/quick/users/users.qrc new file mode 100644 index 0000000..1bd02cb --- /dev/null +++ b/examples/enginio/quick/users/users.qrc @@ -0,0 +1,8 @@ +<RCC> + <qresource prefix="/"> + <file>users.qml</file> + <file>Browse.qml</file> + <file>Login.qml</file> + <file>Register.qml</file> + </qresource> +</RCC> diff --git a/examples/enginio/widgets/cloudaddressbook/addressbookmodel.cpp b/examples/enginio/widgets/cloudaddressbook/addressbookmodel.cpp new file mode 100644 index 0000000..d59b874 --- /dev/null +++ b/examples/enginio/widgets/cloudaddressbook/addressbookmodel.cpp @@ -0,0 +1,198 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 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$ +** +****************************************************************************/ + +#include <QtCore/qhash.h> +#include <QtCore/qbytearray.h> +#include <QtCore/qjsondocument.h> +#include <QtCore/qjsonvalue.h> +#include <QtCore/qjsonobject.h> +#include <QtCore/qjsonarray.h> + +#include <QtGui/qfont.h> + +#include "addressbookmodel.h" + +AddressBookModel::AddressBookModel(QObject *parent) + : EnginioModel(parent) + , _searchReply() +{} + +AddressBookModel::~AddressBookModel() +{} + +//![data] +QVariant AddressBookModel::data(const QModelIndex &index, int role) const +{ + if (role == Qt::DisplayRole) { + // we assume here that column order is constant and it is the same as in AddressBookModel::Roles + return EnginioModel::data(index, FirstNameRole + index.column()).value<QJsonValue>().toString(); + } + if (role == Qt::FontRole) { + // this role is used to mark items found in the full text search. + QFont font; + QString id = EnginioModel::data(index, Enginio::IdRole).value<QString>(); + font.setBold(_markedItems.contains(id)); + return font; + } + + return EnginioModel::data(index, role); +} + +bool AddressBookModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + bool result = role == Qt::EditRole + ? EnginioModel::setData(this->index(index.row()), value, FirstNameRole + index.column()) + : EnginioModel::setData(this->index(index.row()), value, role); + + // if the data was edited, the marked items set may not be valid anymore + // so we need to clear it. + if (result) + _markedItems.clear(); + return result; +} +//![data] + +//![tableViewIntegration] +int AddressBookModel::columnCount(const QModelIndex &parent) const +{ + return parent.isValid() ? 0 : 5; +} + +QVariant AddressBookModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { + switch (section) { + case 0: return QStringLiteral("First name"); + case 1: return QStringLiteral("Last name"); + case 2: return QStringLiteral("Email"); + case 3: return QStringLiteral("Phone number"); + case 4: return QStringLiteral("Address"); + } + return QVariant(); + } + return EnginioModel::headerData(section, orientation, role); +} +//![tableViewIntegration] + +//![Roles] +QHash<int, QByteArray> AddressBookModel::roleNames() const +{ + QHash<int, QByteArray> roles = EnginioModel::roleNames(); + roles.insert(FirstNameRole, "firstName"); + roles.insert(LastNameRole, "lastName"); + roles.insert(AddressRole, "email"); + roles.insert(PhoneRole, "phone"); + roles.insert(AddressRole, "address"); + return roles; +} +//![Roles] + +void AddressBookModel::newSearch(const QString &search) +{ + if (search.isEmpty()) + return; + + //![query] + // construct JSON object: + // { + // "objectTypes": ["objects.addressbook"], + // "search": { "phrase": "*PHRASE*", + // "properties": ["firstName", "lastName", "email", "phone", "address"] + // } + // } + + QJsonObject query; + { + QJsonArray objectTypes; + objectTypes.append(QString::fromUtf8("objects.addressbook")); + + QJsonArray properties; + properties.append(QString::fromUtf8("firstName")); + properties.append(QString::fromUtf8("lastName")); + properties.append(QString::fromUtf8("email")); + properties.append(QString::fromUtf8("phone")); + properties.append(QString::fromUtf8("address")); + + QJsonObject searchQuery; + searchQuery.insert("phrase", "*" + search + "*"); + searchQuery.insert("properties", properties); + + query.insert("objectTypes", objectTypes); + query.insert("search", searchQuery); + } + //![query] + + if (_searchReply) { + // a new search is created before the old one was finished + // we will not be interested in the results of the old search. + _searchReply->disconnect(this); + } + + //![callSearch] + _searchReply = client()->fullTextSearch(query); + QObject::connect(_searchReply, &EnginioReply::finished, this, &AddressBookModel::searchResultsArrived); + QObject::connect(_searchReply, &EnginioReply::finished, _searchReply, &EnginioReply::deleteLater); + //![callSearch] +} + +//![results] +void AddressBookModel::searchResultsArrived() +{ + // clear old marks. + _markedItems.clear(); + + // update marked ids. + QJsonArray results = _searchReply->data()["results"].toArray(); + foreach (const QJsonValue &value, results) { + QJsonObject person = value.toObject(); + _markedItems.insert(person["id"].toString()); + } + + QVector<int> roles; + roles.append(Qt::FontRole); + // We do not keep id -> row mapping, therefore it is easier to emit + // data change signal for all items, even if it is not optimal from + // the performance point of view. + emit dataChanged(index(0), index(rowCount() - 1, columnCount() - 1) , roles); + + _searchReply = 0; + emit searchFinished(); +} +//![results] diff --git a/examples/enginio/widgets/cloudaddressbook/addressbookmodel.h b/examples/enginio/widgets/cloudaddressbook/addressbookmodel.h new file mode 100644 index 0000000..fc5580c --- /dev/null +++ b/examples/enginio/widgets/cloudaddressbook/addressbookmodel.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 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$ +** +****************************************************************************/ + +#ifndef ADDRESSBOOKMODEL_H +#define ADDRESSBOOKMODEL_H + +#include <Enginio/enginiomodel.h> +#include <Enginio/enginioreply.h> + +class AddressBookModel : public EnginioModel +{ + Q_OBJECT + + EnginioReply *_searchReply; + QSet<QString> _markedItems; + +public: + //![Roles] + enum Roles { + FirstNameRole = Enginio::CustomPropertyRole, + LastNameRole, + EmailRole, + PhoneRole, + AddressRole + }; + //![Roles] + + explicit AddressBookModel(QObject *parent); + virtual ~AddressBookModel(); + + virtual QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; + bool setData(const QModelIndex &index, const QVariant &value, int role) Q_DECL_OVERRIDE; + virtual int columnCount(const QModelIndex & parent = QModelIndex()) const Q_DECL_OVERRIDE; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE; + virtual QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE; + +public slots: + void newSearch(const QString &search); + +private slots: + void searchResultsArrived(); + +signals: + void searchFinished(); +}; + +#endif // ADDRESSBOOKMODEL_H + diff --git a/examples/enginio/widgets/cloudaddressbook/cloudaddressbook.pro b/examples/enginio/widgets/cloudaddressbook/cloudaddressbook.pro new file mode 100644 index 0000000..dd20cf2 --- /dev/null +++ b/examples/enginio/widgets/cloudaddressbook/cloudaddressbook.pro @@ -0,0 +1,18 @@ +QT += network gui widgets enginio + +TARGET = cloudaddressbook +TEMPLATE = app + +include(../../common/backendhelper/backendhelper.pri) + +SOURCES += \ + main.cpp\ + mainwindow.cpp \ + addressbookmodel.cpp \ + +HEADERS += \ + mainwindow.h \ + addressbookmodel.h \ + +FORMS += \ + mainwindow.ui diff --git a/examples/enginio/widgets/cloudaddressbook/doc/src/cloudaddressbook.qdoc b/examples/enginio/widgets/cloudaddressbook/doc/src/cloudaddressbook.qdoc new file mode 100644 index 0000000..94d79de --- /dev/null +++ b/examples/enginio/widgets/cloudaddressbook/doc/src/cloudaddressbook.qdoc @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \title Enginio C++ Examples - Cloud Address Book + \example cloudaddressbook + \brief The Cloud Address Book example shows sorting, filtering and the full text search functionality + \ingroup enginio-examples + \inmodule enginio-qt + + This example explains how to use the full text search feature of Enginio and how to sort and filter data + showed from the EnginioModel. To present that. a simple address book like application, will be created. + This example doesn't cover security or multi-user management, for such topics please refer + to Social Todo example. + + \section1 Preconditions + To start the example, a backend id and a backend secret have to be provided to an existing and configured + Enginio backend. The backend can be created using dashboard, the Cloud Address Book pre-configured backend + can be chosen. + + \section1 Backend description + We recommend to use pre-configured backend, because it contain already all data and structures that are + needed to run this examples, but it is not difficult to create the backend from scratch too. + The backend should contain one custom object type "objects.addressbook" having properties: + \list + \li firstName + \li lastName + \li email + \li phone + \li address + \endlist + All properties are of string type and have to be indexed, because only indexed properties will be searched + by the full text search. + + \section1 Application design + The application's ui mainly consist of a table showing all addresses and a text filed where a query + can be typed. A user should be able to sort addresses or highlight an address containing a specified phrase. + + \section1 Implementation + From a developer point of view the application from a few simple components: + \list + \li EnginioClient which encapsulates all information that are needed to keep connection to the backend + \li EnginioModel which queries all addresses + \li QSortFilterProxy which sorts the data + \li QTableView which shows the data + \endlist + + The first thing to be done is to construct connection to Enginio service. We need to specify backend id as well + as backend secret. + \snippet cloudaddressbook/mainwindow.cpp client + + The second step is to create EnginioModel which queries all data from the backend. The query is quite simple, + it specifies an object type of which all objects needs to be returned. + \snippet cloudaddressbook/mainwindow.cpp model + + EnginioModel can sort or filter data only initially, which means that for example a newly added + item will not be placed correctly. To solve the problem QSortFilterProxy has to be used. + \snippet cloudaddressbook/mainwindow.cpp assignProxyModel + + Now it is a time to look deeper into EngnioModel. EnginioModel should define data roles. + \snippet cloudaddressbook/addressbookmodel.h Roles + \snippet cloudaddressbook/addressbookmodel.cpp Roles + + and as always \l{EnginioModel::data}{data()} \l{EnginioModel::setData}{setData()} functions have to be overridden + to provide Qt::DisplayRole in the way it is needed to nicely cooperate with QTableView. + \snippet cloudaddressbook/addressbookmodel.cpp data + + Usage of QTableView requires to provide columns headers, so they can be shown in the user interface + \snippet cloudaddressbook/addressbookmodel.cpp tableViewIntegration + + Integration of the full text search is the last step in this tutorial. The goal is to highlight items that + contains a given phrase. The highlighting is done by \l{EnginioModel::data}{data()}, which returns a bold font + for Qt::FontRole, if an item is matching the search query. This example for simplicity assumes that matching + items count is not big and can be kept in a QSet, which would be recreated on each search. + + To do a full text search, a JSON query needs to be constructed. + \snippet cloudaddressbook/addressbookmodel.cpp query + The query contains "objectTypes" property (mark 's' at the end) which is an array of all object types which + have to be searched. In this case, it is only one type "objects.addressbook". Next "search" property has to + be filed. It is an object that is required to have "phrase" property. The property is exactly the search + phrase that has to be found. Please mark '*' characters, without them the full text search would find + only full words. To avoid founding substrings, for example in on object id, which is not visible for a user + the search has to limit scanned property list, by "properties" array. + + When the search query is constructed it is enough to call \l{EnginioClient::fullTextSearch()}{fullTextSearch()}: + \snippet cloudaddressbook/addressbookmodel.cpp callSearch + The result will be delivered to the searchResultsArrived slot. In which from result array all objects ids + are gathered in \a markedItems set. + \snippet cloudaddressbook/addressbookmodel.cpp results +*/ diff --git a/examples/enginio/widgets/cloudaddressbook/main.cpp b/examples/enginio/widgets/cloudaddressbook/main.cpp new file mode 100644 index 0000000..8794f32 --- /dev/null +++ b/examples/enginio/widgets/cloudaddressbook/main.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 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$ +** +****************************************************************************/ + +#include "mainwindow.h" +#include <QApplication> + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/examples/enginio/widgets/cloudaddressbook/mainwindow.cpp b/examples/enginio/widgets/cloudaddressbook/mainwindow.cpp new file mode 100644 index 0000000..32352e7 --- /dev/null +++ b/examples/enginio/widgets/cloudaddressbook/mainwindow.cpp @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 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$ +** +****************************************************************************/ + +#include <QtCore/qbytearray.h> +#include <QtCore/qpair.h> + +#include <QtCore/qjsondocument.h> +#include <QtCore/qjsonobject.h> +#include <QtCore/qsortfilterproxymodel.h> + +#include <Enginio/enginioclient.h> +#include <Enginio/enginioreply.h> + +#include <QtGui/qicon.h> +#include <QtWidgets/qpushbutton.h> + +#include "addressbookmodel.h" + +// To get the backend right, we use a helper class in the example. +// Usually one would just insert the backend information below. +#include "backendhelper.h" + +#include "mainwindow.h" + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) +{ + setupUi(this); + QByteArray EnginioBackendId = backendId("cloudaddressbook"); + + //![client] + client = new EnginioClient(this); + client->setBackendId(EnginioBackendId); + //![client] + + // this line is a debugging conviniance, passing all errors to qDebug() + QObject::connect(client, &EnginioClient::error, this, &MainWindow::error); + + //![model] + model = new AddressBookModel(this); + model->setClient(client); + + QJsonObject query; + query["objectType"] = QString::fromUtf8("objects.addressbook"); + model->setQuery(query); + //![model] + + tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); + + //![assignProxyModel] + QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this); + proxyModel->setSourceModel(model); + tableView->setSortingEnabled(true); + tableView->setModel(proxyModel); + //![assignProxyModel] + + // create the full text search based on searchEdit text value + QObject::connect(searchEdit, &QLineEdit::returnPressed, this, &MainWindow::onSearchEdit); + + // clear the status bar when the search is finished + QObject::connect(model, &AddressBookModel::searchFinished, this, &MainWindow::onSearchFinished); + + // append an empty row + QObject::connect(add, &QPushButton::clicked, this, &MainWindow::onAddRow); + + // enable remove button when a row is selected + QObject::connect(tableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MainWindow::onSelectionChanged); + + // remove selected rows + QObject::connect(remove, &QPushButton::clicked, this, &MainWindow::onRemoveRow); +} + +void MainWindow::onSearchEdit() +{ + model->newSearch(searchEdit->text()); + statusbar->showMessage(QStringLiteral("Searching for: ") + searchEdit->text()); + searchEdit->clear(); +} + +void MainWindow::onSearchFinished() +{ + statusbar->showMessage(QStringLiteral("Search finished"), 1500); +} + +void MainWindow::onAddRow() +{ + QJsonObject item; + item.insert("objectType", QString::fromUtf8("objects.addressbook")); + EnginioReply *reply = model->append(item); + QObject::connect(reply, &EnginioReply::finished, reply, &EnginioReply::deleteLater); +} + +void MainWindow::onSelectionChanged() +{ + remove->setEnabled(tableView->selectionModel()->selectedRows().count()); +} + +void MainWindow::onRemoveRow() +{ + foreach (const QModelIndex &index, tableView->selectionModel()->selectedRows()) { + EnginioReply *reply = model->remove(index.row()); + QObject::connect(reply, &EnginioReply::finished, reply, &EnginioReply::deleteLater); + } +} + +void MainWindow::error(EnginioReply *error) +{ + qWarning() << Q_FUNC_INFO << error; +} + + diff --git a/examples/enginio/widgets/cloudaddressbook/mainwindow.h b/examples/enginio/widgets/cloudaddressbook/mainwindow.h new file mode 100644 index 0000000..7161792 --- /dev/null +++ b/examples/enginio/widgets/cloudaddressbook/mainwindow.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 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$ +** +****************************************************************************/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <QtWidgets/qmainwindow.h> +#include "ui_mainwindow.h" + +QT_BEGIN_NAMESPACE +class EnginioClient; +class EnginioReply; +QT_END_NAMESPACE + + +QT_USE_NAMESPACE + +class AddressBookModel; +class MainWindow : public QMainWindow, Ui_MainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget *parent = 0); + +private slots: + void onSearchEdit(); + void onSearchFinished(); + void onAddRow(); + void onSelectionChanged(); + void onRemoveRow(); + void error(EnginioReply *error); + +private: + // The Enginio client object used in all enginio operations + EnginioClient *client; + + // Enginio object model containing addresses + AddressBookModel *model; +}; + +#endif // MAINWINDOW_H diff --git a/examples/enginio/widgets/cloudaddressbook/mainwindow.ui b/examples/enginio/widgets/cloudaddressbook/mainwindow.ui new file mode 100644 index 0000000..cb68852 --- /dev/null +++ b/examples/enginio/widgets/cloudaddressbook/mainwindow.ui @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>640</width> + <height>480</height> + </rect> + </property> + <property name="windowTitle"> + <string>Enginio address book example</string> + </property> + <widget class="QWidget" name="centralwidget"> + <layout class="QGridLayout" name="gridLayout"> + <item row="2" column="0" colspan="3"> + <widget class="QLineEdit" name="searchEdit"> + <property name="toolTip"> + <string>Type here a phrase to search</string> + </property> + <property name="placeholderText"> + <string>Search phrase</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="0" colspan="3"> + <widget class="QTableView" name="tableView"> + <property name="toolTip"> + <string>address book </string> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QPushButton" name="add"> + <property name="text"> + <string>Add</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QPushButton" name="remove"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Remove</string> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QStatusBar" name="statusbar"/> + </widget> + <resources/> + <connections/> +</ui> diff --git a/examples/enginio/widgets/image-gallery-cpp/doc/src/image-gallery-cpp.qdoc b/examples/enginio/widgets/image-gallery-cpp/doc/src/image-gallery-cpp.qdoc new file mode 100644 index 0000000..13613fb --- /dev/null +++ b/examples/enginio/widgets/image-gallery-cpp/doc/src/image-gallery-cpp.qdoc @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ +/*! + \title Enginio C++ Examples - Image Gallery + \example image-gallery-cpp + \brief This is an example that demonstrates uploading and downloading of files in Enginio. + \ingroup enginio-examples + \inmodule enginio-qt + + The user interface consists of a list of images and a button to upload more images. + + \section1 Backend configuration + The Enginio backend needs to be set up in order to get this example working. + + Go to the Enginio Dashboard and create a new backend with the 'Image Gallery' template. + The template will construct a new custom backend by executing these steps: + \list + \li Create a new object type "objects.image" (on the Object Types page). + + Add two properties to the image object: + name:"name", type: "String" and name: "file", type: "Ref" with target "files". + + \li Add a file processor by clicking the "file" property. + Choose "Image processor" and in "Variants" enter: + \code + { + "thumbnail": { "crop":"100x100" } + } + \endcode + This JSON snippet triggers the server to generate thumbnails for all uploaded images. + In the image gallery, the thumbnails will be used in the list view, and the full image will be shown + when the thumbnail is clicked. + \endlist + + Copy the backend Id from the Enginio dashboard and use them when requested. + + \section1 The example code + + The example consists of three classes. + ImageModel is a subclass of \l {EnginioModelCpp}{EnginioModel} + that exposes the images in the \l Qt::DecorationRole for the list view. + In the MainWindow, a normal QListView is used to display the model contents. + The ImageObject is a class that takes care of the download and emits a signal + when an image has been downloaded. + + +*/ diff --git a/examples/enginio/widgets/image-gallery-cpp/image-gallery-cpp.pro b/examples/enginio/widgets/image-gallery-cpp/image-gallery-cpp.pro new file mode 100644 index 0000000..fad9ce1 --- /dev/null +++ b/examples/enginio/widgets/image-gallery-cpp/image-gallery-cpp.pro @@ -0,0 +1,17 @@ +QT += network gui widgets enginio + +TARGET = image-gallery +TEMPLATE = app + +include(../../common/backendhelper/backendhelper.pri) + +SOURCES += \ + main.cpp\ + mainwindow.cpp \ + imageobject.cpp \ + imagemodel.cpp + +HEADERS += \ + mainwindow.h \ + imageobject.h \ + imagemodel.h diff --git a/examples/enginio/widgets/image-gallery-cpp/imagemodel.cpp b/examples/enginio/widgets/image-gallery-cpp/imagemodel.cpp new file mode 100644 index 0000000..68bc813 --- /dev/null +++ b/examples/enginio/widgets/image-gallery-cpp/imagemodel.cpp @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 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$ +** +****************************************************************************/ + +#include "imagemodel.h" +#include "qabstractitemmodel.h" +#include <qjsonvalue.h> +#include <qjsonobject.h> +#include <qvariant.h> +#include <qicon.h> +#include <QtCore/qdatetime.h> + +ImageModel::ImageModel(QObject *parent) + : EnginioModel(parent) +{ + connect(this, SIGNAL(modelReset()), this, SLOT(reset())); + connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)), + this, SLOT(updateRows(QModelIndex,int,int))); + + connect(this, SIGNAL(dataChanged(QModelIndex,QModelIndex)), + this, SLOT(onDataChanged(QModelIndex,QModelIndex))); +} + +void ImageModel::reset() +{ + updateRows(QModelIndex(), 0, rowCount() - 1); +} + +void ImageModel::updateRows(const QModelIndex &, int start, int end) +{ + for (int row = start; row <= end; ++row) { + QJsonValue rowData = EnginioModel::data(index(row)).value<QJsonValue>(); + QString id = rowData.toObject().value("id").toString(); + if (id.isEmpty() || m_images.contains(id)) + continue; + ImageObject *image = new ImageObject(client()); + connect(image, SIGNAL(imageChanged(QString)), this, SLOT(imageChanged(QString))); + m_images.insert(id, image); + image->setObject(rowData.toObject()); + QModelIndex changedIndex = index(row); + emit dataChanged(changedIndex, changedIndex); + } +} + +void ImageModel::imageChanged(const QString &id) +{ + for (int row = 0; row < rowCount(); ++row) { + if (data(index(row), Enginio::IdRole).toString() == id) { + QModelIndex changedIndex = index(row); + emit dataChanged(changedIndex, changedIndex); + } + } +} + +void ImageModel::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) +{ + int start = topLeft.row(); + int end = bottomRight.row(); + + updateRows(QModelIndex(), start, end); +} + +QVariant ImageModel::data(const QModelIndex &index, int role) const +{ + switch (role) { + case Qt::DecorationRole: { + QJsonObject rowData = EnginioModel::data(index).value<QJsonValue>().toObject(); + QString id = rowData.value("id").toString(); + if (m_images.contains(id)) + return m_images.value(id)->thumbnail(); + return QVariant(); + } + case Qt::SizeHintRole: { + return QVariant(QSize(100, 100)); + } + } + + return EnginioModel::data(index, role); +} + +Qt::ItemFlags ImageModel::flags(const QModelIndex &index) const +{ + return QAbstractListModel::flags(index) & ~Qt::ItemIsSelectable; +} diff --git a/examples/enginio/widgets/image-gallery-cpp/imagemodel.h b/examples/enginio/widgets/image-gallery-cpp/imagemodel.h new file mode 100644 index 0000000..89125c9 --- /dev/null +++ b/examples/enginio/widgets/image-gallery-cpp/imagemodel.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 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$ +** +****************************************************************************/ + +#include <enginiomodel.h> +#include "imageobject.h" + +#ifndef IMAGEMODEL_H +#define IMAGEMODEL_H +class ImageModel : public EnginioModel +{ + Q_OBJECT +public: + ImageModel(QObject *parent = 0); + + QVariant data(const QModelIndex &index, int role) const; + + virtual Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; + +public slots: + void updateRows(const QModelIndex &, int start, int end); + void onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); + void reset(); + void imageChanged(const QString &id); + +private: + QMap<QString, ImageObject*> m_images; + +}; + +#endif diff --git a/examples/enginio/widgets/image-gallery-cpp/imageobject.cpp b/examples/enginio/widgets/image-gallery-cpp/imageobject.cpp new file mode 100644 index 0000000..ab1ebe6 --- /dev/null +++ b/examples/enginio/widgets/image-gallery-cpp/imageobject.cpp @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 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$ +** +****************************************************************************/ + +#include "imageobject.h" + +#include <QtNetwork> +#include <Enginio/enginioclient.h> +#include <Enginio/enginioreply.h> + +ImageObject::ImageObject(EnginioClient *enginio) + : m_enginio(enginio) +{} + +void ImageObject::setObject(const QJsonObject &object) +{ + m_object = object; + QString fileId; + fileId = object.value("file").toObject().value("id").toString(); + + if (!fileId.isEmpty()) { + QJsonObject fileObject; + fileObject.insert("id", fileId); + fileObject.insert("variant", QString("thumbnail")); + EnginioReply *reply = m_enginio->downloadUrl(fileObject); + connect(reply, SIGNAL(finished(EnginioReply*)), this, SLOT(replyFinished(EnginioReply*))); + } else { + // Try to fall back to the local file + QString localPath = object.value("localPath").toString(); + if (QFile::exists(localPath)) { + m_image = QImage(localPath); + emit imageChanged(object.value("id").toString()); + } + } +} + +void ImageObject::replyFinished(EnginioReply *enginioReply) +{ + QString url = enginioReply->data().value("expiringUrl").toString(); + QNetworkRequest request(url); + m_reply = m_enginio->networkManager()->get(request); + m_reply->setParent(this); + connect(m_reply, SIGNAL(finished()), this, SLOT(downloadFinished())); +} + +void ImageObject::downloadFinished() +{ + QByteArray imageData = m_reply->readAll(); + m_image.loadFromData(imageData); + emit imageChanged(m_object.value("id").toString()); + + m_reply->deleteLater(); + m_reply = 0; +} + +QPixmap ImageObject::thumbnail() +{ + if (m_image.isNull() || !m_thumbnail.size().isNull()) + return m_thumbnail; + m_thumbnail = QPixmap::fromImage(m_image.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + return m_thumbnail; +} diff --git a/examples/enginio/widgets/image-gallery-cpp/imageobject.h b/examples/enginio/widgets/image-gallery-cpp/imageobject.h new file mode 100644 index 0000000..60c46bb --- /dev/null +++ b/examples/enginio/widgets/image-gallery-cpp/imageobject.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 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$ +** +****************************************************************************/ + +#ifndef IMAGEOBJECT_H +#define IMAGEOBJECT_H + +#include <QtCore> +#include <QtGui> + +QT_BEGIN_NAMESPACE +class QNetworkReply; +class EnginioClient; +class EnginioReply; +QT_END_NAMESPACE +QT_USE_NAMESPACE + +class ImageObject : public QObject +{ + Q_OBJECT +public: + explicit ImageObject(EnginioClient *enginio); + + void setObject(const QJsonObject &object); + + QImage image() { return m_image; } + QPixmap thumbnail(); + +signals: + void imageChanged(const QString &id); + +private slots: + void replyFinished(EnginioReply *enginioReply); + void downloadFinished(); + +private: + QImage m_image; + QPixmap m_thumbnail; + QNetworkReply *m_reply; + EnginioClient *m_enginio; + QJsonObject m_object; +}; + +#endif // IMAGEOBJECT_H diff --git a/examples/enginio/widgets/image-gallery-cpp/main.cpp b/examples/enginio/widgets/image-gallery-cpp/main.cpp new file mode 100644 index 0000000..18d6793 --- /dev/null +++ b/examples/enginio/widgets/image-gallery-cpp/main.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 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$ +** +****************************************************************************/ + +#include "mainwindow.h" +#include <QApplication> + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/examples/enginio/widgets/image-gallery-cpp/mainwindow.cpp b/examples/enginio/widgets/image-gallery-cpp/mainwindow.cpp new file mode 100644 index 0000000..18f2c49 --- /dev/null +++ b/examples/enginio/widgets/image-gallery-cpp/mainwindow.cpp @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 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$ +** +****************************************************************************/ + +#include <QtWidgets> +#include <QDebug> +#include <QFrame> +#include <QLabel> +#include <QListView> +#include <QMenu> +#include <QNetworkAccessManager> +#include <QPushButton> +#include <QTimer> +#include <QVBoxLayout> + +#include <enginioclient.h> +#include <enginioreply.h> + +// To get the backend right, we use a helper class in the example. +// Usually one would just insert the backend information below. +#include "backendhelper.h" + +#include "imageobject.h" +#include "mainwindow.h" +#include "imagemodel.h" + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) +{ + setWindowTitle(QStringLiteral("Enginio Image Gallery")); + + m_client = new EnginioClient(this); + m_client->setBackendId(backendId("image-gallery")); + + m_model = new ImageModel(this); + m_model->setClient(m_client); + + m_view = new QListView; + m_view->setModel(m_model); + m_view->setViewMode(QListView::IconMode); + m_view->setGridSize(QSize(104, 104)); + + m_fileDialog = new QFileDialog(this); + m_fileDialog->setFileMode(QFileDialog::ExistingFile); + m_fileDialog->setNameFilter("Image files (*.png *.jpg *.jpeg)"); + connect(m_fileDialog, SIGNAL(fileSelected(QString)), + this, SLOT(fileSelected(QString))); + + m_uploadButton = new QPushButton("Upload image"); + connect(m_uploadButton, SIGNAL(clicked()), + m_fileDialog, SLOT(show())); + + QFrame *frame = new QFrame; + QVBoxLayout *windowLayout = new QVBoxLayout(frame); + windowLayout->addWidget(m_view); + windowLayout->addWidget(m_uploadButton); + setCentralWidget(frame); + + queryImages(); +} + +QSize MainWindow::sizeHint() const +{ + return QSize(500, 700); +} + +void MainWindow::queryImages() +{ + QJsonObject query; + query.insert("objectType", QStringLiteral("objects.image")); + QJsonObject fileObject; + fileObject.insert("file", QJsonObject()); + + // Use include parameter to request full "file" object for every result + // object including image and thumbnail URLs. + query.insert("include", fileObject); + + // Filter out objects which have not yet been uploaded completely + QJsonObject filter; + QJsonObject exists; + exists.insert("$exists", true); + filter.insert("file.id", exists); + query.insert("query", filter); + + m_model->setQuery(query); +} + +void MainWindow::error(EnginioReply *error) +{ + qWarning() << Q_FUNC_INFO << error; +} + +void MainWindow::fileSelected(const QString &filePath) +{ + if (filePath.isEmpty()) + return; + + QJsonObject object; + object.insert("objectType", QString("objects.image")); + QString fileName = filePath.split(QDir::separator()).last(); + object.insert("name", fileName); + object.insert("localPath", filePath); + EnginioReply *reply = m_model->append(object); + connect(reply, SIGNAL(finished(EnginioReply*)), this, SLOT(beginUpload(EnginioReply*))); +} + +void MainWindow::beginUpload(EnginioReply *reply) +{ + reply->deleteLater(); + QString path = reply->data().value("localPath").toString(); + QString objectId = reply->data().value("id").toString(); + + QJsonObject object; + object.insert("id", objectId); + object.insert("objectType", QStringLiteral("objects.image")); + object.insert("propertyName", QStringLiteral("file")); + + QJsonObject fileObject; + fileObject.insert(QStringLiteral("fileName"), path); + + QJsonObject uploadJson; + uploadJson.insert(QStringLiteral("targetFileProperty"), object); + uploadJson.insert(QStringLiteral("file"), fileObject); + + EnginioReply *upload = m_client->uploadFile(uploadJson, QUrl::fromUserInput(path)); + connect(upload, SIGNAL(finished(EnginioReply*)), upload, SLOT(deleteLater())); +} diff --git a/examples/enginio/widgets/image-gallery-cpp/mainwindow.h b/examples/enginio/widgets/image-gallery-cpp/mainwindow.h new file mode 100644 index 0000000..01f119e --- /dev/null +++ b/examples/enginio/widgets/image-gallery-cpp/mainwindow.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 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$ +** +****************************************************************************/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <QMainWindow> +#include <QMap> +#include <QModelIndex> + +QT_BEGIN_NAMESPACE +class EnginioClient; +class EnginioReply; +class QFileDialog; +class QListView; +class QNetworkReply; +class QPushButton; +QT_END_NAMESPACE +QT_USE_NAMESPACE + +class ImageModel; +class ImageObject; +class ImageDownloader; + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget *parent = 0); + virtual QSize sizeHint() const; + +private slots: + void queryImages(); + void error(EnginioReply *error); + void beginUpload(EnginioReply *reply); + void fileSelected(const QString &file); + +private: + // The Enginio client object used in all enginio operations + EnginioClient *m_client; + + // Enginio object model containing image objects + ImageModel *m_model; + + // The list view showing contents of m_model + QListView *m_view; + QPushButton *m_uploadButton; + QFileDialog *m_fileDialog; +}; + +#endif // MAINWINDOW_H diff --git a/examples/enginio/widgets/todos-cpp/doc/src/todos-cpp.qdoc b/examples/enginio/widgets/todos-cpp/doc/src/todos-cpp.qdoc new file mode 100644 index 0000000..7d0b689 --- /dev/null +++ b/examples/enginio/widgets/todos-cpp/doc/src/todos-cpp.qdoc @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ +/*! + \title Enginio C++ Examples - Todos + \example todos-cpp + \brief The Todo example shows the \l {EnginioModelCpp}{EnginioModel} usage together with QtWigets. + \ingroup enginio-examples + \inmodule enginio-qt + + In this example, a simple list of objects is displayed in a \l QListView. + Each item in the list is a "To Do" object which can be "done" or "not yet done". + Todos can be added, removed, or altered. + + In this simple schema the objects will have two properties that are added + to the default properties (such as creation date which always exists): + a string "title" and a bool "completed". The object type will be created + when a call to create, or in this case EnginoModel::append(), is made. + + A todo object will look like this (in JSON): + \code +{ + "title": "Buy Milk", + "completed": false +} + \endcode + + The first step is to create a TodosModel which inherits \l {EnginioModelCpp}{EnginioModel} + and defines the main roles which will be used. As we are interested in the To Do \c title + and the \c completed information we need to define these two roles. + \snippet todos-cpp/todosmodel.h definition + + By default views (for example \l QListView) use the \l{Qt::ItemDataRole} role to display or edit the content. + The newly created \l{EnginioModelCpp}{EnginioModel} is empty and defines basic roles. Most roles are created + dynamically, based on the json data-structure. They have no predefined value in the \l Qt::ItemDataRole enum. + \l{EnginioModelCpp}{EnginioModel} automatically populates itself as soon as the + \l{EnginioModel::query}{query} and \l{EnginioModel::enginio}{enginio} properties have been set. + When the data is downloaded, the model resets itself, and sets up the internal data cache and roles names. + \l{EnginioModelCpp}{EnginioModel} guesses the role names based on heuristics and it may be wrong if not all + objects received from the backend have exactly the same structure, for example a property can be missing + in certain objects. To protect against such cases we overload \l{EnginioModel::roleNames}{roleNames()}. + Overriding \l{EnginioModel::roleNames}{roleNames()} can also be used to match default Qt roles to the named + ones. + + \snippet todos-cpp/todosmodel.cpp roleNames + + In this example we map the \l Qt::DisplayRole and \l Qt::EditRole to the "title" property in the JSON. + This way the right string is shown by default and editing works as expected. + + Remember to always call the base class implementation to avoid situations in which the internal cache is not in sync. + + By default \l {EnginioModelCpp}{EnginioModel} operates on \l{QJsonValue}, and that is + what the \l{EnginioModel::data()}{data()} function returns inside the \l QVariant, but standard + views, such as \l QListView, use predefined roles which do not map directly to our roles. + That is why we need to write a mapping between them: + + \snippet todos-cpp/todosmodel.cpp data + + As we have our model defined, we need to create an instance of \l EnginioClient: + + \snippet todos-cpp/mainwindow.cpp client + + It is used by model to connect to the Enginio backend. Next we need to construct + and configure our model too. The configuration is based on two steps, assigning + an \l EnginioClient instance and by creating a query. + + \snippet todos-cpp/mainwindow.cpp model + + The model has to be assigned to a view, in our case it is a \l QListView. + + \snippet todos-cpp/mainwindow.cpp assignModel + + To make the application fully functional, a way to add and remove "To Dos" is needed. + To do so, we need to connect correct buttons to slots for adding a new item: + + \snippet todos-cpp/mainwindow.cpp appendItem + + and for removing it: + + \snippet todos-cpp/mainwindow.cpp removeItem +*/ diff --git a/examples/enginio/widgets/todos-cpp/main.cpp b/examples/enginio/widgets/todos-cpp/main.cpp new file mode 100644 index 0000000..8794f32 --- /dev/null +++ b/examples/enginio/widgets/todos-cpp/main.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 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$ +** +****************************************************************************/ + +#include "mainwindow.h" +#include <QApplication> + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/examples/enginio/widgets/todos-cpp/mainwindow.cpp b/examples/enginio/widgets/todos-cpp/mainwindow.cpp new file mode 100644 index 0000000..2293aa0 --- /dev/null +++ b/examples/enginio/widgets/todos-cpp/mainwindow.cpp @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 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$ +** +****************************************************************************/ + +#include <QtWidgets/qframe.h> +#include <QtWidgets/qlabel.h> +#include <QtWidgets/qlistview.h> +#include <QtWidgets/qpushbutton.h> +#include <QtWidgets/qtoolbar.h> +#include <QtWidgets/qinputdialog.h> +#include <QtWidgets/qlayout.h> + +#include <QtCore/qjsondocument.h> +#include <QtCore/qjsonobject.h> + +#include <Enginio/enginioclient.h> +#include <Enginio/enginioreply.h> + +// To get the backend right, we use a helper class in the example. +// Usually one would just insert the backend information below. +#include "backendhelper.h" + +#include "mainwindow.h" +#include "todosmodel.h" + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) +{ + setWindowTitle(QStringLiteral("Enginio TODO example")); + + QByteArray EnginioBackendId = backendId("todo"); + + //![client] + m_client = new EnginioClient(this); + m_client->setBackendId(EnginioBackendId); + //![client] + + QObject::connect(m_client, &EnginioClient::error, this, &MainWindow::error); + + //![model] + m_model = new TodosModel(this); + m_model->setClient(m_client); + + QJsonObject query; + query["objectType"] = QString::fromUtf8("objects.todos"); + m_model->setQuery(query); + //![model] + + QToolBar *toolBar = new QToolBar(this); + m_addNewButton = new QPushButton(toolBar); + m_addNewButton->setText("&Add"); + QObject::connect(m_addNewButton, &QPushButton::clicked, this, &MainWindow::appendItem); + + m_removeButton = new QPushButton(toolBar); + m_removeButton->setText("&Remove"); + m_removeButton->setEnabled(false); + QObject::connect(m_removeButton, &QPushButton::clicked, this, &MainWindow::removeItem); + + m_toggleButton = new QPushButton(toolBar); + m_toggleButton->setText("&Toggle Completed"); + m_toggleButton->setEnabled(false); + QObject::connect(m_toggleButton, &QPushButton::clicked, this, &MainWindow::toggleCompleted); + + toolBar->addWidget(m_addNewButton); + toolBar->addWidget(m_removeButton); + toolBar->addWidget(m_toggleButton); + + m_view = new QTreeView(this); + m_view->setAlternatingRowColors(true); + QFrame *frame = new QFrame(this); + QVBoxLayout *windowLayout = new QVBoxLayout(frame); + windowLayout->addWidget(m_view); + windowLayout->addWidget(toolBar); + setCentralWidget(frame); + + //![assignModel] + m_view->setModel(m_model); + //![assignModel] + + m_view->setSelectionModel(new QItemSelectionModel(m_model, m_model)); + QObject::connect(m_view->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MainWindow::selectionChanged); +} + +QSize MainWindow::sizeHint() const +{ + return QSize(400, 600); +} + +void MainWindow::error(EnginioReply *error) +{ + qWarning() << Q_FUNC_INFO << error; +} + +//![removeItem] +void MainWindow::removeItem() +{ + QModelIndex index = m_view->currentIndex(); + EnginioReply *reply = m_model->remove(index.row()); + QObject::connect(reply, &EnginioReply::finished, reply, &EnginioReply::deleteLater); +} +//![removeItem] + +//![appendItem] +void MainWindow::appendItem() +{ + bool ok; + QString text = QInputDialog::getText(this, tr("Create a new To Do") + , tr("Title:"), QLineEdit::Normal + , "", &ok); + if (ok && !text.isEmpty()){ + QJsonObject object; + object["title"] = text; + object["completed"] = false; // By default a new To Do is not completed + EnginioReply *reply = m_model->append(object); + QObject::connect(reply, &EnginioReply::finished, reply, &EnginioReply::deleteLater); + } +} +//![appendItem] + +void MainWindow::toggleCompleted() +{ + QModelIndex index = m_view->currentIndex(); + bool completed = m_model->data(index, m_model->CompletedRole).toBool(); + m_model->setData(index, QVariant(!completed), TodosModel::CompletedRole); +} + +void MainWindow::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) +{ + Q_UNUSED(deselected); + bool value = selected.count(); + m_removeButton->setEnabled(value); + m_toggleButton->setEnabled(value); +} diff --git a/examples/enginio/widgets/todos-cpp/mainwindow.h b/examples/enginio/widgets/todos-cpp/mainwindow.h new file mode 100644 index 0000000..2d20d9f --- /dev/null +++ b/examples/enginio/widgets/todos-cpp/mainwindow.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 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 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$ +** +****************************************************************************/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <QMainWindow> +#include <QTreeView> + +QT_BEGIN_NAMESPACE +class QPushButton; +class EnginioClient; +class EnginioReply; +QT_END_NAMESPACE +QT_USE_NAMESPACE + +class TodosModel; +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget *parent = 0); + virtual QSize sizeHint() const; + +private slots: + void error(EnginioReply *error); + + void removeItem(); + void appendItem(); + void toggleCompleted(); + void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); + +private: + void queryTodos(); + + // The Enginio client object used in all enginio operations + EnginioClient *m_client; + + // Enginio object model containing todos objects + TodosModel *m_model; + + // The list view showing contents of m_model + QTreeView *m_view; + + QPushButton *m_addNewButton; + QPushButton *m_removeButton; + QPushButton *m_toggleButton; +}; + +#endif // MAINWINDOW_H diff --git a/examples/enginio/widgets/todos-cpp/todos-cpp.pro b/examples/enginio/widgets/todos-cpp/todos-cpp.pro new file mode 100644 index 0000000..3862441 --- /dev/null +++ b/examples/enginio/widgets/todos-cpp/todos-cpp.pro @@ -0,0 +1,15 @@ +QT += network gui widgets enginio + +TARGET = todos +TEMPLATE = app + +include(../../common/backendhelper/backendhelper.pri) + +SOURCES += \ + main.cpp\ + mainwindow.cpp \ + todosmodel.cpp \ + +HEADERS += \ + mainwindow.h \ + todosmodel.h \ diff --git a/examples/enginio/widgets/todos-cpp/todosmodel.cpp b/examples/enginio/widgets/todos-cpp/todosmodel.cpp new file mode 100644 index 0000000..f44c1e5 --- /dev/null +++ b/examples/enginio/widgets/todos-cpp/todosmodel.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 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$ +** +****************************************************************************/ + +#include "todosmodel.h" + +#include <QtCore/qjsonvalue.h> +#include <QtCore/qjsonobject.h> +#include <QtGui/qcolor.h> +#include <QtGui/qfont.h> + +#include <Enginio/enginioreply.h> + +TodosModel::TodosModel(QObject *parent) + : EnginioModel(parent) +{} + +QVariant TodosModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && section == 0 && role == Qt::DisplayRole) + return QStringLiteral("Todo List"); + return EnginioModel::headerData(section, orientation, role); +} + +//![data] +QVariant TodosModel::data(const QModelIndex &index, int role) const +{ + if (role == Qt::FontRole) { + bool completed = EnginioModel::data(index, CompletedRole).value<QJsonValue>().toBool(); + QFont font; + font.setPointSize(20); + font.setStrikeOut(completed); + return font; + } + + if (role == Qt::TextColorRole) { + bool completed = EnginioModel::data(index, CompletedRole).value<QJsonValue>().toBool(); + return completed ? QColor("#999") : QColor("#333"); + } + + if (role == CompletedRole) + return EnginioModel::data(index, CompletedRole).value<QJsonValue>().toBool(); + + // fallback to base class + return EnginioModel::data(index, role); +} +//![data] +//![roleNames] +QHash<int, QByteArray> TodosModel::roleNames() const +{ + QHash<int, QByteArray> roles = EnginioModel::roleNames(); + roles.insert(TitleRole, "title"); + roles.insert(Qt::DisplayRole, "title"); + roles.insert(Qt::EditRole, "title"); + roles.insert(CompletedRole, "completed"); + return roles; +} +//![roleNames] diff --git a/examples/enginio/widgets/todos-cpp/todosmodel.h b/examples/enginio/widgets/todos-cpp/todosmodel.h new file mode 100644 index 0000000..76e2f19 --- /dev/null +++ b/examples/enginio/widgets/todos-cpp/todosmodel.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 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$ +** +****************************************************************************/ + +#ifndef TODOSMODEL_H +#define TODOSMODEL_H + +#include <Enginio/enginiomodel.h> + +//![definition] +class TodosModel : public EnginioModel +{ + Q_OBJECT + +public: + enum Role + { + TitleRole = Enginio::CustomPropertyRole, + CompletedRole + }; +//![definition] + + explicit TodosModel(QObject *parent = 0); + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE; + + virtual QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE; +}; + +#endif // TODOSMODEL_H diff --git a/examples/enginio/widgets/widgets.pro b/examples/enginio/widgets/widgets.pro new file mode 100644 index 0000000..b3975d9 --- /dev/null +++ b/examples/enginio/widgets/widgets.pro @@ -0,0 +1,6 @@ +TEMPLATE = subdirs + +SUBDIRS += \ + image-gallery-cpp \ + todos-cpp \ + cloudaddressbook \ |