summaryrefslogtreecommitdiff
path: root/examples/enginio
diff options
context:
space:
mode:
authorFrederik Gladhorn <frederik.gladhorn@digia.com>2013-12-06 14:20:59 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-12-06 20:26:58 +0100
commitef22abaf91de79b9b47f20e71305a1cdea177da0 (patch)
tree36860f6a248c233213537b9a729e253a409115ac /examples/enginio
parentf4875461a7133f5978b460940812d9c569a26c23 (diff)
downloadqtenginio-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')
-rw-r--r--examples/enginio/common/backendhelper/BackendHelper.qml126
-rw-r--r--examples/enginio/common/backendhelper/backendhelper.cpp89
-rw-r--r--examples/enginio/common/backendhelper/backendhelper.h48
-rw-r--r--examples/enginio/common/backendhelper/backendhelper.pri6
-rw-r--r--examples/enginio/common/backendhelper/helperdialog.ui115
-rw-r--r--examples/enginio/common/backendhelper/qmlbackendhelper.pri1
-rw-r--r--examples/enginio/common/backendhelper/qmlbackendhelper.qrc8
-rw-r--r--examples/enginio/common/icons/add_icon.pngbin0 -> 2346 bytes
-rw-r--r--examples/enginio/common/icons/add_icon_pressed.pngbin0 -> 2442 bytes
-rw-r--r--examples/enginio/common/icons/back_icon.pngbin0 -> 1590 bytes
-rw-r--r--examples/enginio/common/icons/delete_icon.pngbin0 -> 1891 bytes
-rw-r--r--examples/enginio/common/icons/delete_icon_pressed.pngbin0 -> 1860 bytes
-rw-r--r--examples/enginio/common/icons/reload_icon.pngbin0 -> 2346 bytes
-rw-r--r--examples/enginio/common/icons/reload_icon_pressed.pngbin0 -> 2346 bytes
-rw-r--r--examples/enginio/common/icons/share_icon.pngbin0 -> 2276 bytes
-rw-r--r--examples/enginio/common/icons/share_icon_pressed.pngbin0 -> 2566 bytes
-rw-r--r--examples/enginio/common/images/checkbox.pngbin0 -> 570 bytes
-rw-r--r--examples/enginio/common/images/checkbox_checked.pngbin0 -> 830 bytes
-rw-r--r--examples/enginio/common/images/delegate.pngbin0 -> 6860 bytes
-rw-r--r--examples/enginio/common/images/delegate_pressed.pngbin0 -> 6362 bytes
-rw-r--r--examples/enginio/common/images/enginio.pngbin0 -> 7679 bytes
-rw-r--r--examples/enginio/common/images/shadow.pngbin0 -> 131 bytes
-rw-r--r--examples/enginio/common/images/textfield.pngbin0 -> 2535 bytes
-rw-r--r--examples/enginio/enginio.pro8
-rw-r--r--examples/enginio/quick/image-gallery/doc/images/image-gallery.pngbin0 -> 82046 bytes
-rw-r--r--examples/enginio/quick/image-gallery/doc/src/image-gallery.qdoc94
-rw-r--r--examples/enginio/quick/image-gallery/gallery.qrc16
-rw-r--r--examples/enginio/quick/image-gallery/image-gallery.pro15
-rw-r--r--examples/enginio/quick/image-gallery/image-gallery.qml466
-rw-r--r--examples/enginio/quick/image-gallery/image_gallery80.pngbin0 -> 4945 bytes
-rw-r--r--examples/enginio/quick/main.cpp127
-rw-r--r--examples/enginio/quick/quick.pro7
-rw-r--r--examples/enginio/quick/socialtodos/Header.qml86
-rw-r--r--examples/enginio/quick/socialtodos/List.qml239
-rw-r--r--examples/enginio/quick/socialtodos/Login.qml219
-rw-r--r--examples/enginio/quick/socialtodos/ShareDialog.qml142
-rw-r--r--examples/enginio/quick/socialtodos/TextField.qml101
-rw-r--r--examples/enginio/quick/socialtodos/TodoLists.qml224
-rw-r--r--examples/enginio/quick/socialtodos/TouchButton.qml91
-rw-r--r--examples/enginio/quick/socialtodos/backendconfig/sharedtodo.zipbin0 -> 961 bytes
-rw-r--r--examples/enginio/quick/socialtodos/doc/src/socialtodos.qdoc421
-rw-r--r--examples/enginio/quick/socialtodos/socialtodos.pro21
-rw-r--r--examples/enginio/quick/socialtodos/socialtodos.qml93
-rw-r--r--examples/enginio/quick/socialtodos/socialtodos.qrc30
-rw-r--r--examples/enginio/quick/todos/doc/images/todolist.pngbin0 -> 52293 bytes
-rw-r--r--examples/enginio/quick/todos/doc/src/todos.qdoc91
-rw-r--r--examples/enginio/quick/todos/todo.qml279
-rw-r--r--examples/enginio/quick/todos/todo.qrc18
-rw-r--r--examples/enginio/quick/todos/todos.pro13
-rw-r--r--examples/enginio/quick/users/Browse.qml83
-rw-r--r--examples/enginio/quick/users/Login.qml149
-rw-r--r--examples/enginio/quick/users/Register.qml126
-rw-r--r--examples/enginio/quick/users/doc/src/users.qdoc114
-rw-r--r--examples/enginio/quick/users/users.pro13
-rw-r--r--examples/enginio/quick/users/users.qml92
-rw-r--r--examples/enginio/quick/users/users.qrc8
-rw-r--r--examples/enginio/widgets/cloudaddressbook/addressbookmodel.cpp198
-rw-r--r--examples/enginio/widgets/cloudaddressbook/addressbookmodel.h85
-rw-r--r--examples/enginio/widgets/cloudaddressbook/cloudaddressbook.pro18
-rw-r--r--examples/enginio/widgets/cloudaddressbook/doc/src/cloudaddressbook.qdoc114
-rw-r--r--examples/enginio/widgets/cloudaddressbook/main.cpp51
-rw-r--r--examples/enginio/widgets/cloudaddressbook/mainwindow.cpp148
-rw-r--r--examples/enginio/widgets/cloudaddressbook/mainwindow.h79
-rw-r--r--examples/enginio/widgets/cloudaddressbook/mainwindow.ui71
-rw-r--r--examples/enginio/widgets/image-gallery-cpp/doc/src/image-gallery-cpp.qdoc71
-rw-r--r--examples/enginio/widgets/image-gallery-cpp/image-gallery-cpp.pro17
-rw-r--r--examples/enginio/widgets/image-gallery-cpp/imagemodel.cpp120
-rw-r--r--examples/enginio/widgets/image-gallery-cpp/imagemodel.h67
-rw-r--r--examples/enginio/widgets/image-gallery-cpp/imageobject.cpp98
-rw-r--r--examples/enginio/widgets/image-gallery-cpp/imageobject.h80
-rw-r--r--examples/enginio/widgets/image-gallery-cpp/main.cpp51
-rw-r--r--examples/enginio/widgets/image-gallery-cpp/mainwindow.cpp163
-rw-r--r--examples/enginio/widgets/image-gallery-cpp/mainwindow.h89
-rw-r--r--examples/enginio/widgets/todos-cpp/doc/src/todos-cpp.qdoc104
-rw-r--r--examples/enginio/widgets/todos-cpp/main.cpp51
-rw-r--r--examples/enginio/widgets/todos-cpp/mainwindow.cpp169
-rw-r--r--examples/enginio/widgets/todos-cpp/mainwindow.h88
-rw-r--r--examples/enginio/widgets/todos-cpp/todos-cpp.pro15
-rw-r--r--examples/enginio/widgets/todos-cpp/todosmodel.cpp94
-rw-r--r--examples/enginio/widgets/todos-cpp/todosmodel.h66
-rw-r--r--examples/enginio/widgets/widgets.pro6
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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For the Enginio Examples to work the backend ID is needed. Please copy them from your &lt;a href=&quot;http://engin.io&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Enginio Dashboard.&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Make sure to have the right type of backend or configure it manually according to the example's documentation. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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
new file mode 100644
index 0000000..cfd6fc5
--- /dev/null
+++ b/examples/enginio/common/icons/add_icon.png
Binary files differ
diff --git a/examples/enginio/common/icons/add_icon_pressed.png b/examples/enginio/common/icons/add_icon_pressed.png
new file mode 100644
index 0000000..2d7fe82
--- /dev/null
+++ b/examples/enginio/common/icons/add_icon_pressed.png
Binary files differ
diff --git a/examples/enginio/common/icons/back_icon.png b/examples/enginio/common/icons/back_icon.png
new file mode 100644
index 0000000..5340209
--- /dev/null
+++ b/examples/enginio/common/icons/back_icon.png
Binary files differ
diff --git a/examples/enginio/common/icons/delete_icon.png b/examples/enginio/common/icons/delete_icon.png
new file mode 100644
index 0000000..59abea8
--- /dev/null
+++ b/examples/enginio/common/icons/delete_icon.png
Binary files differ
diff --git a/examples/enginio/common/icons/delete_icon_pressed.png b/examples/enginio/common/icons/delete_icon_pressed.png
new file mode 100644
index 0000000..991dda1
--- /dev/null
+++ b/examples/enginio/common/icons/delete_icon_pressed.png
Binary files differ
diff --git a/examples/enginio/common/icons/reload_icon.png b/examples/enginio/common/icons/reload_icon.png
new file mode 100644
index 0000000..cfd6fc5
--- /dev/null
+++ b/examples/enginio/common/icons/reload_icon.png
Binary files differ
diff --git a/examples/enginio/common/icons/reload_icon_pressed.png b/examples/enginio/common/icons/reload_icon_pressed.png
new file mode 100644
index 0000000..cfd6fc5
--- /dev/null
+++ b/examples/enginio/common/icons/reload_icon_pressed.png
Binary files differ
diff --git a/examples/enginio/common/icons/share_icon.png b/examples/enginio/common/icons/share_icon.png
new file mode 100644
index 0000000..f0f2084
--- /dev/null
+++ b/examples/enginio/common/icons/share_icon.png
Binary files differ
diff --git a/examples/enginio/common/icons/share_icon_pressed.png b/examples/enginio/common/icons/share_icon_pressed.png
new file mode 100644
index 0000000..70421b6
--- /dev/null
+++ b/examples/enginio/common/icons/share_icon_pressed.png
Binary files differ
diff --git a/examples/enginio/common/images/checkbox.png b/examples/enginio/common/images/checkbox.png
new file mode 100644
index 0000000..81d5743
--- /dev/null
+++ b/examples/enginio/common/images/checkbox.png
Binary files differ
diff --git a/examples/enginio/common/images/checkbox_checked.png b/examples/enginio/common/images/checkbox_checked.png
new file mode 100644
index 0000000..a551018
--- /dev/null
+++ b/examples/enginio/common/images/checkbox_checked.png
Binary files differ
diff --git a/examples/enginio/common/images/delegate.png b/examples/enginio/common/images/delegate.png
new file mode 100644
index 0000000..0166ddf
--- /dev/null
+++ b/examples/enginio/common/images/delegate.png
Binary files differ
diff --git a/examples/enginio/common/images/delegate_pressed.png b/examples/enginio/common/images/delegate_pressed.png
new file mode 100644
index 0000000..eba3c11
--- /dev/null
+++ b/examples/enginio/common/images/delegate_pressed.png
Binary files differ
diff --git a/examples/enginio/common/images/enginio.png b/examples/enginio/common/images/enginio.png
new file mode 100644
index 0000000..7d286a1
--- /dev/null
+++ b/examples/enginio/common/images/enginio.png
Binary files differ
diff --git a/examples/enginio/common/images/shadow.png b/examples/enginio/common/images/shadow.png
new file mode 100644
index 0000000..d3eb97f
--- /dev/null
+++ b/examples/enginio/common/images/shadow.png
Binary files differ
diff --git a/examples/enginio/common/images/textfield.png b/examples/enginio/common/images/textfield.png
new file mode 100644
index 0000000..65dc759
--- /dev/null
+++ b/examples/enginio/common/images/textfield.png
Binary files differ
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
new file mode 100644
index 0000000..ed4cc1c
--- /dev/null
+++ b/examples/enginio/quick/image-gallery/doc/images/image-gallery.png
Binary files differ
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
new file mode 100644
index 0000000..6ad8096
--- /dev/null
+++ b/examples/enginio/quick/image-gallery/image_gallery80.png
Binary files differ
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
new file mode 100644
index 0000000..e13e388
--- /dev/null
+++ b/examples/enginio/quick/socialtodos/backendconfig/sharedtodo.zip
Binary files differ
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
new file mode 100644
index 0000000..4bc7849
--- /dev/null
+++ b/examples/enginio/quick/todos/doc/images/todolist.png
Binary files differ
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 \