\n"
+
+include($QT_INSTALL_DOCS/global/qt-html-templates-online.qdocconf)
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/doc/qtwebbrowser-project.qdocconf b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/doc/qtwebbrowser-project.qdocconf
new file mode 100644
index 0000000..3fe897c
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/doc/qtwebbrowser-project.qdocconf
@@ -0,0 +1,36 @@
+project = "QtWebBrowser"
+description = "Qt WebBrowser Manual"
+
+sourcedirs += src
+imagedirs += images
+
+sources.fileextensions = "*.qdoc"
+
+qhp.projects = QtWebBrowser
+qhp.QtWebBrowser.file = qtwebbrowser.qhp
+qhp.QtWebBrowser.namespace = org.qt-project.qtwebbrowser.$$QT_VERSION_TAG
+qhp.QtWebBrowser.virtualFolder = qtwebbrowser
+qhp.QtWebBrowser.indexTitle = Qt WebBrowser
+qhp.QtWebBrowser.filterAttributes = qtwebbrowser
+qhp.QtWebBrowser.customFilters.QtWebBrowser.name = Qt WebBrowser $QT_VERSION
+qhp.QtWebBrowser.customFilters.QtWebBrowser.filterAttributes = qtwebbrowser $QT_VERSION
+qhp.QtWebBrowser.indexRoot =
+
+qhp.QtWebBrowser.subprojects = manual
+qhp.QtWebBrowser.subprojects.manual.indexTitle = Qt WebBrowser
+qhp.QtWebBrowser.subprojects.manual.title = Qt WebBrowser
+qhp.QtWebBrowser.subprojects.manual.type = manual
+
+#indexes += $QT_INSTALL_DOCS/qtlocation/qtlocation.index \
+# $QT_INSTALL_DOCS/qtquick/qtquick.index \
+# $QT_INSTALL_DOCS/qtvirtualkeyboard/qtvirtualkeyboard.index \
+# $QT_INSTALL_DOCS/qtwebengine/qtwebengine.index
+
+depends += qtquick qtlocation qtwebengine qtvirtualkeyboard
+
+# Doxygen compatibility commands
+macro.see = "\\sa"
+macro.function = "\\fn"
+
+navigation.homepage = "Qt WebBrowser Manual"
+buildversion = "Qt WebBrowser $QT_VERSION"
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/doc/qtwebbrowser.qdocconf b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/doc/qtwebbrowser.qdocconf
new file mode 100644
index 0000000..383d83a
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/doc/qtwebbrowser.qdocconf
@@ -0,0 +1,2 @@
+include($QT_INSTALL_DOCS/global/qt-module-defaults-offline.qdocconf)
+include(qtwebbrowser-project.qdocconf)
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/doc/src/external-resources.qdoc b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/doc/src/external-resources.qdoc
new file mode 100644
index 0000000..8a5cc00
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/doc/src/external-resources.qdoc
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt WebBrowser application.
+**
+** $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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \externalpage https://www.chromium.org/
+ \title Chromium Project
+*/
+
+/*!
+ \externalpage https://www.google.com/
+ \title Google
+*/
+
+/*!
+ \externalpage https://doc.qt.io/qt-5/qtwebengine-debugging.html
+ \title Qt WebEngine Debugging and Profiling
+*/
+
+/*
+ This prevents autolinking of each occurrence of 'WebEngine'
+ To link to the WebEngine QML type, use explicit linking:
+ \l [QML] WebEngine
+ \sa {QtWebEngine::}{WebEngine}
+*/
+/*!
+\externalpage nolink
+\title WebEngine
+\internal
+*/
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/doc/src/qtwebbrowser.qdoc b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/doc/src/qtwebbrowser.qdoc
new file mode 100644
index 0000000..08496a0
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/doc/src/qtwebbrowser.qdoc
@@ -0,0 +1,185 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt WebBrowser application.
+**
+** $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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\page qtwebbrowser-index.html
+
+\title Qt WebBrowser
+
+The Qt WebBrowser (codename \c{Roadtrip}) is a browser for embedded
+devices developed using the capabilities of Qt and \l{Qt WebEngine}.
+Using recent \l{Chromium Project}{Chromium}, it features up-to-date
+HTML technologies behind a minimal but slick touch-friendly
+user interface written in \l{Qt Quick}.
+
+\image webbrowser.png
+
+\section1 User Interface
+
+The user interface of the browser is designed for embedded devices
+using a touch screen. It uses flat icons and minimalistic transitions to
+provide a contemporary look and feel.
+
+All central actions are conveniently accessible in the menu bar at the
+top. When the user scrolls down a page, the menu bar disappears to
+leave more screen space for content. It appears again if
+the user scrolls upwards.
+
+\image menubar.png
+
+The \uicontrol Back button (1) and \uicontrol Forward button (2) navigate
+through the history of pages already visited.
+The input bar (3) allows the user to type and edit URL's,
+or search for text. It also allows to reload a page, or stop a page currently
+loading.
+Pages can be bookmarked with the \uicontrol Bookmark button (6),
+the bookmarked pages are accessible through the \uicontrol Home button (4).
+The \uicontrol Pages button (5) allows the user to manage the pages
+currently opened. The \uicontrol Settings button (7) brings up a view of
+the current settings.
+
+\section2 Opening Pages
+
+The input bar supports typing in either a full URL or a query
+that is automatically passed to \l{Google}. Url suggestions of visited pages
+matching the text are suggested during typing. The current text can be
+cleared by pressing the \uicontrol Cancel button on the right.
+
+\image inputhelp.png
+
+When the user finishes editing, a blue line serves as a progress indicator
+for the page currently loading. The loading can be stopped by pressing
+the \uicontrol Cancel button. After the page finished loading
+this button is replaced by a \uicontrol Reload button, that forces a reload
+of the page when pressed.
+
+\section2 Page Scrolling
+
+The view of the page can be moved around by pressing and moving a finger.
+
+\section2 Page Zooming
+
+Zoom in or out a particular section of the page by pinching fingers.
+
+\section2 Bookmark Management
+
+Individual pages can be bookmarked by pressing the \uicontrol Bookmark
+button. By pressing the same button again the page is removed from the
+bookmarks.
+
+The \uicontrol Home button lets the user browse the bookmarked pages
+in a multi-page grid. Each page is represented by its name and icon,
+if available.
+
+\image bookmarks.png
+
+\section2 Page Management
+
+The \uicontrol Pages button enables the user to open new pages and to
+switch between them using the Carousel UI pattern:
+
+\image pageselection.png
+
+The number of pages that can be opened simultaneously is intentionally
+limited to 10.
+
+\section2 User Settings
+
+A settings page is available by pressing the \uicontrol Settings button.
+The page contains options for enabling a \e {private browsing} mode
+that does not leave traces in the history and cookies.
+
+\image settings.png
+
+\section2 Virtual Keyboard
+
+The integrated \l{Qt Virtual Keyboard}
+slides in whenever text input is required. It enables typing text in a
+great variety of different languages.
+
+\image virtualkeyboard.png
+
+\section1 Features
+
+Qt WebEngine leverages \l{Chromium Project}{Chromium} to provide
+a state-of-the art, high performance HTML5 web engine.
+
+\image html5test.png
+
+\section2 Video and Audio
+
+Chromium and therefore Qt WebEngine directly
+integrate with OS services to access video and audio devices.
+After the user acknowledges access to them, solutions using WebRTC, such as
+video and audio conferencing, work out-of-the-box, provided that the
+required codecs are available.
+
+\section2 Location Information
+
+Qt WebEngine uses \l {Qt Location} to provide pages with location
+information. Again, the users have to explicitly give their consent to each
+page attempting to access this information.
+
+\section2 Fullscreen Mode
+
+Videos can be played in fullscreen mode.
+
+\section1 Developer Features
+
+\section2 Developer Tools
+
+Qt WebEngine supports remotely accessing the built-in Chromium Developer
+Tools. This allows debugging and optimizing individual pages on the device.
+
+For more information, see the \l{Qt WebEngine} documentation on
+\l{Qt WebEngine Debugging and Profiling}{Debugging and Profiling}.
+
+\section2 Simulation of Touch Input
+
+While the Qt WebBrowser is optimized for touch devices,
+it can also be tested on all the desktop operating systems.
+Keyboard and mouse input works out of the box. Touch input
+can be simulated by using several mouse buttons
+while pressing the \c Ctrl key.
+
+\section1 Platform Requirements
+
+Qt WebBrowser requires the \l{Qt WebEngine},
+\l{Qt Quick} and
+\l{Qt Virtual Keyboard} modules in version 5.7 or
+newer.
+
+\image block-diagram.png
+
+At minimum 1 GB of RAM is advised to provide a seamless experience
+for different pages. Depending on the exact configuration and the
+pages visited this can be further optimized.
+
+Qt Quick and Qt WebEngine use OpenGL for rendering. Best performance
+therefore requires dedicated graphics hardware with drivers supporting
+OpenGL.
+*/
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/00_HomePage.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/00_HomePage.png
new file mode 100644
index 0000000..cf7c69c
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/00_HomePage.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/00_HomePage_DeleteBookmarks.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/00_HomePage_DeleteBookmarks.png
new file mode 100644
index 0000000..95441e4
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/00_HomePage_DeleteBookmarks.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/01_Browsing.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/01_Browsing.png
new file mode 100644
index 0000000..d93a211
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/01_Browsing.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/01_Browsing_Bookmark.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/01_Browsing_Bookmark.png
new file mode 100644
index 0000000..0b880b8
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/01_Browsing_Bookmark.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/01_Browsing_Loading.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/01_Browsing_Loading.png
new file mode 100644
index 0000000..016b7f7
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/01_Browsing_Loading.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/01_Browsing_NoKb.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/01_Browsing_NoKb.png
new file mode 100644
index 0000000..e330c6c
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/01_Browsing_NoKb.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/01_Browsing_Private.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/01_Browsing_Private.png
new file mode 100644
index 0000000..50d1115
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/01_Browsing_Private.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/01_URLbox+Bookmark.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/01_URLbox+Bookmark.png
new file mode 100644
index 0000000..1d11050
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/01_URLbox+Bookmark.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/01_URLbox.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/01_URLbox.png
new file mode 100644
index 0000000..eec1ae1
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/01_URLbox.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/02_Selection_Link.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/02_Selection_Link.png
new file mode 100644
index 0000000..7edffa0
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/02_Selection_Link.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/02_Selection_Text.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/02_Selection_Text.png
new file mode 100644
index 0000000..476fcbc
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/02_Selection_Text.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/02_Selection_URL.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/02_Selection_URL.png
new file mode 100644
index 0000000..861e774
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/02_Selection_URL.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_1.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_1.png
new file mode 100644
index 0000000..80a9a77
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_1.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_10+.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_10+.png
new file mode 100644
index 0000000..58c833e
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_10+.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_2.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_2.png
new file mode 100644
index 0000000..f4da8ae
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_2.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_3.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_3.png
new file mode 100644
index 0000000..4d89730
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_3.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_4.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_4.png
new file mode 100644
index 0000000..c4c74a0
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_4.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_5+.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_5+.png
new file mode 100644
index 0000000..ccfc920
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_5+.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_5.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_5.png
new file mode 100644
index 0000000..451dec4
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_5.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_New.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_New.png
new file mode 100644
index 0000000..08ef407
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/03_Tabs_New.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/04_Settings.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/04_Settings.png
new file mode 100644
index 0000000..0de35da
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/04_Settings.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/Bookmarks_Button.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/Bookmarks_Button.png
new file mode 100644
index 0000000..83849d3
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/Bookmarks_Button.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/LightWebBrowserFunctions.xlsx b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/LightWebBrowserFunctions.xlsx
new file mode 100644
index 0000000..037813a
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/LightWebBrowserFunctions.xlsx differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/LightWebBrowser_Specs.pdf b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/LightWebBrowser_Specs.pdf
new file mode 100644
index 0000000..8f77fe5
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/mockups/LightWebBrowser_Specs.pdf differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/qtwebbrowser.pro b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/qtwebbrowser.pro
new file mode 100644
index 0000000..619a237
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/qtwebbrowser.pro
@@ -0,0 +1,8 @@
+TEMPLATE = subdirs
+
+SUBDIRS = \
+ doc \
+ src
+
+requires(qtHaveModule(webengine))
+
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/appengine.cpp b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/appengine.cpp
new file mode 100644
index 0000000..f48325d
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/appengine.cpp
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt WebBrowser application.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "appengine.h"
+
+#include
+#include
+#include
+#include
+
+AppEngine::AppEngine(QObject *parent)
+ : QObject(parent)
+ , m_settings(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) % QDir::separator() % "settings.ini", QSettings::IniFormat, this)
+{
+ foreach (const QString &arg, QCoreApplication::arguments().mid(1)) {
+ if (arg.startsWith('-'))
+ continue;
+ const QUrl url(http://github.com/arg);
+ if (url.isValid()) {
+ m_initialUrl = url.toString();
+ break;
+ }
+ }
+}
+
+QString AppEngine::settingsPath()
+{
+ return m_settings.fileName();
+}
+
+QString AppEngine::initialUrl() const
+{
+ return m_initialUrl;
+}
+
+QUrl AppEngine::fromUserInput(const QString& userInput)
+{
+ QFileInfo fileInfo(userInput);
+ if (fileInfo.exists())
+ return QUrl::fromLocalFile(fileInfo.absoluteFilePath());
+ return QUrl::fromUserInput(userInput);
+}
+
+bool AppEngine::isUrl(const QString& userInput)
+{
+ if (userInput.startsWith(QStringLiteral("www."))
+ || userInput.startsWith(QStringLiteral("http"))
+ || userInput.startsWith(QStringLiteral("ftp"))
+ || userInput.contains(QStringLiteral("://"))
+ || userInput.endsWith(QStringLiteral(".com")))
+ return true;
+ return false;
+}
+
+QString AppEngine::domainFromString(const QString& urlString)
+{
+ return QUrl::fromUserInput(urlString).host();
+}
+
+QString AppEngine::fallbackColor()
+{
+ static QList colors = QList() << QStringLiteral("#46a2da")
+ << QStringLiteral("#18394c")
+ << QStringLiteral("#ff8c0a")
+ << QStringLiteral("#5caa15");
+ static int index = -1;
+ if (++index == colors.count())
+ index = 0;
+ return colors[index];
+}
+
+QString AppEngine::restoreSetting(const QString &name, const QString &defaultValue)
+{
+ return m_settings.value(name, defaultValue).toString();
+}
+
+void AppEngine::saveSetting(const QString &name, const QString &value)
+{
+ m_settings.setValue(name, value);
+}
+
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/appengine.h b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/appengine.h
new file mode 100644
index 0000000..c5ad20e
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/appengine.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt WebBrowser application.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef APPENGINE_H
+#define APPENGINE_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace utils {
+inline bool isTouchEvent(const QEvent* event)
+{
+ switch (event->type()) {
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ return true;
+ default:
+ return false;
+ }
+}
+
+inline bool isMouseEvent(const QEvent* event)
+{
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseMove:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ return true;
+ default:
+ return false;
+ }
+}
+
+}
+
+class AppEngine : public QObject {
+ Q_OBJECT
+
+ Q_PROPERTY(QString settingsPath READ settingsPath FINAL CONSTANT)
+ Q_PROPERTY(QString initialUrl READ initialUrl FINAL CONSTANT)
+
+public:
+ AppEngine(QObject *parent = 0);
+
+ QString settingsPath();
+ QString initialUrl() const;
+
+ Q_INVOKABLE bool isUrl(const QString& userInput);
+ Q_INVOKABLE QUrl fromUserInput(const QString& userInput);
+ Q_INVOKABLE QString domainFromString(const QString& urlString);
+ Q_INVOKABLE QString fallbackColor();
+ Q_INVOKABLE QString restoreSetting(const QString &name, const QString &defaultValue = QString());
+ Q_INVOKABLE void saveSetting(const QString &name, const QString &value);
+
+private:
+ QSettings m_settings;
+ QString m_initialUrl;
+};
+
+#endif // APPENGINE_H
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/main.cpp b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/main.cpp
new file mode 100644
index 0000000..e21440a
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/main.cpp
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt WebBrowser application.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "appengine.h"
+#include "navigationhistoryproxymodel.h"
+#include "touchtracker.h"
+
+#if defined(DESKTOP_BUILD)
+#include "touchmockingapplication.h"
+#endif
+
+#include
+#include
+#include
+#include
+#include
+
+static QObject *engine_factory(QQmlEngine *engine, QJSEngine *scriptEngine)
+{
+ Q_UNUSED(engine);
+ Q_UNUSED(scriptEngine);
+ AppEngine *eng = new AppEngine();
+ return eng;
+}
+
+int main(int argc, char **argv)
+{
+ qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard"));
+
+ //do not use any plugins installed on the device
+ qputenv("QML2_IMPORT_PATH", QByteArray());
+
+ // We use touch mocking on desktop and apply all the mobile switches.
+ QByteArrayList args = QByteArrayList()
+ << QByteArrayLiteral("--enable-embedded-switches")
+ << QByteArrayLiteral("--log-level=0");
+ const int count = args.size() + argc;
+ QVector qargv(count);
+
+ qargv[0] = argv[0];
+ for (int i = 0; i < args.size(); ++i)
+ qargv[i + 1] = args[i].data();
+ for (int i = args.size() + 1; i < count; ++i)
+ qargv[i] = argv[i - args.size()];
+
+ int qAppArgCount = qargv.size();
+
+#if defined(DESKTOP_BUILD)
+ TouchMockingApplication app(qAppArgCount, qargv.data());
+#else
+ QGuiApplication app(qAppArgCount, qargv.data());
+#endif
+
+ qmlRegisterType("WebBrowser", 1, 0, "SearchProxyModel");
+ qmlRegisterType("WebBrowser", 1, 0, "TouchTracker");
+ qmlRegisterSingletonType("WebBrowser", 1, 0, "AppEngine", engine_factory);
+
+ QtWebEngine::initialize();
+
+ app.setOrganizationName("The Qt Company");
+ app.setOrganizationDomain("qt.io");
+ app.setApplicationName("qtwebbrowser");
+
+ QQuickView view;
+ view.setTitle("Qt WebBrowser");
+ view.setFlags(Qt::Window | Qt::WindowTitleHint);
+ view.setResizeMode(QQuickView::SizeRootObjectToView);
+ view.setColor(Qt::black);
+ view.setSource(QUrl("qrc:///qml/Main.qml"));
+
+ QObject::connect(view.engine(), SIGNAL(quit()), &app, SLOT(quit()));
+
+#if defined(DESKTOP_BUILD)
+ view.show();
+ if (view.size().isEmpty())
+ view.setGeometry(0, 0, 800, 600);
+#else
+ view.showFullScreen();
+#endif
+
+ app.exec();
+}
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/navigationhistoryproxymodel.cpp b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/navigationhistoryproxymodel.cpp
new file mode 100644
index 0000000..a124f76
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/navigationhistoryproxymodel.cpp
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt WebBrowser application.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "navigationhistoryproxymodel.h"
+
+NavigationHistoryProxyModel::NavigationHistoryProxyModel(QObject *parent)
+ : QSortFilterProxyModel(parent)
+{
+
+}
+
+bool NavigationHistoryProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
+{
+ QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
+
+ // Use UrlRole and TitleRole instead of DisplayRole
+ return (sourceModel()->data(index, Qt::UserRole + 1).toString().contains(filterRegExp())
+ || sourceModel()->data(index, Qt::UserRole + 2).toString().contains(filterRegExp()));
+}
+
+void NavigationHistoryProxyModel::setEnabled(bool enabled)
+{
+ if (dynamicSortFilter() == enabled)
+ return;
+ setDynamicSortFilter(enabled);
+ emit enabledChanged();
+}
+
+QString NavigationHistoryProxyModel::searchString() const
+{
+ return m_searchString;
+}
+
+void NavigationHistoryProxyModel::setSearchString(const QString &pattern)
+{
+ if (m_searchString == pattern)
+ return;
+
+ m_searchString = pattern;
+ setFilterRegExp(QRegExp(pattern, Qt::CaseInsensitive, QRegExp::FixedString));
+ emit searchStringChanged();
+}
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/navigationhistoryproxymodel.h b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/navigationhistoryproxymodel.h
new file mode 100644
index 0000000..f12cd06
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/navigationhistoryproxymodel.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt WebBrowser application.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef NAVIGATIONHISTORYPROXYMODEL_H
+#define NAVIGATIONHISTORYPROXYMODEL_H
+
+#include
+#include
+#include
+
+class NavigationHistoryProxyModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QAbstractItemModel * target READ sourceModel WRITE setSourceModel)
+ Q_PROPERTY(QString searchString READ searchString WRITE setSearchString NOTIFY searchStringChanged)
+ Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
+
+public:
+ explicit NavigationHistoryProxyModel(QObject *parent = 0);
+
+
+ bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
+
+ bool enabled() const { return dynamicSortFilter(); }
+ void setEnabled(bool enabled);
+
+ void setTarget(QAbstractItemModel *t);
+
+ QString searchString() const ;
+ void setSearchString(const QString &pattern);
+
+signals:
+ void searchStringChanged();
+ void enabledChanged();
+
+private:
+ QString m_searchString;
+};
+
+#endif // NAVIGATIONHISTORYPROXYMODEL_H
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/BrowserWindow.qml b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/BrowserWindow.qml
new file mode 100644
index 0000000..7f4d332
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/BrowserWindow.qml
@@ -0,0 +1,465 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt WebBrowser application.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.5
+import QtWebEngine 1.1
+
+import QtQuick.Controls 1.0
+import QtQuick.Controls.Styles 1.0
+import QtQuick.Layouts 1.0
+import QtQuick.Controls.Private 1.0
+import QtQuick.Dialogs 1.2
+
+import "assets"
+import WebBrowser 1.0
+import "Utils.js" as Utils
+
+Item {
+ id: browserWindow
+
+ property Item currentWebView: {
+ return tabView.get(tabView.currentIndex) ? tabView.get(tabView.currentIndex).item.webView : null
+ }
+
+ property string googleSearchQuery: "https://www.google.com/search?sourceid=qtbrowser&ie=UTF-8&q="
+
+ property int toolBarSize: 80
+ property string uiColor: settingsView.privateBrowsingEnabled ? "#3a4055" : "#09102b"
+
+ property string uiSeparatorColor: "#9d9faa"
+
+ property string toolBarSeparatorColor: "#9d9faa"
+
+ property string toolBarFillColor: settingsView.privateBrowsingEnabled ? "#3a4055" : "#09102b"
+
+ property string buttonPressedColor: "#41cd52"
+ property string emptyBackgroundColor: "#09102b"
+ property string uiHighlightColor: "#41cd52"
+ property string inactivePagerColor: "#bcbdbe"
+ property string textFieldStrokeColor: "#9d9faa"
+ property string placeholderColor: "#a0a1a2"
+ property string iconOverlayColor: "#0e202c"
+ property string iconStrokeColor: "#9d9faa"
+ property string defaultFontFamily: appFont
+
+ property int gridViewPageItemCount: 8
+ property int gridViewMaxBookmarks: 3 * gridViewPageItemCount
+ property int tabViewMaxTabs: 10
+ property int animationDuration: 200
+ property int velocityThreshold: 400
+ property int velocityY: 0
+ property real touchY: 0
+ property real touchReference: 0
+ property bool touchGesture: false
+
+ width: 1024
+ height: 600
+ visible: true
+
+ Action {
+ shortcut: "Ctrl+D"
+ onTriggered: {
+ downloadView.visible = !downloadView.visible
+ }
+ }
+
+ Action {
+ id: focus
+ shortcut: "Ctrl+L"
+ onTriggered: {
+ navigation.addressBar.forceActiveFocus();
+ navigation.addressBar.selectAll();
+ }
+ }
+ Action {
+ shortcut: "Ctrl+R"
+ onTriggered: {
+ if (currentWebView)
+ currentWebView.reload()
+ navigation.addressBar.forceActiveFocus()
+ }
+ }
+ Action {
+ id: newTabAction
+ shortcut: "Ctrl+T"
+ onTriggered: {
+ tabView.get(tabView.currentIndex).item.webView.takeSnapshot()
+ var tab = tabView.createEmptyTab()
+
+ if (!tab)
+ return
+
+ navigation.addressBar.selectAll();
+ tabView.makeCurrent(tabView.count - 1)
+ navigation.addressBar.forceActiveFocus()
+ }
+ }
+ Action {
+ shortcut: "Ctrl+W"
+ onTriggered: tabView.remove(tabView.currentIndex)
+ }
+
+ UIToolBar {
+ id: tabEditToolBar
+
+ source: "icons/Btn_Add.png"
+ indicator: tabView.count
+
+ anchors {
+ left: parent.left
+ right: parent.right
+ top: navigation.top
+ }
+
+ visible: opacity != 0.0
+ opacity: tabView.viewState == "list" ? 1.0 : 0.0
+ onDoneClicked: tabView.viewState = "page"
+ onOptionClicked: newTabAction.trigger()
+ }
+
+ UIToolBar {
+ id: settingsToolBar
+ z: 5
+ title: qsTr("Settings")
+ visible: opacity != 0.0
+
+ anchors {
+ left: parent.left
+ right: parent.right
+ top: navigation.top
+ }
+
+ onDoneClicked: {
+ settingsView.save()
+ settingsView.state = "disabled"
+ }
+ }
+
+ UIToolBar {
+ id: fullScreenBar
+ z: 6
+ title: qsTr("Leave Full Screen Mode")
+ visible: opacity != 0.0
+ opacity: tabView.viewState == "fullscreen" ? 1.0 : 0.0
+ anchors {
+ left: parent.left
+ right: parent.right
+ top: navigation.top
+ }
+ onDoneClicked: {
+ navigation.webView.triggerWebAction(WebEngineView.ExitFullScreen);
+ }
+ }
+
+ NavigationBar {
+ id: navigation
+
+ anchors {
+ left: parent.left
+ right: parent.right
+ }
+ }
+ Rectangle{
+ anchors.bottom: navigation.bottom
+ anchors.left: navigation.left
+ anchors.right: navigation.right
+ height: 2
+ color: "#9d9faa"
+ }
+
+ PageView {
+ id: tabView
+ interactive: {
+ if (sslDialog.visible || homeScreen.state != "disabled" || urlDropDown.state == "enabled" || settingsView.state == "enabled")
+ return false
+ return true
+ }
+
+ anchors {
+ top: navigation.bottom
+ left: parent.left
+ right: parent.right
+ }
+
+ height: inputPanel.y
+
+ Component.onCompleted: {
+ var tab = createEmptyTab()
+
+ if (!tab)
+ return
+
+ navigation.webView = tab.webView
+ var url = AppEngine.initialUrl
+
+ navigation.load();
+ }
+ onCurrentIndexChanged: {
+ if (!tabView.get(tabView.currentIndex))
+ return
+ navigation.webView = tabView.get(tabView.currentIndex).item.webView
+ }
+ }
+
+ QtObject{
+ id: acceptedCertificates
+
+ property var acceptedUrls : []
+
+ function shouldAutoAccept(certificateError){
+ var domain = AppEngine.domainFromString(certificateError.url)
+ return acceptedUrls.indexOf(domain) >= 0
+ }
+ }
+
+ MessageDialog {
+ id: sslDialog
+
+ property var certErrors: []
+ property var currentError: null
+ visible: certErrors.length > 0
+ icon: StandardIcon.Warning
+ standardButtons: StandardButton.No | StandardButton.Yes
+ title: "Server's certificate not trusted"
+ text: "Do you wish to continue?"
+ detailedText: "If you wish so, you may continue with an unverified certificate. " +
+ "Accepting an unverified certificate means " +
+ "you may not be connected with the host you tried to connect to.\n" +
+ "Do you wish to override the security check and continue?"
+ onYes: {
+ var cert = certErrors.shift()
+ var domain = AppEngine.domainFromString(cert.url)
+ acceptedCertificates.acceptedUrls.push(domain)
+ cert.ignoreCertificateError()
+ presentError()
+ }
+ onNo: reject()
+ onRejected: reject()
+
+ function reject(){
+ certErrors.shift().rejectCertificate()
+ presentError()
+ }
+ function enqueue(error){
+ currentError = error
+ certErrors.push(error)
+ presentError()
+ }
+ function presentError(){
+ informativeText = "SSL error from URL\n\n" + currentError.url + "\n\n" + currentError.description + "\n"
+ }
+ }
+
+ Rectangle {
+ id: urlDropDown
+ color: "white"
+ visible: navigation.visible
+
+ property string searchString: navigation.addressBar.text
+
+ anchors {
+ left: parent.left
+ right: parent.right
+ top: navigation.bottom
+ }
+
+ state: "disabled"
+
+ states: [
+ State {
+ name: "enabled"
+ PropertyChanges {
+ target: urlDropDown
+ height: browserWindow.height - toolBarSize - 3
+ }
+ },
+ State {
+ name: "disabled"
+ PropertyChanges {
+ target: urlDropDown
+ height: 0
+ }
+ }
+ ]
+
+ Rectangle {
+ anchors.fill: parent
+ color: emptyBackgroundColor
+ }
+
+ SearchProxyModel {
+ id: proxy
+ target: navigation.webView.navigationHistory.items
+ searchString: urlDropDown.searchString
+ enabled: urlDropDown.state == "enabled"
+ }
+
+ ListView {
+ id: historyList
+ property int remainingHeight: Math.min((historyList.count + 1) * toolBarSize, inputPanel.y - toolBarSize - 3)
+ model: proxy
+ clip: true
+ boundsBehavior: Flickable.StopAtBounds
+ footerPositioning: ListView.InlineFooter
+ visible: urlDropDown.state == "enabled"
+
+ anchors {
+ top: parent.top
+ left: parent.left
+ right: parent.right
+ }
+ height: remainingHeight
+ delegate: Rectangle {
+ id: wrapper
+ width: historyList.width
+ height: toolBarSize
+ color: "#09102b"
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ if (!url)
+ return
+ navigation.webView.url = url
+ navigation.webView.forceActiveFocus()
+ }
+ }
+
+ Column {
+ width: parent.width - 60
+ height: parent.height
+ anchors {
+ verticalCenter: parent.verticalCenter
+ horizontalCenter: parent.horizontalCenter
+ }
+ Text {
+ property string highlightTitle: title ? title : ""
+ height: wrapper.height / 2
+ width: parent.width
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignBottom
+ anchors{
+ leftMargin: 30
+ rightMargin: 30
+ }
+ id: titleLabel
+ font.family: defaultFontFamily
+ font.pixelSize: 23
+ color: "white"
+ text: Utils.highlight(highlightTitle, urlDropDown.searchString)
+ }
+ Text {
+ property string highlightUrl: url ? url : ""
+ height: wrapper.height / 2 - 1
+ width: parent.width
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignTop
+ font.family: defaultFontFamily
+ font.pixelSize: 23
+ color: "white" //uiColor
+ text: Utils.highlight(highlightUrl, urlDropDown.searchString)
+ }
+ Rectangle {
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: historyList.width
+ height: 1
+ color: iconStrokeColor
+ }
+ }
+ }
+ footer: Rectangle {
+ z: 5
+ width: historyList.width
+ height: toolBarSize
+ color: "#09102b"
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ var string = urlDropDown.searchString
+ var constructedUrl = ""
+ if (AppEngine.isUrl(string)) {
+ constructedUrl = AppEngine.fromUserInput(string)
+ } else {
+ constructedUrl = AppEngine.fromUserInput(googleSearchQuery + string)
+ }
+ navigation.webView.url = constructedUrl
+ navigation.webView.forceActiveFocus()
+ }
+ }
+ Row {
+ height: parent.height
+ Rectangle {
+ id: searchIcon
+ height: parent.height
+ width: height
+ color: "transparent"
+ Image {
+ anchors.centerIn: parent
+ source: "assets/icons/Btn_Search.png"
+ }
+ }
+ Text {
+ id: searchText
+ height: parent.height
+ width: historyList.width - searchIcon.width - 30
+ elide: Text.ElideRight
+ text: urlDropDown.searchString
+ verticalAlignment: Text.AlignVCenter
+ font.family: defaultFontFamily
+ font.pixelSize: 23
+ color: "white"
+ }
+ }
+ }
+ }
+
+ transitions: Transition {
+ PropertyAnimation { property: "height"; duration: animationDuration; easing.type : Easing.InSine }
+ }
+ }
+
+ HomeScreen {
+ id: homeScreen
+ height: parent.height - toolBarSize
+ anchors {
+ top: navigation.bottom
+ left: parent.left
+ right: parent.right
+ }
+ }
+
+ SettingsView {
+ id: settingsView
+ height: parent.height - toolBarSize
+ anchors {
+ top: navigation.bottom
+ left: parent.left
+ right: parent.right
+ }
+ }
+}
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/CustomSwitch.qml b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/CustomSwitch.qml
new file mode 100644
index 0000000..e25a84e
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/CustomSwitch.qml
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt WebBrowser application.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+import QtDeviceUtilities.QtButtonImageProvider 1.0
+import QtQuick.Controls 2.1
+
+Switch {
+ id: control
+
+ property alias indicatorWidth: indicatorImg.width
+ property alias indicatorHeight: indicatorImg.height
+ property string switchTextColor: "#3b4155"
+
+ indicator: Image {
+ id: indicatorImg
+ width: 200
+ height: 75
+ sourceSize: Qt.size(width, height)
+ anchors.horizontalCenter: control.horizontalCenter
+ y: parent.height / 2 - height / 2
+ source: "image://QtButton/10/#848895/transparent"
+ Text {
+ id: offText
+ anchors.left: parent.left
+ anchors.leftMargin: parent.width * 0.075
+ anchors.verticalCenter: parent.verticalCenter
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ fontSizeMode: Text.Fit
+ minimumPixelSize: 1
+ font.pixelSize: parent.height * 0.55
+ color: switchTextColor
+ text: "OFF"
+ font.family: defaultFontFamily
+ }
+ Text {
+ id: onText
+ anchors.right: parent.right
+ anchors.rightMargin: parent.width * 0.1
+ anchors.verticalCenter: parent.verticalCenter
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ fontSizeMode: Text.Fit
+ minimumPixelSize: 1
+ font.pixelSize: parent.height * 0.55
+ color: switchTextColor
+ text: "ON"
+ font.family: defaultFontFamily
+ }
+
+ Binding {
+ target: qtHandle
+ property: "x"
+ value: control.checked ? indicatorImg.width - qtHandle.width - indicatorImg.width * 0.025 : indicatorImg.width * 0.025
+ when: !mousearea.drag.active
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: control.checked = !control.checked
+ }
+
+ QtButton {
+ id: qtHandle
+ anchors.verticalCenter: parent.verticalCenter
+ width: parent.width * 0.475
+ height: parent.height * 0.9
+ fillColor: control.checked ? buttonPressedColor : toolBarSeparatorColor
+ text: control.checked ? "ON" : "OFF"
+ borderColor: "transparent"
+ Behavior on x {
+ NumberAnimation { duration: 50 }
+ }
+
+ MouseArea {
+ id: mousearea
+ anchors.fill: parent
+ drag.target: qtHandle
+ drag.axis: Drag.XAxis
+ drag.minimumX: indicatorImg.width * 0.005
+ drag.maximumX: indicatorImg.width - width - indicatorImg.width * 0.005
+
+ onClicked: {
+ control.checked = !control.checked
+ }
+
+ onReleased: {
+ if (qtHandle.x > indicatorImg.width / 5 ) {
+ control.checked = true
+ } else {
+ control.checked = false
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/FeaturePermissionBar.qml b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/FeaturePermissionBar.qml
new file mode 100644
index 0000000..374c9d7
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/FeaturePermissionBar.qml
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt WebBrowser application.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import QtWebEngine 1.1
+import QtQuick.Layouts 1.0
+
+import "assets"
+
+Rectangle {
+ property var requestedFeature;
+ property url securityOrigin;
+ property WebEngineView view;
+
+ id: permissionBar
+ visible: false
+ height: 50
+
+ onRequestedFeatureChanged: {
+ message.text = securityOrigin + " wants to access " + message.textForFeature(requestedFeature);
+ }
+
+
+ RowLayout {
+ spacing: 0
+ anchors {
+ fill: permissionBar
+ }
+ Rectangle {
+ color: uiColor
+ height: parent.height
+ Layout.fillWidth: true
+
+ Text {
+ id: message
+ width: parent.width
+ elide: Text.ElideRight
+ horizontalAlignment: Text.AlignHCenter
+ anchors {
+ leftMargin: 15
+ rightMargin: 15
+ verticalCenter: parent.verticalCenter
+ horizontalCenter: parent.horizontalCenter
+ }
+ font.family: defaultFontFamily
+ font.pixelSize: 20
+ color: "white"
+ function textForFeature(feature) {
+ if (feature === WebEngineView.MediaAudioCapture)
+ return "your microphone"
+ if (feature === WebEngineView.MediaVideoCapture)
+ return "your camera"
+ if (feature === WebEngineView.MediaAudioVideoCapture)
+ return "your camera and microphone"
+ if (feature === WebEngineView.Geolocation)
+ return "your position"
+ }
+ }
+ }
+ Rectangle {
+ width: 1
+ height: parent.height
+ color: uiSeparatorColor
+ }
+
+ UIButton {
+ id: acceptButton
+ implicitHeight: permissionBar.height
+ implicitWidth: toolBarSize
+ buttonText: "Accept"
+ textSize: 18
+ Layout.alignment: Qt.AlignRight
+ onClicked: {
+ view.grantFeaturePermission(securityOrigin, requestedFeature, true);
+ permissionBar.visible = false;
+ }
+ }
+ Rectangle {
+ width: 1
+ height: parent.height
+ color: uiSeparatorColor
+ }
+
+ UIButton {
+ buttonText: "Deny"
+ textSize: 18
+ implicitHeight: permissionBar.height
+ implicitWidth: toolBarSize
+ Layout.alignment: Qt.AlignRight
+ onClicked: {
+ view.grantFeaturePermission(securityOrigin, requestedFeature, false);
+ permissionBar.visible = false
+ }
+ }
+ }
+}
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/HomeScreen.qml b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/HomeScreen.qml
new file mode 100644
index 0000000..6b53f55
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/HomeScreen.qml
@@ -0,0 +1,595 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt WebBrowser application.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.5
+import WebBrowser 1.0
+import "assets"
+
+Rectangle {
+ id: homeScreen
+ property int padding: 60
+ property int cellSize: width / 5 - padding
+ property alias messageBox: messageBox
+ property alias count: gridView.count
+ property alias currentIndex: gridView.currentIndex
+ color: "#09102b"
+ function set(i) {
+ var p = (i - i % gridViewPageItemCount) / gridViewPageItemCount
+ gridView.contentX = p * gridView.page
+ }
+
+ state: "enabled"
+ onStateChanged: {
+ if (state == "enabled" && !gridView.count)
+ messageBox.state = "empty"
+ }
+
+ signal add(string title, string url, string iconUrl, string fallbackColor)
+ onAdd: {
+ if (listModel.count === gridViewMaxBookmarks) {
+ navigation.refresh()
+ messageBox.state = "full"
+ state = "enabled"
+ homeScreen.forceActiveFocus()
+ return
+ }
+ var icon = url.indexOf("qt.io") != -1 ? "assets/icons/qt.png" : iconUrl
+ var element = { "title": title, "url": url, "iconUrl": icon, "fallbackColor": fallbackColor }
+ listModel.append(element)
+ set(listModel.count - 1)
+ }
+
+ signal remove(string url, int idx)
+ onRemove: {
+ var index = idx < 0 ? contains(url) : idx
+ if (index < 0)
+ return
+
+ listModel.remove(index)
+ gridView.forceLayout()
+ navigation.refresh()
+ if (!listModel.count)
+ messageBox.state = "empty"
+ }
+
+ function get(index) {
+ return listModel.get(index)
+ }
+
+ function contains(url) {
+ for (var idx = 0; idx < listModel.count; ++idx) {
+ if (listModel.get(idx).url === url)
+ return idx;
+ }
+ return -1;
+ }
+
+ states: [
+ State {
+ name: "enabled"
+ AnchorChanges {
+ target: homeScreen
+ anchors.top: navigation.bottom
+ }
+ },
+ State {
+ name: "disabled"
+ AnchorChanges {
+ target: homeScreen
+ anchors.top: homeScreen.parent.bottom
+ }
+ },
+ State {
+ name: "edit"
+ }
+ ]
+
+ transitions: Transition {
+ AnchorAnimation { duration: animationDuration; easing.type : Easing.InSine }
+ }
+
+ ListModel {
+ id: listModel
+ property string defaultBookmarks: "[{\"fallbackColor\":\"#46a2da\",\"iconUrl\":\"assets/icons/qt.png\",\"title\":\"Qt - Home\",\"url\":\"http://www.qt.io//"},{\"fallbackColor\":\"#18394c\",\"iconUrl\":\"http://www.topgear.com/sites/all/themes/custom/tg/apple-touch-icon-144x144.png/",\"title\":\"Top Gear\",\"url\":\"http://www.topgear.com//"},{\"fallbackColor\":\"#46a2da\",\"iconUrl\":\"https://duckduckgo.com/assets/icons/meta/DDG-iOS-icon_152x152.png/",\"title\":\"DuckDuckGo\",\"url\":\"https://duckduckgo.com//"},{\"fallbackColor\":\"#ff8c0a\",\"iconUrl\":\"http://s.blogsmithmedia.com/www.engadget.com/assets/images/favicon-160x160.png/",\"title\":\"Engadget | Technology News, Advice and Features\",\"url\":\"http://www.engadget.com//"},{\"fallbackColor\":\"#ff8c0a\",\"iconUrl\":\"https://www.openstreetmap.org/assets/favicon-194x194-32cdac24b02b88e09f0639bb92c760b2.png/",\"title\":\"OpenStreetMap\",\"url\":\"https://www.openstreetmap.org//"},{\"fallbackColor\":\"#5caa15\",\"iconUrl\":\"http://www.redditstatic.com/icon.png/",\"title\":\"reddit: the front page of the internet\",\"url\":\"http://www.reddit.com//"}]"
+
+ Component.onCompleted: {
+ listModel.clear()
+ var string = AppEngine.restoreSetting("bookmarks", defaultBookmarks)
+ if (!string)
+ return
+ var list = JSON.parse(string)
+ for (var i = 0; i < list.length; ++i) {
+ listModel.append(list[i])
+ }
+ navigation.refresh()
+ }
+ Component.onDestruction: {
+ var list = []
+ for (var i = 0; i < listModel.count; ++i) {
+ list[i] = listModel.get(i)
+ }
+ AppEngine.saveSetting("bookmarks", JSON.stringify(list))
+ }
+ }
+
+ GridView {
+ id: gridView
+
+ onCountChanged: {
+ if (!count)
+ messageBox.state = "empty"
+ else
+ messageBox.state = "disabled"
+ }
+
+ property real dragStart: 0
+ property real page: 4 * cellWidth
+
+ anchors.fill: parent
+ model: listModel
+ cellWidth: homeScreen.cellSize + homeScreen.padding
+ cellHeight: cellWidth
+ flow: GridView.FlowTopToBottom
+ boundsBehavior: Flickable.StopAtBounds
+ maximumFlickVelocity: 0
+ contentHeight: parent.height
+
+ MouseArea {
+ z: -1
+ enabled: homeScreen.state == "edit"
+ anchors.fill: parent
+ onClicked: homeScreen.state = "enabled"
+ }
+
+ rightMargin: {
+ var margin = (parent.width - 4 * gridView.cellWidth - homeScreen.padding) / 2
+ var padding = gridView.page - Math.round(gridView.count % gridViewPageItemCount / 2) * gridView.cellWidth
+
+ if (padding == gridView.page)
+ return margin
+
+ return margin + padding
+ }
+
+ anchors {
+ topMargin: toolBarSize
+ leftMargin: (parent.width - 4 * gridView.cellWidth + homeScreen.padding) / 2
+ }
+
+ Behavior on contentX {
+ NumberAnimation { duration: 1.5 * animationDuration; easing.type : Easing.InSine}
+ }
+
+ function snapToPage() {
+ if (dragging) {
+ dragStart = contentX
+ return
+ }
+ if (dragStart == 2 * page && contentX < 2 * page) {
+ contentX = page
+ return
+ }
+ if (dragStart == page) {
+ if (contentX < page) {
+ contentX = 0
+ return
+ }
+ if (page < contentX) {
+ contentX = 2 * page
+ return
+ }
+ }
+ if (dragStart == 0 && 0 < contentX) {
+ contentX = page
+ return
+ }
+ contentX = 0
+ }
+
+ onDraggingChanged: snapToPage()
+ delegate: Rectangle {
+ id: square
+ property string iconColor: "#f6f6f6"
+ width: homeScreen.cellSize
+ height: width
+ border.color: iconStrokeColor
+ border.width: 1
+
+ Rectangle {
+ id: bg
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ top: parent.top
+ margins: 1
+ }
+ state: "fallback"
+ width: square.width - 2
+ height: width
+ states: [
+ State {
+ name: "fallback"
+ PropertyChanges {
+ target: square
+ color: fallbackColor
+ }
+ PropertyChanges {
+ target: bg
+ color: square.color
+ }
+ },
+ State {
+ name: "normal"
+ PropertyChanges {
+ target: square
+ color: iconColor
+ }
+ PropertyChanges {
+ target: bg
+ color: square.color
+ }
+ }
+ ]
+
+ Image {
+ id: icon
+ smooth: true
+ anchors {
+ top: parent.top
+ horizontalCenter: parent.horizontalCenter
+ topMargin: width < bg.width ? 15 : 0
+ }
+ width: {
+ if (!icon.sourceSize.width)
+ return 0
+ if (icon.sourceSize.width < 100)
+ return 32
+
+ return bg.width
+ }
+ height: width
+ source: iconUrl
+ onStatusChanged: {
+ switch (status) {
+ case Image.Null:
+ case Image.Loading:
+ case Image.Error:
+ bg.state = "fallback"
+ break
+ case Image.Ready:
+ bg.state = "normal"
+ break
+ }
+ }
+ }
+ Text {
+ function cleanup(string) {
+ var t = string.replace("-", " ")
+ .replace("|", " ").replace(",", " ")
+ .replace(/\s\s+/g, "\n")
+ return t
+ }
+
+ visible: icon.width != bg.width
+ text: cleanup(title)
+ font.family: defaultFontFamily
+ font.pixelSize: 18
+ color: bg.state == "fallback" ? "white" : "black"
+ anchors {
+ top: icon.bottom
+ bottom: parent.bottom
+ left: parent.left
+ right: parent.right
+ leftMargin: 15
+ rightMargin: 15
+ bottomMargin: 15
+ }
+ maximumLineCount: 3
+ elide: Text.ElideRight
+ wrapMode: Text.Wrap
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+ }
+ }
+
+ Rectangle {
+ id: overlay
+ visible: opacity != 0.0
+ anchors.fill: parent
+ color: iconOverlayColor
+ opacity: {
+ if (iconMouse.pressed) {
+ if (homeScreen.state != "edit")
+ return 0.1
+ return 0.4
+ }
+ if (homeScreen.state == "edit")
+ return 0.3
+ return 0.0
+ }
+ }
+ MouseArea {
+ id: iconMouse
+ anchors.fill: parent
+ onPressAndHold: {
+ if (homeScreen.state == "edit") {
+ homeScreen.state = "enabled"
+ return
+ }
+ homeScreen.state = "edit"
+ }
+ onClicked: {
+ if (homeScreen.state == "edit") {
+ homeScreen.state = "enabled"
+ return
+ }
+ navigation.load(url)
+ }
+ }
+ Rectangle {
+ enabled: homeScreen.state == "edit"
+ opacity: enabled ? 1.0 : 0.0
+ width: image.sourceSize.width
+ height: image.sourceSize.height - 2
+ radius: width / 2
+ color: iconOverlayColor
+ anchors {
+ horizontalCenter: parent.right
+ verticalCenter: parent.top
+ }
+ Image {
+ id: image
+ opacity: {
+ if (deleteButton.pressed)
+ return 0.70
+ return 1.0
+ }
+ anchors {
+ top: parent.top
+ left: parent.left
+ }
+ source: "assets/icons/Btn_Delete.png"
+ MouseArea {
+ id: deleteButton
+ anchors.fill: parent
+ onClicked: {
+ mouse.accepted = true
+ remove(url, index)
+ }
+ }
+ }
+ Behavior on opacity {
+ NumberAnimation { duration: animationDuration }
+ }
+ }
+ }
+ }
+ Rectangle {
+ width: homeScreen.cellSize - homeScreen.padding / 2 - 10
+ anchors {
+ left: parent.left
+ top: parent.top
+ bottom: parent.bottom
+ }
+ MouseArea {
+ enabled: homeScreen.state == "edit"
+ anchors.fill: parent
+ onClicked: homeScreen.state = "enabled"
+ }
+ color: "#09102b"
+ }
+ Rectangle {
+ width: homeScreen.cellSize - homeScreen.padding / 2 - 10
+ anchors {
+ right: parent.right
+ top: parent.top
+ bottom: parent.bottom
+ }
+ MouseArea {
+ enabled: homeScreen.state == "edit"
+ anchors.fill: parent
+ onClicked: homeScreen.state = "enabled"
+ }
+ color: "#09102b"
+ }
+ Row {
+ id: pageIndicator
+ spacing: 20
+ anchors {
+ bottomMargin: 40
+ bottom: parent.bottom
+ horizontalCenter: parent.horizontalCenter
+ }
+ Repeater {
+ model: {
+ var c = gridView.count % gridViewPageItemCount
+ if (c > 0)
+ c = 1
+ return Math.floor(gridView.count / gridViewPageItemCount) + c
+ }
+ delegate: Rectangle {
+ property bool active: index * gridView.page <= gridView.contentX && gridView.contentX < (index + 1) * gridView.page
+ width: 10
+ height: width
+ radius: width / 2
+ color: !active ? inactivePagerColor : uiColor
+ anchors.verticalCenter: parent.verticalCenter
+ MouseArea {
+ anchors.fill: parent
+ onClicked: gridView.contentX = index * gridView.page
+ }
+ }
+ }
+ }
+
+ Rectangle {
+ id: messageBox
+ color: "white"
+ anchors.fill: parent
+
+ Rectangle {
+ id: error
+ visible: messageBox.state != "empty"
+ height: childrenRect.height
+ anchors {
+ top: parent.top
+ left: parent.left
+ right: parent.right
+ topMargin: 50
+ }
+ Image {
+ id: errorIcon
+ source: "assets/icons/Error_Icon.png"
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ top: parent.top
+ }
+ }
+ Text {
+ anchors {
+ topMargin: 30
+ top: errorIcon.bottom
+ horizontalCenter: parent.horizontalCenter
+ }
+ font.family: defaultFontFamily
+ font.pixelSize: message.font.pixelSize
+ text: "Oops!..."
+ color: iconOverlayColor
+ }
+ }
+
+ Text {
+ id: message
+ anchors {
+ top: error.bottom
+ horizontalCenter: parent.horizontalCenter
+ }
+ color: iconOverlayColor
+ font.family: defaultFontFamily
+ font.pixelSize: 28
+ verticalAlignment: Text.AlignTop
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ Rectangle {
+ color: parent.color
+ anchors {
+ top: message.bottom
+ bottom: parent.bottom
+ left: parent.left
+ right: parent.right
+ bottomMargin: 70
+ }
+ UIButton {
+ color: uiColor
+ implicitWidth: 180
+ implicitHeight: 70
+ buttonText: "OK"
+ visible: messageBox.state != "empty"
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ bottom: parent.bottom
+ }
+ onClicked: {
+ if (messageBox.state == "tabsfull") {
+ homeScreen.state = "disabled"
+ tabView.viewState = "list"
+ return
+ }
+ if (messageBox.state == "full") {
+ messageBox.state = "disabled"
+ homeScreen.state = "edit"
+ return
+ }
+ }
+ }
+ }
+
+ state: "disabled"
+
+ states: [
+ State {
+ name: "disabled"
+ PropertyChanges {
+ target: messageBox
+ visible: false
+ }
+ },
+ State {
+ name: "empty"
+ PropertyChanges {
+ target: message
+ text: qsTr("No bookmarks have been saved so far.")
+ }
+ PropertyChanges {
+ target: messageBox
+ color: emptyBackgroundColor
+ visible: true
+ }
+ PropertyChanges {
+ target: error
+ anchors.topMargin: 30
+ }
+ PropertyChanges {
+ target: navigation
+ state: "enabled"
+ }
+ },
+ State {
+ name: "full"
+ PropertyChanges {
+ target: message
+ text: qsTr("24 bookmarks is the maximum limit.\nTo bookmark a new page you must delete a bookmark first.")
+ }
+ PropertyChanges {
+ target: messageBox
+ visible: true
+ }
+ PropertyChanges {
+ target: navigation
+ state: "enabled"
+ }
+ },
+ State {
+ name: "tabsfull"
+ PropertyChanges {
+ target: message
+ text: qsTr("10 open tabs is the maximum limit.\nTo open a new tab you must close another one first.")
+ }
+ PropertyChanges {
+ target: messageBox
+ visible: true
+ }
+ PropertyChanges {
+ target: navigation
+ state: "enabled"
+ }
+ }
+ ]
+ }
+}
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/Keyboard.qml b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/Keyboard.qml
new file mode 100644
index 0000000..9ea7f71
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/Keyboard.qml
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt WebBrowser application.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.5
+import QtQuick.VirtualKeyboard 2.0
+
+InputPanel {
+ id: inputPanel
+ property int windowHeight: 0
+ property int animationDuration: 0
+
+ y: windowHeight
+ anchors {
+ left: parent.left
+ right: parent.right
+ }
+ states: State {
+ name: "visible"
+ when: Qt.inputMethod.visible
+ PropertyChanges {
+ target: inputPanel
+ y: windowHeight - inputPanel.height
+ }
+ }
+ transitions: Transition {
+ from: ""
+ to: "visible"
+ reversible: true
+ NumberAnimation {
+ properties: "y"
+ duration: animationDuration
+ easing.type: Easing.InOutQuad
+ }
+ }
+}
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/Main.qml b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/Main.qml
new file mode 100644
index 0000000..653b435
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/Main.qml
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt WebBrowser application.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.5
+
+Item {
+ BrowserWindow{
+ id: root
+ anchors.fill: parent
+ Keyboard{
+ id: inputPanel
+ windowHeight: root.height
+ animationDuration: root.animationDuration
+ }
+ }
+}
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/MockTouchPoint.qml b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/MockTouchPoint.qml
new file mode 100644
index 0000000..b47525c
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/MockTouchPoint.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt WebBrowser application.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Item {
+ id: mockTouchPoint
+
+ property bool pressed: false
+ property int pointId: 0
+
+ Image {
+ source: "assets/icons/touchpoint.png"
+ x: -(width / 2)
+ y: -(height / 2)
+ height: parent.height
+ width: parent.width
+ opacity: parent.pressed ? 0.6 : 0.0
+
+ Behavior on opacity {
+ NumberAnimation { duration: 200 }
+ }
+
+ Text {
+ text: mockTouchPoint.pointId
+ anchors.centerIn: parent
+ }
+ }
+}
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/NavigationBar.qml b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/NavigationBar.qml
new file mode 100644
index 0000000..8edbf77
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/NavigationBar.qml
@@ -0,0 +1,422 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt WebBrowser application.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.5
+import QtQuick.Controls 1.4
+import QtQuick.Controls.Styles 1.4
+import QtQuick.Layouts 1.2
+import WebBrowser 1.0
+
+import "assets"
+
+ToolBar {
+ id: root
+
+ property alias addressBar: urlBar
+ property Item webView: null
+
+ onWebViewChanged: {
+
+ }
+
+ visible: opacity != 0.0
+ opacity: tabView.viewState == "page" ? 1.0 : 0.0
+
+ function load(url) {
+ if (url)
+ webView.url = url
+ homeScreen.state = "disabled"
+ }
+
+ function refresh() {
+ if (urlBar.text == "")
+ bookmarksButton.bookmarked = false
+ else
+ bookmarksButton.bookmarked = homeScreen.contains(urlBar.text) !== -1
+ }
+
+ state: "enabled"
+
+ style: ToolBarStyle {
+ background: Rectangle {
+ color: uiColor
+ implicitHeight: toolBarSize + 3
+ }
+ padding {
+ left: 0
+ right: 0
+ top: 0
+ bottom: 0
+ }
+ }
+
+ Behavior on y {
+ NumberAnimation { duration: animationDuration }
+ }
+
+ states: [
+ State {
+ name: "enabled"
+ PropertyChanges {
+ target: root
+ y: 0
+ }
+ },
+ State {
+ name: "tracking"
+ PropertyChanges {
+ target: root
+ y: {
+ var diff = touchReference - touchY
+
+ if (velocityY > velocityThreshold) {
+ if (diff > 0)
+ return -root.height
+ else
+ return 0
+ }
+
+ if (!touchGesture || diff == 0) {
+ if (y < -root.height / 2)
+ return -root.height
+ else
+ return 0
+ }
+
+ if (diff > root.height)
+ return -root.height
+
+ if (diff > 0) {
+ if (y == -root.height)
+ return -root.height
+ return -diff
+ }
+
+ // diff < 0
+
+ if (y == 0)
+ return 0
+
+ diff = Math.abs(diff)
+ if (diff >= root.height)
+ return 0
+
+ return -root.height + diff
+ }
+ }
+ },
+ State {
+ name: "disabled"
+ PropertyChanges {
+ target: root
+ y: -root.height
+ }
+ }
+ ]
+
+ RowLayout {
+ height: toolBarSize
+ anchors {
+ top: parent.top
+ right: parent.right
+ left: parent.left
+ }
+ spacing: 0
+
+ UIButton {
+ id: backButton
+ source: "icons/Btn_Back.png"
+ color: uiColor
+ highlightColor: buttonPressedColor
+ onClicked: webView.goBack()
+ enabled: webView && webView.canGoBack
+ }
+ Rectangle {
+ width: 1
+ height: parent.height
+ color: uiSeparatorColor
+ }
+ UIButton {
+ id: forwardButton
+ source: "icons/Btn_Forward.png"
+ color: uiColor
+ highlightColor: buttonPressedColor
+ onClicked: webView.goForward()
+ enabled: webView && webView.canGoForward
+ }
+ Rectangle {
+ width: 1
+ height: parent.height
+ color: uiSeparatorColor
+ }
+ Rectangle {
+ Layout.fillWidth: true
+ implicitWidth: 10
+ height: parent.height
+ color: uiColor
+ }
+ TextField {
+ id: urlBar
+ Layout.fillWidth: true
+ text: webView ? webView.url : ""
+ activeFocusOnPress: true
+ inputMethodHints: Qt.ImhUrlCharactersOnly | Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase | Qt.ImhPreferLowercase
+ placeholderText: qsTr("Search or type a URL")
+
+ onActiveFocusChanged: {
+ if (activeFocus) {
+ urlBar.selectAll()
+ root.state = "enabled"
+ homeScreen.state = "disabled"
+ urlDropDown.state = "enabled"
+ } else {
+ urlDropDown.state = "disabled"
+ root.state = "tracking"
+ }
+ }
+
+ UIButton {
+ id: reloadButton
+ state: cancelButton.visible ? "edit" : "load"
+ states: [
+ State {
+ name: "load"
+ PropertyChanges {
+ target: reloadButton
+ source: webView && webView.loading ? "icons/Btn_Clear.png" : "icons/Btn_Reload.png"
+ height: 54
+ }
+ },
+ State {
+ name: "edit"
+ PropertyChanges {
+ target: reloadButton
+ source: "icons/Btn_Clear.png"
+ height: 45
+ visible: urlBar.text != ""
+ }
+ }
+ ]
+ height: 54
+ width: height
+ color: "transparent"
+ highlightColor: "#eeeeee"
+ radius: width / 2
+ anchors {
+ rightMargin: 1
+ right: parent.right
+ verticalCenter: addressBar.verticalCenter;
+ }
+ onClicked: {
+ if (state == "load") {
+ webView.loading ? webView.stop() : webView.reload()
+ webView.forceActiveFocus()
+ return
+ }
+ urlBar.selectAll()
+ urlBar.remove(urlBar.selectionStart, urlBar.selectionEnd)
+ }
+ }
+ style: TextFieldStyle {
+ textColor: "white"
+ font.family: defaultFontFamily
+ font.pixelSize: 28
+ selectionColor: uiHighlightColor
+ selectedTextColor: "white"
+ placeholderTextColor: placeholderColor
+ background: Rectangle {
+ implicitWidth: 514
+ implicitHeight: 56
+ border.color: textFieldStrokeColor
+ color: "#09102b"
+ border.width: 2
+ }
+ padding {
+ left: 15
+ right: reloadButton.width
+ }
+ }
+ onAccepted: {
+ webView.url = AppEngine.fromUserInput(text)
+ homeScreen.state = "disabled"
+ tabView.viewState = "page"
+ }
+
+ onTextChanged: refresh()
+ onEditingFinished: {
+ selectAll()
+ webView.forceActiveFocus()
+ }
+ }
+ Rectangle {
+ visible: !cancelButton.visible
+ Layout.fillWidth: true
+ implicitWidth: 10
+ height: parent.height
+ color: uiColor
+ }
+
+ UIButton {
+ id: cancelButton
+ color: uiColor
+ visible: urlDropDown.state === "enabled"
+ highlightColor: buttonPressedColor
+ Text {
+ color: "white"
+ anchors.centerIn: parent
+ text: "Cancel"
+ font.family: defaultFontFamily
+ font.pixelSize: 28
+ }
+ implicitWidth: 120
+ onClicked: {
+ urlDropDown.state = "disabled"
+ webView.forceActiveFocus()
+ }
+ }
+ Rectangle {
+ width: 1
+ height: parent.height
+ color: uiSeparatorColor
+ }
+ UIButton {
+ id: homeButton
+ source: "icons/Btn_Home.png"
+ color: uiColor
+ highlightColor: buttonPressedColor
+ onClicked: {
+ if (homeScreen.state == "disabled" || homeScreen.state == "edit") {
+ homeScreen.messageBox.state = "disabled"
+ homeScreen.state = "enabled"
+ homeScreen.forceActiveFocus()
+ } else if (homeScreen.state != "disabled") {
+ homeScreen.state = "disabled"
+ }
+ }
+ }
+ Rectangle {
+ width: 1
+ height: parent.height
+ color: uiSeparatorColor
+ }
+ UIButton {
+ id: pageViewButton
+ source: "icons/Btn_Tabs.png"
+ color: uiColor
+ highlightColor: buttonPressedColor
+ onClicked: {
+ if (tabView.viewState == "list") {
+ tabView.viewState = "page"
+ } else {
+ tabView.get(tabView.currentIndex).item.webView.takeSnapshot()
+ homeScreen.state = "disabled"
+ tabView.viewState = "list"
+ }
+ }
+ Text {
+ anchors {
+ centerIn: parent
+ verticalCenterOffset: 4
+ }
+
+ text: tabView.count
+ font.family: defaultFontFamily
+ font.pixelSize: 16
+ font.weight: Font.DemiBold
+ color: "white"
+ }
+ }
+ Rectangle {
+ width: 1
+ height: parent.height
+ color: uiSeparatorColor
+ }
+ UIButton {
+ id: bookmarksButton
+ color: uiColor
+ highlightColor: buttonPressedColor
+ enabled: urlBar.text != "" && !settingsView.privateBrowsingEnabled
+ property bool bookmarked: false
+ source: bookmarked ? "icons/Btn_Bookmark_Checked.png" : "icons/Btn_Bookmarks.png"
+ onClicked: {
+ if (!webView)
+ return
+ var icon = webView.loading ? "" : webView.icon
+ var idx = homeScreen.contains(webView.url.toString())
+ if (idx !== -1) {
+ homeScreen.remove("", idx)
+ return
+ }
+ var count = homeScreen.count
+ homeScreen.add(webView.title, webView.url, icon, AppEngine.fallbackColor())
+ if (count < homeScreen.count)
+ bookmarked = true
+ }
+ Component.onCompleted: refresh()
+ }
+ Rectangle {
+ width: 1
+ height: parent.height
+ color: uiSeparatorColor
+ }
+ UIButton {
+ id: settingsButton
+ source: "icons/Btn_Settings.png"
+ color: uiColor
+ highlightColor: buttonPressedColor
+ onClicked: {
+ settingsView.state = "enabled"
+ }
+ }
+ }
+ ProgressBar {
+ id: progressBar
+ height: 3
+ anchors {
+ left: parent.left
+ bottom: parent.bottom
+ right: parent.right
+ leftMargin: -10
+ rightMargin: -10
+ }
+ style: ProgressBarStyle {
+ background: Rectangle {
+ height: 3
+ color: emptyBackgroundColor
+ }
+ progress: Rectangle {
+ //color: settingsView.privateBrowsingEnabled ? "#46a2da" : "#317198"
+ color: "#41cd52"
+ }
+ }
+ minimumValue: 0
+ maximumValue: 100
+ value: (webView && webView.loadProgress < 100) ? webView.loadProgress : 0
+ }
+}
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/PageView.qml b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/PageView.qml
new file mode 100644
index 0000000..b5b64b5
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/PageView.qml
@@ -0,0 +1,682 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt WebBrowser application.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.5
+import QtWebEngine 1.1
+import QtQuick.Controls 1.4
+import QtQuick.Controls.Styles 1.4
+import QtQuick.Layouts 1.2
+import QtGraphicalEffects 1.0
+
+import WebBrowser 1.0
+import "assets"
+
+Rectangle {
+ id: root
+
+ property int itemWidth: browserWindow.width / 2
+ property int itemHeight: browserWindow.height / 2
+
+ property bool interactive: true
+
+ property alias currentIndex: pathView.currentIndex
+ property alias count: pathView.count
+
+ property string viewState: "page"
+
+ onViewStateChanged: {
+ if (viewState == "page" || viewState == "fullscreen")
+ homeScreen.state = "disabled"
+ }
+
+ property QtObject otrProfile: WebEngineProfile {
+ offTheRecord: true
+ }
+
+ property QtObject defaultProfile: WebEngineProfile {
+ storageName: "YABProfile"
+ offTheRecord: false
+ }
+
+ Component {
+ id: tabComponent
+ Rectangle {
+ id: tabItem
+ property alias webView: webEngineView
+ property alias title: webEngineView.title
+
+ property var image: QtObject {
+ property var snapshot: null
+ property string url: "about:blank"
+ }
+
+ visible: opacity != 0.0
+
+ Behavior on opacity {
+ NumberAnimation { duration: animationDuration }
+ }
+
+ anchors.fill: parent
+
+ Action {
+ shortcut: "Ctrl+F"
+ onTriggered: {
+ findBar.visible = !findBar.visible
+ if (findBar.visible) {
+ findTextField.forceActiveFocus()
+ }
+ }
+ }
+
+ FeaturePermissionBar {
+ id: permBar
+ view: webEngineView
+ anchors {
+ left: parent.left
+ right: parent.right
+ top: parent.top
+ }
+ z: 3
+ }
+
+ WebEngineView {
+ id: webEngineView
+
+ anchors {
+ fill: parent
+ top: permBar.bottom
+ }
+
+ profile: settingsView.privateBrowsingEnabled ? otrProfile : defaultProfile
+ enabled: root.interactive
+
+ function takeSnapshot() {
+ if (webEngineView.url == "" || webEngineView.url == "about:blank") {
+ tabItem.image.url = "about:blank"
+ tabItem.image.snapshot = null
+ return
+ }
+
+ if (tabItem.image.url == webEngineView.url || tabItem.opacity != 1.0)
+ return
+
+ tabItem.image.url = webEngineView.url
+ webEngineView.grabToImage(function(result) {
+ tabItem.image.snapshot = result;
+ console.log("takeSnapshot("+result.url+")")
+ });
+ }
+
+ // Trigger a refresh to check if the new url is bookmarked.
+ onUrlChanged: navigation.refresh()
+
+
+ settings.autoLoadImages: settingsView.autoLoadImages
+ settings.javascriptEnabled: !settingsView.javaScriptDisabled
+
+ // This should be enabled as we can switch to Qt 5.6 (i.e. import QtWebEngine 1.2)
+ // settings.pluginsEnabled: settingsView.pluginsEnabled
+
+ onLoadingChanged: {
+ if (loading)
+ navigation.state = "enabled"
+ }
+
+ onCertificateError: {
+ if (!acceptedCertificates.shouldAutoAccept(error)){
+ error.defer()
+ sslDialog.enqueue(error)
+ } else{
+ error.ignoreCertificateError()
+ }
+ }
+
+ onNewViewRequested: {
+ webEngineView.takeSnapshot()
+ var tab
+ if (!request.userInitiated) {
+ print("Warning: Blocked a popup window.")
+ return
+ }
+
+ tab = tabView.createEmptyTab()
+
+ if (!tab)
+ return
+
+ if (request.destination == WebEngineView.NewViewInTab) {
+ pathView.positionViewAtIndex(tabView.count - 1, PathView.Center)
+ request.openIn(tab.webView)
+ } else if (request.destination == WebEngineView.NewViewInBackgroundTab) {
+ var index = pathView.currentIndex
+ request.openIn(tab.webView)
+ pathView.positionViewAtIndex(index, PathView.Center)
+ } else if (request.destination == WebEngineView.NewViewInDialog) {
+ request.openIn(tab.webView)
+ } else {
+ request.openIn(tab.webView)
+ }
+ }
+
+ onFeaturePermissionRequested: {
+ permBar.securityOrigin = securityOrigin;
+ permBar.requestedFeature = feature;
+ permBar.visible = true;
+ }
+
+ onFullScreenRequested: {
+ if (request.toggleOn)
+ viewState = "fullscreen"
+ else
+ viewState = "page"
+ request.accept()
+ }
+ }
+
+ Desaturate {
+ id: desaturate
+ visible: desaturation != 0.0
+ anchors.fill: webEngineView
+ source: webEngineView
+ desaturation: root.interactive ? 0.0 : 1.0
+
+ Behavior on desaturation {
+ NumberAnimation { duration: animationDuration }
+ }
+ }
+
+ FastBlur {
+ id: blur
+ visible: radius != 0.0
+ anchors.fill: desaturate
+ source: desaturate
+ radius: desaturate.desaturation * 25
+ }
+
+ TouchTracker {
+ id: tracker
+ enabled: root.interactive
+ target: webEngineView
+ anchors.fill: parent
+ onTouchYChanged: browserWindow.touchY = tracker.touchY
+ onYVelocityChanged: browserWindow.velocityY = yVelocity
+ onTouchBegin: {
+ browserWindow.touchY = tracker.touchY
+ browserWindow.velocityY = yVelocity
+ browserWindow.touchReference = tracker.touchY
+ browserWindow.touchGesture = true
+ navigation.state = "tracking"
+ }
+ onTouchEnd: {
+ browserWindow.velocityY = yVelocity
+ browserWindow.touchGesture = false
+ navigation.state = "tracking"
+ }
+ onScrollDirectionChanged: {
+ browserWindow.velocityY = 0
+ browserWindow.touchReference = tracker.touchY
+ }
+ }
+
+ Rectangle {
+ opacity: {
+ if (inputPanel.state === "visible")
+ return 0.0
+ if (webEngineView.url == "" || webEngineView.url == "about:blank")
+ return 1.0
+ return 0.0
+ }
+ anchors.fill: parent
+ visible: opacity != 0.0
+ color: "#09102b"
+ Image {
+ id: placeholder
+ y: placeholder.height - navigation.y
+ anchors.horizontalCenter: parent.horizontalCenter
+ source: "assets/icons/AppLogoColor.png"
+ }
+ Text {
+ id: label
+ anchors {
+ top: placeholder.bottom
+ topMargin: 20
+ horizontalCenter: placeholder.horizontalCenter
+ }
+ font.family: defaultFontFamily
+ font.pixelSize: 28
+ color: "white"
+ text: "Qt WebBrowser"
+ }
+
+ Behavior on opacity {
+ NumberAnimation { duration: animationDuration }
+ }
+ }
+
+ Rectangle {
+ id: findBar
+ anchors {
+ right: webEngineView.right
+ left: webEngineView.left
+ top: webEngineView.top
+ }
+ height: toolBarSize / 2 + 10
+ visible: false
+ color: uiColor
+
+ RowLayout {
+ spacing: 0
+ anchors.fill: parent
+ Rectangle {
+ width: 5
+ height: parent.height
+ color: uiColor
+ }
+ TextField {
+ id: findTextField
+ Layout.fillWidth: true
+ onAccepted: {
+ webEngineView.findText(text)
+ }
+ style: TextFieldStyle {
+ textColor: "black"
+ font.family: defaultFontFamily
+ font.pixelSize: 28
+ selectionColor: uiHighlightColor
+ selectedTextColor: "black"
+ placeholderTextColor: placeholderColor
+ background: Rectangle {
+ implicitWidth: 514
+ implicitHeight: toolBarSize / 2
+ border.color: textFieldStrokeColor
+ border.width: 1
+ }
+ }
+ }
+ Rectangle {
+ width: 5
+ height: parent.height
+ color: uiColor
+ }
+ Rectangle {
+ width: 1
+ height: parent.height
+ color: uiSeparatorColor
+ }
+ UIButton {
+ id: findBackwardButton
+ iconSource: "assets/icons/Btn_Back.png"
+ implicitHeight: parent.height
+ onClicked: webEngineView.findText(findTextField.text, WebEngineView.FindBackward)
+ }
+ Rectangle {
+ width: 1
+ height: parent.height
+ color: uiSeparatorColor
+ }
+ UIButton {
+ id: findForwardButton
+ iconSource: "assets/icons/Btn_Forward.png"
+ implicitHeight: parent.height
+ onClicked: webEngineView.findText(findTextField.text)
+ }
+ Rectangle {
+ width: 1
+ height: parent.height
+ color: uiSeparatorColor
+ }
+ UIButton {
+ id: findCancelButton
+ iconSource: "assets/icons/Btn_Clear.png"
+ implicitHeight: parent.height
+ onClicked: findBar.visible = false
+ }
+ }
+ }
+ }
+ }
+
+ ListModel {
+ id: listModel
+ }
+
+ function makeCurrent(index) {
+ viewState = "list"
+ pathView.positionViewAtIndex(index, PathView.Center)
+ viewState = "page"
+ }
+
+ function createEmptyTab() {
+ var tab = add(tabComponent)
+ return tab
+ }
+
+ function add(component) {
+ if (listModel.count === tabViewMaxTabs) {
+ homeScreen.messageBox.state = "tabsfull"
+ homeScreen.state = "enabled"
+ homeScreen.forceActiveFocus()
+ return null
+ }
+
+ var element = {"item": null }
+ element.item = component.createObject(root, { "width": root.width, "height": root.height, "opacity": 0.0 })
+
+ if (element.item == null) {
+ console.log("PageView::add(): Error creating object");
+ return
+ }
+
+ listModel.append(element)
+ return element.item
+ }
+
+ function remove(index) {
+ pathView.interactive = false
+ pathView.currentItem.state = ""
+ pathView.currentItem.visible = false
+ listModel.remove(index)
+ pathView.decrementCurrentIndex()
+ pathView.interactive = true
+ }
+
+ function get(index) {
+ return listModel.get(index)
+ }
+
+ Component {
+ id: delegate
+
+ Rectangle {
+ id: wrapper
+
+ parent: item
+
+ property real visibility: 0.0
+ property bool isCurrentItem: PathView.isCurrentItem
+
+ visible: PathView.onPath && visibility != 0.0
+ state: isCurrentItem ? root.viewState : "list"
+
+ Behavior on scale {
+ NumberAnimation { duration: animationDuration }
+ }
+
+ states: [
+ State {
+ name: "page"
+ PropertyChanges { target: wrapper; width: root.width; height: root.height; visibility: 0.0 }
+ PropertyChanges { target: pathView; interactive: false }
+ PropertyChanges { target: item; opacity: 1.0 }
+ PropertyChanges { target: navigation; state: "enabled" }
+ },
+ State {
+ name: "list"
+ PropertyChanges { target: wrapper; width: itemWidth; height: itemHeight; visibility: 1.0 }
+ PropertyChanges { target: pathView; interactive: true }
+ PropertyChanges { target: item; opacity: 0.0 }
+ },
+ State {
+ name: "fullscreen"
+ PropertyChanges { target: wrapper; width: root.width; height: root.height; visibility: 0.0 }
+ PropertyChanges { target: pathView; interactive: false }
+ PropertyChanges { target: item; opacity: 1.0 }
+ PropertyChanges { target: navigation; state: "disabled" }
+ }
+ ]
+
+ transitions: Transition {
+ ParallelAnimation {
+ PropertyAnimation { property: "visibility"; duration: animationDuration; easing.type : Easing.InSine }
+ PropertyAnimation { properties: "x,y"; duration: animationDuration; easing.type: Easing.InSine }
+ PropertyAnimation { properties: "width,height"; duration: animationDuration; easing.type: Easing.InSine }
+ }
+ }
+
+ width: itemWidth; height: itemHeight
+ scale: {
+ if (pathView.count == 1)
+ return 1.0
+ if (pathView.count < 4)
+ return isCurrentItem ? 1.0 : 0.5
+
+ if (isCurrentItem)
+ return 1.0
+
+ var index1 = pathView.currentIndex - 2
+ var index2 = pathView.currentIndex - 1
+ var index4 = (pathView.currentIndex + 1) % pathView.count
+ var index5 = (pathView.currentIndex + 2) % pathView.count
+
+ if (index1 < 0)
+ index1 = pathView.count + index1
+ if (index2 < 0)
+ index2 = pathView.count + index2
+
+ switch (index) {
+ case index1 :
+ return 0.25
+ case index2:
+ return 0.5
+ case index4:
+ return 0.5
+ case index5:
+ return 0.25
+ }
+
+ return 0.25
+ }
+ z: PathView.itemZ
+
+ MouseArea {
+ enabled: pathView.interactive
+ anchors.fill: wrapper
+ onClicked: {
+ mouse.accepted = true
+ if (index < 0)
+ return
+
+ if (index == pathView.currentIndex) {
+ if (root.viewState == "list")
+ root.viewState = "page"
+ return
+ }
+ pathView.currentIndex = index
+ }
+ }
+ Rectangle {
+ id: shadow
+ visible: false
+ property real size: 24
+ anchors {
+ top: parent.top
+ topMargin: 9
+ horizontalCenter: parent.horizontalCenter
+ }
+ color: iconOverlayColor
+ radius: size / 2
+ width: snapshot.width
+ height: snapshot.height
+ }
+ GaussianBlur {
+ anchors.fill: shadow
+ source: shadow
+ radius: shadow.size
+ samples: shadow.size * 2
+ opacity: 0.3
+ transparentBorder: true
+ visible: wrapper.visibility == 1.0
+ }
+
+ Rectangle {
+ id: snapshot
+ color: uiColor
+
+ Image {
+ source: {
+ if (!item.image.snapshot)
+ return "assets/icons/about_blank.png"
+ return item.image.snapshot.url
+ }
+ anchors.fill: parent
+ Rectangle {
+ enabled: index == pathView.currentIndex && !pathView.moving && !pathView.flicking && wrapper.visibility == 1.0
+ opacity: enabled ? 1.0 : 0.0
+ visible: wrapper.visibility == 1.0 && listModel.count > 1
+ width: image.sourceSize.width
+ height: image.sourceSize.height - 2
+ radius: width / 2
+ color: iconOverlayColor
+ anchors {
+ horizontalCenter: parent.right
+ verticalCenter: parent.top
+ }
+ Image {
+ id: image
+ opacity: {
+ if (closeButton.pressed)
+ return 0.70
+ return 1.0
+ }
+ anchors {
+ top: parent.top
+ left: parent.left
+ }
+ source: "assets/icons/Btn_Delete.png"
+ MouseArea {
+ id: closeButton
+ anchors.fill: parent
+ onClicked: {
+ mouse.accepted = true
+ remove(pathView.currentIndex)
+ }
+ }
+ }
+ Behavior on opacity {
+ NumberAnimation { duration: animationDuration / 2 }
+ }
+ }
+ }
+ anchors.fill: wrapper
+ }
+
+ Text {
+ anchors {
+ topMargin: -25
+ top: parent.top
+ horizontalCenter: parent.horizontalCenter
+ }
+ horizontalAlignment: Text.AlignHCenter
+ width: parent.width - image.width
+ elide: Text.ElideRight
+ text: item.title
+ font.pixelSize: 16
+ font.family: defaultFontFamily
+ color: "white"
+ visible: wrapper.isCurrentItem && wrapper.visibility == 1.0
+ }
+ }
+ }
+
+ Rectangle {
+ color: "#09102b"
+ anchors.fill: parent
+ }
+
+ PathView {
+ id: pathView
+ pathItemCount: 5
+ anchors.fill: parent
+ model: listModel
+ delegate: delegate
+ highlightMoveDuration: animationDuration
+ highlightRangeMode: PathView.StrictlyEnforceRange
+ snapMode: PathView.SnapToItem
+ preferredHighlightBegin: 0.5
+ preferredHighlightEnd: 0.5
+
+ dragMargin: itemHeight
+
+ focus: pathView.interactive
+
+ property real offset: 30
+
+ property real margin: {
+ if (count == 2)
+ return root.width / 4 - offset
+ if (count == 3)
+ return root.width / 8 + offset
+ if (count == 4)
+ return root.width / 8 - offset
+
+ return offset
+ }
+
+ property real middle: {
+ if (currentItem)
+ return (pathView.height / 2) - (currentItem.visibility * 50)
+ return (pathView.height / 2 - 50)
+ }
+
+ path: Path {
+ startX: pathView.margin
+ startY: pathView.middle
+
+ PathPercent { value: 0.0 }
+ PathAttribute { name: "itemZ"; value: 0 }
+ PathLine {
+ x: (pathView.width - itemWidth) / 2 + 106
+ y: pathView.middle
+ }
+ PathPercent { value: 0.49 }
+ PathAttribute { name: "itemZ"; value: 6 }
+
+ PathLine { relativeX: 0; relativeY: 0 }
+
+ PathLine {
+ x: (pathView.width - itemWidth) / 2 + itemWidth - 106
+ y: pathView.middle
+ }
+ PathPercent { value: 0.51 }
+
+ PathLine { relativeX: 0; relativeY: 0 }
+
+ PathAttribute { name: "itemZ"; value: 4 }
+ PathLine {
+ x: pathView.width - pathView.margin
+ y: pathView.middle
+ }
+ PathPercent { value: 1 }
+ PathAttribute { name: "itemZ"; value: 2 }
+ }
+
+ Keys.onLeftPressed: decrementCurrentIndex()
+ Keys.onRightPressed: incrementCurrentIndex()
+ }
+}
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/SettingsView.qml b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/SettingsView.qml
new file mode 100644
index 0000000..0b45801
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/SettingsView.qml
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt WebBrowser application.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.5
+import QtQuick.Layouts 1.0
+import QtQuick.Controls 1.4
+import QtQuick.Controls.Styles 1.4
+import Qt.labs.settings 1.0
+
+import WebBrowser 1.0
+
+Rectangle {
+ id: root
+ color: "#09102b"
+ property bool privateBrowsingEnabled: appSettings[0].active
+ property bool httpDiskCacheEnabled: appSettings[1].active
+ property bool autoLoadImages: appSettings[2].active
+ property bool javaScriptDisabled: appSettings[3].active
+ // property bool pluginsEnabled: appSettings[4].active
+
+ property var appSettings: [
+ { "name": "Private Browsing", "active": false, "notify": function(v) { privateBrowsingEnabled = v; } },
+ { "name": "Enable HTTP Disk Cache", "active": true, "notify": function(v) { httpDiskCacheEnabled = v; } },
+ { "name": "Auto Load Images", "active": true, "notify": function(v) { autoLoadImages = v; } },
+ { "name": "Disable JavaScript", "active": false, "notify": function(v) { javaScriptDisabled = v; } },
+// { "name": "Enable Plugins", "active": false, "notify": function(v) { pluginsEnabled = v; } }
+ ]
+
+ function save() {
+ for (var i = 0; i < appSettings.length; ++i) {
+ var setting = appSettings[i]
+
+ listModel.get(i).active = setting.active
+ // Do not persist private browsing mode
+ if (setting.name === "Private Browsing")
+ continue
+ AppEngine.saveSetting(setting.name, setting.active)
+ }
+ }
+
+ Rectangle{
+ color: toolBarSeparatorColor
+ height: 2
+ anchors.top: root.top
+ anchors.right: root.right
+ anchors.left: root.left
+ z: 100
+ }
+
+ state: "disabled"
+
+ states: [
+ State {
+ name: "enabled"
+ AnchorChanges {
+ target: root
+ anchors.top: navigation.bottom
+ }
+ PropertyChanges {
+ target: settingsToolBar
+ opacity: 1.0
+ }
+ },
+ State {
+ name: "disabled"
+ AnchorChanges {
+ target: root
+ anchors.top: root.parent.bottom
+ }
+ PropertyChanges {
+ target: settingsToolBar
+ opacity: 0.0
+ }
+ }
+ ]
+
+ transitions: Transition {
+ AnchorAnimation { duration: animationDuration; easing.type : Easing.InSine }
+ }
+
+ ListModel {
+ id: listModel
+ }
+
+ ListView {
+ id: listView
+ anchors.fill: parent
+ model: listModel
+ delegate: Rectangle {
+ color: "transparent"
+ height: 100
+ width: 560
+ anchors.horizontalCenter: parent.horizontalCenter
+ Text {
+ anchors.verticalCenter: parent.verticalCenter
+ font.family: defaultFontFamily
+ font.pixelSize: 28
+ text: name
+ color: sw.enabled ? "white" : "#848895"
+ }
+ Rectangle {
+ anchors {
+ right: parent.right
+ verticalCenter: parent.verticalCenter
+ }
+ CustomSwitch {
+ id: sw
+ onCheckedChanged: {
+ var setting = appSettings[index]
+ setting.active = checked
+ setting.notify(checked)
+ }
+ enabled: {
+ var ok = appSettings[index].name.indexOf("Disk Cache") < 0
+ return ok || !privateBrowsingEnabled
+ }
+ anchors.centerIn: parent
+ checked: {
+ if (enabled)
+ return active
+ return false
+ }
+ /*style: SwitchStyle {
+ handle: Rectangle {
+ width: 42
+ height: 42
+ radius: height / 2
+ color: "white"
+ border.color: control.checked ? "#5caa14" : "#9b9b9b"
+ border.width: 1
+ }
+
+ groove: Rectangle {
+ implicitWidth: 72
+ height: 42
+ radius: height / 2
+ border.color: control.checked ? "#5caa14" : "#9b9b9b"
+ color: control.checked ? "#5cff14" : "white"
+ border.width: 1
+ }
+ }*/
+ }
+ }
+ }
+
+ Component.onCompleted: {
+ for (var i = 0; i < appSettings.length; ++i) {
+ var setting = appSettings[i]
+ var active = JSON.parse(AppEngine.restoreSetting(setting.name, setting.active))
+ if (setting.active !== active) {
+ setting.active = active
+ setting.notify(active)
+ }
+ listModel.append(setting)
+ }
+ listView.forceLayout()
+ }
+ Component.onDestruction: root.save()
+ }
+}
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/Utils.js b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/Utils.js
new file mode 100644
index 0000000..07ee41d
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/Utils.js
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt WebBrowser application.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+. pragma library
+
+function quote(str, delimiter) {
+ // discuss at: http://phpjs.org/functions/preg_quote/
+ // original by: booeyOH
+ // improved by: Ates Goral (http://magnetiq.com)
+ // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
+ // improved by: Brett Zamir (http://brett-zamir.me)
+ // bugfixed by: Onno Marsman
+ // example 1: preg_quote("$40");
+ // returns 1: '\\$40'
+ // example 2: preg_quote("*RRRING* Hello?");
+ // returns 2: '\\*RRRING\\* Hello\\?'
+ // example 3: preg_quote("\\.+*?[^]$(){}=!<>|:");
+ // returns 3: '\\\\\\.\\+\\*\\?\\[\\^\\]\\$\\(\\)\\{\\}\\=\\!\\<\\>\\|\\:'
+
+ return String(str)
+ .replace(new RegExp('[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\' + (delimiter || '') + '-]', 'g'), '\\$&');
+}
+
+function highlight( text, search )
+{
+ return text.replace( new RegExp( "(" + quote( search ) + ")" , 'gi' ), "$1" );
+}
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/UIButton.qml b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/UIButton.qml
new file mode 100644
index 0000000..38d3e5a
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/UIButton.qml
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt WebBrowser application.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.5
+import QtQuick.Controls 1.4
+import QtQuick.Controls.Styles 1.4
+import QtQuick.Layouts 1.2
+
+
+ToolButton {
+ id: root
+ implicitHeight: toolBarSize
+ implicitWidth: toolBarSize
+
+ property alias buttonText: label.text
+ property alias textColor: label.color
+ property alias textSize: label.font.pixelSize
+ property string source: ""
+ property real radius: 0.0
+ property string color: uiColor
+ property string highlightColor: buttonPressedColor
+ Text {
+ id: label
+ color: "white"
+ anchors.centerIn: parent
+ font.family: defaultFontFamily
+ font.pixelSize: 28
+ }
+ style: ButtonStyle {
+ background: Rectangle {
+ opacity: root.enabled ? 1.0 : 0.3
+ color: root.pressed || root.checked ? root.highlightColor : root.color
+ radius: root.radius
+ Image {
+ source: root.source
+ width: Math.min(sourceSize.width, root.width)
+ height: Math.min(sourceSize.height, root.height)
+ anchors.centerIn: parent
+ }
+ }
+ }
+}
+
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/UIToolBar.qml b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/UIToolBar.qml
new file mode 100644
index 0000000..caf4ec1
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/UIToolBar.qml
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt WebBrowser application.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.5
+import QtQuick.Controls 1.0
+import QtQuick.Controls.Styles 1.0
+import QtQuick.Layouts 1.0
+
+ToolBar {
+ id: root
+
+ property alias title: titleBox.text
+ property alias source: toolBarButton.source
+ property alias indicator: indicatorText.text
+
+ property int indicatorWidth: 40
+ property int indicatorHeight: 32
+
+ signal optionClicked()
+ signal doneClicked()
+
+ height: navigation.height
+
+ style: ToolBarStyle {
+ background: Rectangle {
+ color: toolBarFillColor
+ }
+ padding {
+ left: 0
+ right: 0
+ top: 0
+ bottom: 0
+ }
+ }
+
+ RowLayout {
+ spacing: 0
+ height: toolBarSize
+ anchors {
+ top: parent.top
+ right: parent.right
+ left: parent.left
+ }
+ Rectangle {
+ width: childrenRect.width
+ height: parent.height
+ color: toolBarFillColor
+ Text {
+ id: titleBox
+ visible: root.title !== ""
+ anchors {
+ leftMargin: visible ? 30 : 0
+ left: parent.left
+ verticalCenter: parent.verticalCenter
+ }
+ color: "white"
+ font.pixelSize: 28
+ font.family: defaultFontFamily
+ }
+ Rectangle {
+ visible: toolBarButton.visible && titleBox.visible
+ width: 1
+ anchors {
+ top: parent.top
+ bottom: parent.bottom
+ }
+ color: toolBarSeparatorColor
+ }
+ UIButton {
+ id: toolBarButton
+ visible: root.source !== ""
+ color: toolBarFillColor
+ Component.onCompleted: toolBarButton.clicked.connect(root.optionClicked)
+ anchors.left: titleBox.right
+ }
+ }
+ Rectangle {
+ visible: toolBarButton.visible
+ width: 1
+ height: parent.height
+ color: toolBarSeparatorColor
+ }
+ Rectangle {
+ width: indicatorWidth
+ height: parent.height
+ color: toolBarFillColor
+ }
+ Rectangle {
+ color: toolBarFillColor
+ Layout.fillWidth: true
+ height: parent.height
+ Rectangle {
+ visible: root.indicator !== ""
+ color: "transparent"
+ border.color: "white"
+ border.width: 2
+ width: indicatorWidth
+ height: indicatorHeight
+ anchors.centerIn: parent
+ Text {
+ id: indicatorText
+ anchors.centerIn: parent
+ color: "white"
+ font.family: defaultFontFamily
+ font.pixelSize: 20
+ }
+ }
+ }
+ Rectangle {
+ width: 1
+ height: parent.height
+ color: toolBarSeparatorColor
+ }
+ UIButton {
+ id: doneButton
+ color: toolBarFillColor
+ buttonText: "Done"
+ implicitWidth: 120
+ Component.onCompleted: doneButton.clicked.connect(root.doneClicked)
+ }
+ }
+}
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/AppLogoColor.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/AppLogoColor.png
new file mode 100644
index 0000000..2a49717
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/AppLogoColor.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/AppLogoGrey.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/AppLogoGrey.png
new file mode 100644
index 0000000..b2baae5
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/AppLogoGrey.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Add.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Add.png
new file mode 100644
index 0000000..3c45c42
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Add.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Back.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Back.png
new file mode 100644
index 0000000..562c9f6
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Back.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Bookmark_Checked.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Bookmark_Checked.png
new file mode 100644
index 0000000..a6dbe6a
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Bookmark_Checked.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Bookmark_Indicator.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Bookmark_Indicator.png
new file mode 100644
index 0000000..a8b8b6b
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Bookmark_Indicator.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Bookmarks.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Bookmarks.png
new file mode 100644
index 0000000..fc286cc
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Bookmarks.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Clear.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Clear.png
new file mode 100644
index 0000000..1c9870a
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Clear.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Delete.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Delete.png
new file mode 100644
index 0000000..2010838
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Delete.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Forward.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Forward.png
new file mode 100644
index 0000000..e4c96f8
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Forward.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Home.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Home.png
new file mode 100644
index 0000000..7358a59
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Home.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Reload.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Reload.png
new file mode 100644
index 0000000..cff41cd
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Reload.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Search.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Search.png
new file mode 100644
index 0000000..a6ef383
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Search.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Settings.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Settings.png
new file mode 100644
index 0000000..33d7400
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Settings.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Tabs.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Tabs.png
new file mode 100644
index 0000000..c007408
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Tabs.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Up.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Up.png
new file mode 100644
index 0000000..f70a78d
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Btn_Up.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Error_Icon.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Error_Icon.png
new file mode 100644
index 0000000..cf40696
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/Error_Icon.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/LightWebBrowser_Icons.svg b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/LightWebBrowser_Icons.svg
new file mode 100644
index 0000000..fce4b40
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/LightWebBrowser_Icons.svg
@@ -0,0 +1,243 @@
+
+
+
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/about_blank.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/about_blank.png
new file mode 100644
index 0000000..6901b0b
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/about_blank.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/qt.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/qt.png
new file mode 100644
index 0000000..6a22d2e
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/qt.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/touchpoint.png b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/touchpoint.png
new file mode 100644
index 0000000..7649ee9
Binary files /dev/null and b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/qml/assets/icons/touchpoint.png differ
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/resources.qrc b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/resources.qrc
new file mode 100644
index 0000000..451a67f
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/resources.qrc
@@ -0,0 +1,37 @@
+
+
+ qml/BrowserWindow.qml
+ qml/FeaturePermissionBar.qml
+ qml/MockTouchPoint.qml
+ qml/PageView.qml
+ qml/NavigationBar.qml
+ qml/HomeScreen.qml
+ qml/SettingsView.qml
+ qml/assets/UIButton.qml
+ qml/assets/UIToolBar.qml
+ qml/Utils.js
+ qml/assets/icons/Btn_Home.png
+ qml/assets/icons/Btn_Tabs.png
+ qml/assets/icons/Btn_Forward.png
+ qml/assets/icons/Btn_Back.png
+ qml/assets/icons/Btn_Reload.png
+ qml/assets/icons/Btn_Clear.png
+ qml/assets/icons/touchpoint.png
+ qml/assets/icons/Btn_Delete.png
+ qml/assets/icons/Btn_Bookmarks.png
+ qml/assets/icons/Btn_Bookmark_Checked.png
+ qml/assets/icons/Btn_Bookmark_Indicator.png
+ qml/assets/icons/Btn_Settings.png
+ qml/assets/icons/about_blank.png
+ qml/assets/icons/Btn_Add.png
+ qml/assets/icons/Btn_Up.png
+ qml/assets/icons/Btn_Search.png
+ qml/assets/icons/Error_Icon.png
+ qml/assets/icons/qt.png
+ qml/assets/icons/AppLogoColor.png
+ qml/assets/icons/AppLogoGrey.png
+ qml/Keyboard.qml
+ qml/Main.qml
+ qml/CustomSwitch.qml
+
+
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/src.pro b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/src.pro
new file mode 100644
index 0000000..f076b73
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/src.pro
@@ -0,0 +1,47 @@
+TARGET = qtwebbrowser
+
+CONFIG += c++11
+CONFIG -= app_bundle
+
+SOURCES = \
+ appengine.cpp \
+ main.cpp \
+ navigationhistoryproxymodel.cpp \
+ touchtracker.cpp
+
+HEADERS = \
+ appengine.h \
+ navigationhistoryproxymodel.h \
+ touchtracker.h \
+
+OTHER_FILES = \
+ qml/assets/UIButton.qml \
+ qml/assets/UIToolBar.qml \
+ qml/ApplicationRoot.qml \
+ qml/BrowserWindow.qml \
+ qml/FeaturePermissionBar.qml \
+ qml/MockTouchPoint.qml \
+ qml/PageView.qml \
+ qml/NavigationBar.qml \
+ qml/HomeScreen.qml \
+ qml/SettingsView.qml \
+ qml/Keyboard.qml \
+ qml/Window.qml
+
+QT += qml quick webengine
+
+RESOURCES += resources.qrc
+
+!cross_compile {
+ DEFINES += DESKTOP_BUILD
+ SOURCES += touchmockingapplication.cpp
+ HEADERS += touchmockingapplication.h
+ QT += gui-private
+ isEmpty(INSTALL_PREFIX): INSTALL_PREFIX=/usr/local/bin
+} else {
+ # Path for Qt for Device Creation
+ isEmpty(INSTALL_PREFIX): INSTALL_PREFIX=/data/user/qt/qtwebbrowser-app
+}
+
+target.path = $$INSTALL_PREFIX
+INSTALLS += target
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/touchmockingapplication.cpp b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/touchmockingapplication.cpp
new file mode 100644
index 0000000..5b56fa8
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/touchmockingapplication.cpp
@@ -0,0 +1,274 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt WebBrowser application.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "touchmockingapplication.h"
+#include "appengine.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+using namespace utils;
+
+static inline QRectF touchRectForPosition(QPointF centerPoint)
+{
+ QRectF touchRect(0, 0, 40, 40);
+ touchRect.moveCenter(centerPoint);
+ return touchRect;
+}
+
+TouchMockingApplication::TouchMockingApplication(int& argc, char** argv)
+ : QGuiApplication(argc, argv)
+ , m_realTouchEventReceived(false)
+ , m_pendingFakeTouchEventCount(0)
+ , m_holdingControl(false)
+{
+}
+
+bool TouchMockingApplication::notify(QObject* target, QEvent* event)
+{
+ // We try to be smart, if we received real touch event, we are probably on a device
+ // with touch screen, and we should not have touch mocking.
+
+ if (!event->spontaneous() || m_realTouchEventReceived)
+ return QGuiApplication::notify(target, event);
+
+ if (isTouchEvent(event)) {
+ if (m_pendingFakeTouchEventCount)
+ --m_pendingFakeTouchEventCount;
+ else
+ m_realTouchEventReceived = true;
+ return QGuiApplication::notify(target, event);
+ }
+
+ QQuickView* window = qobject_cast(target);
+ if (!window)
+ return QGuiApplication::notify(target, event);
+
+ m_holdingControl = QGuiApplication::keyboardModifiers().testFlag(Qt::ControlModifier);
+
+ if (event->type() == QEvent::KeyRelease && static_cast(event)->key() == Qt::Key_Control) {
+ foreach (int id, m_heldTouchPoints)
+ if (m_touchPoints.contains(id) && !QGuiApplication::mouseButtons().testFlag(Qt::MouseButton(id))) {
+ m_touchPoints[id].setState(Qt::TouchPointReleased);
+ m_heldTouchPoints.remove(id);
+ } else
+ m_touchPoints[id].setState(Qt::TouchPointStationary);
+
+ sendTouchEvent(window, m_heldTouchPoints.isEmpty() ? QEvent::TouchEnd : QEvent::TouchUpdate, static_cast(event)->timestamp());
+ }
+
+ if (isMouseEvent(event)) {
+ const QMouseEvent* const mouseEvent = static_cast(event);
+
+ QTouchEvent::TouchPoint touchPoint;
+ touchPoint.setPressure(1);
+
+ QEvent::Type touchType = QEvent::None;
+
+ switch (mouseEvent->type()) {
+ case QEvent::MouseButtonPress:
+ touchPoint.setId(mouseEvent->button());
+ if (m_touchPoints.contains(touchPoint.id())) {
+ touchPoint.setState(Qt::TouchPointMoved);
+ touchType = QEvent::TouchUpdate;
+ } else {
+ touchPoint.setState(Qt::TouchPointPressed);
+ // Check if more buttons are held down than just the event triggering one.
+ if (mouseEvent->buttons() > mouseEvent->button())
+ touchType = QEvent::TouchUpdate;
+ else
+ touchType = QEvent::TouchBegin;
+ }
+ break;
+ case QEvent::MouseMove:
+ if (!mouseEvent->buttons()) {
+ // We have to swallow the event instead of propagating it,
+ // since we avoid sending the mouse release events and if the
+ // Flickable is the mouse grabber it would receive the event
+ // and would move the content.
+ event->accept();
+ return true;
+ }
+ touchType = QEvent::TouchUpdate;
+ touchPoint.setId(mouseEvent->buttons());
+ touchPoint.setState(Qt::TouchPointMoved);
+ break;
+ case QEvent::MouseButtonRelease:
+ // Check if any buttons are still held down after this event.
+ if (mouseEvent->buttons())
+ touchType = QEvent::TouchUpdate;
+ else
+ touchType = QEvent::TouchEnd;
+ touchPoint.setId(mouseEvent->button());
+ touchPoint.setState(Qt::TouchPointReleased);
+ break;
+ case QEvent::MouseButtonDblClick:
+ // Eat double-clicks, their accompanying press event is all we need.
+ event->accept();
+ return true;
+ default:
+ Q_ASSERT_X(false, "multi-touch mocking", "unhandled event type");
+ }
+
+ // A move can have resulted in multiple buttons, so we need check them individually.
+ if (touchPoint.id() & Qt::LeftButton)
+ updateTouchPoint(mouseEvent, touchPoint, Qt::LeftButton);
+ if (touchPoint.id() & Qt::MidButton)
+ updateTouchPoint(mouseEvent, touchPoint, Qt::MidButton);
+ if (touchPoint.id() & Qt::RightButton)
+ updateTouchPoint(mouseEvent, touchPoint, Qt::RightButton);
+
+ if (m_holdingControl && touchPoint.state() == Qt::TouchPointReleased) {
+ // We avoid sending the release event because the Flickable is
+ // listening to mouse events and would start a bounce-back
+ // animation if it received a mouse release.
+ event->accept();
+ return true;
+ }
+
+ // Update states for all other touch-points
+ for (QHash::iterator it = m_touchPoints.begin(), end = m_touchPoints.end(); it != end; ++it) {
+ if (!(it.value().id() & touchPoint.id()))
+ it.value().setState(Qt::TouchPointStationary);
+ }
+
+ Q_ASSERT(touchType != QEvent::None);
+
+ if (!sendTouchEvent(window, touchType, mouseEvent->timestamp()))
+ return QGuiApplication::notify(target, event);
+
+ event->accept();
+ return true;
+ }
+
+ return QGuiApplication::notify(target, event);
+}
+
+void TouchMockingApplication::updateTouchPoint(const QMouseEvent* mouseEvent, QTouchEvent::TouchPoint touchPoint, Qt::MouseButton mouseButton)
+{
+ // Ignore inserting additional touch points if Ctrl isn't held because it produces
+ // inconsistent touch events and results in assers in the gesture recognizers.
+ if (!m_holdingControl && m_touchPoints.size() && !m_touchPoints.contains(mouseButton))
+ return;
+
+ if (m_holdingControl && touchPoint.state() == Qt::TouchPointReleased) {
+ m_heldTouchPoints.insert(mouseButton);
+ return;
+ }
+
+ // Gesture recognition uses the screen position for the initial threshold
+ // but since the canvas translates touch events we actually need to pass
+ // the screen position as the scene position to deliver the appropriate
+ // coordinates to the target.
+ touchPoint.setRect(touchRectForPosition(mouseEvent->localPos()));
+ touchPoint.setSceneRect(touchRectForPosition(mouseEvent->screenPos()));
+
+ if (touchPoint.state() == Qt::TouchPointPressed)
+ touchPoint.setStartScenePos(mouseEvent->screenPos());
+ else {
+ const QTouchEvent::TouchPoint& oldTouchPoint = m_touchPoints[mouseButton];
+ touchPoint.setStartScenePos(oldTouchPoint.startScenePos());
+ touchPoint.setLastPos(oldTouchPoint.pos());
+ touchPoint.setLastScenePos(oldTouchPoint.scenePos());
+ }
+
+ // Update current touch-point.
+ touchPoint.setId(mouseButton);
+ m_touchPoints.insert(mouseButton, touchPoint);
+}
+
+bool TouchMockingApplication::sendTouchEvent(QQuickView* window, QEvent::Type type, ulong timestamp)
+{
+ static QTouchDevice* device = 0;
+ if (!device) {
+ device = new QTouchDevice;
+ device->setType(QTouchDevice::TouchScreen);
+ QWindowSystemInterface::registerTouchDevice(device);
+ }
+
+ m_pendingFakeTouchEventCount++;
+
+ const QList& currentTouchPoints = m_touchPoints.values();
+ Qt::TouchPointStates touchPointStates = 0;
+ foreach (const QTouchEvent::TouchPoint& touchPoint, currentTouchPoints)
+ touchPointStates |= touchPoint.state();
+
+ QTouchEvent event(type, device, Qt::NoModifier, touchPointStates, currentTouchPoints);
+ event.setTimestamp(timestamp);
+ event.setAccepted(false);
+
+ QGuiApplication::notify(window, &event);
+
+ updateVisualMockTouchPoints(window,m_holdingControl ? currentTouchPoints : QList());
+
+ // Get rid of touch-points that are no longer valid
+ foreach (const QTouchEvent::TouchPoint& touchPoint, currentTouchPoints) {
+ if (touchPoint.state() == Qt::TouchPointReleased)
+ m_touchPoints.remove(touchPoint.id());
+ }
+
+ return event.isAccepted();
+}
+
+void TouchMockingApplication::updateVisualMockTouchPoints(QQuickView* window,const QList& touchPoints)
+{
+ if (touchPoints.isEmpty()) {
+ // Hide all touch indicator items.
+ foreach (QQuickItem* item, m_activeMockComponents.values())
+ item->setProperty("pressed", false);
+
+ return;
+ }
+
+ foreach (const QTouchEvent::TouchPoint& touchPoint, touchPoints) {
+ QQuickItem* mockTouchPointItem = m_activeMockComponents.value(touchPoint.id());
+
+ if (!mockTouchPointItem) {
+ QQmlComponent touchMockPointComponent(window->engine(), QUrl("qrc:///qml/MockTouchPoint.qml"));
+ mockTouchPointItem = qobject_cast(touchMockPointComponent.create());
+ Q_ASSERT(mockTouchPointItem);
+ m_activeMockComponents.insert(touchPoint.id(), mockTouchPointItem);
+ mockTouchPointItem->setProperty("pointId", QVariant(touchPoint.id()));
+ mockTouchPointItem->setParent(window->rootObject());
+ mockTouchPointItem->setParentItem(window->rootObject());
+ }
+
+ QRectF touchRect = touchPoint.rect();
+ mockTouchPointItem->setX(touchRect.center().x());
+ mockTouchPointItem->setY(touchRect.center().y());
+ mockTouchPointItem->setWidth(touchRect.width());
+ mockTouchPointItem->setHeight(touchRect.height());
+ mockTouchPointItem->setProperty("pressed", QVariant(touchPoint.state() != Qt::TouchPointReleased));
+ }
+}
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/touchmockingapplication.h b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/touchmockingapplication.h
new file mode 100644
index 0000000..d6f13ec
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/touchmockingapplication.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt WebBrowser application.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TOUCHMOCKINGAPPLICATION_H
+#define TOUCHMOCKINGAPPLICATION_H
+
+#include
+#include
+#include
+#include
+
+QT_BEGIN_NAMESPACE
+class QQuickView;
+class QQuickItem;
+QT_END_NAMESPACE
+
+class TouchMockingApplication : public QGuiApplication
+{
+ Q_OBJECT
+
+public:
+ TouchMockingApplication(int &argc, char **argv);
+
+ virtual bool notify(QObject *, QEvent *) override;
+
+private:
+ void updateTouchPoint(const QMouseEvent *, QTouchEvent::TouchPoint, Qt::MouseButton);
+ bool sendTouchEvent(QQuickView *, QEvent::Type, ulong timestamp);
+ void updateVisualMockTouchPoints(QQuickView *,const QList &touchPoints);
+
+private:
+ bool m_realTouchEventReceived;
+ int m_pendingFakeTouchEventCount;
+
+ QPointF m_lastPos;
+ QPointF m_lastScreenPos;
+ QPointF m_startScreenPos;
+
+ QHash m_touchPoints;
+ QSet m_heldTouchPoints;
+ QHash m_activeMockComponents;
+
+ bool m_holdingControl;
+};
+
+#endif // TOUCHMOCKINGAPPLICATION_H
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/touchtracker.cpp b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/touchtracker.cpp
new file mode 100644
index 0000000..bd0f132
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/touchtracker.cpp
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt WebBrowser application.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "touchtracker.h"
+#include "appengine.h"
+
+#include
+
+using namespace utils;
+
+TouchTracker::TouchTracker(QQuickItem *parent)
+ : QQuickItem(parent)
+ , m_blockEvents(false)
+ , m_diff(0)
+ , m_previousY(0)
+ , m_target(0)
+ , m_delegate(0)
+{
+ m_startPoint.ts = 0;
+ m_currentPoint.ts = 0;
+}
+
+QQuickItem *TouchTracker::target() const
+{
+ return m_target;
+}
+
+void TouchTracker::setTarget(QQuickItem * target)
+{
+ m_target = target;
+ emit targetChanged();
+}
+
+int TouchTracker::xVelocity() const
+{
+ qreal pos = qAbs(m_startPoint.x() - m_currentPoint.x());
+ qreal time = qAbs(m_startPoint.ts - m_currentPoint.ts);
+ return pos / time * 1000;
+}
+
+int TouchTracker::yVelocity() const
+{
+ qreal pos = qAbs(m_startPoint.y() - m_currentPoint.y());
+ qreal time = qAbs(m_startPoint.ts - m_currentPoint.ts);
+ return pos / time * 1000;
+}
+
+
+qreal TouchTracker::touchX() const
+{
+ return m_currentPoint.x();
+}
+
+qreal TouchTracker::touchY() const
+{
+ return m_currentPoint.y();
+}
+
+bool TouchTracker::blockEvents() const
+{
+ return m_blockEvents;
+}
+
+void TouchTracker::setBlockEvents(bool shouldBlock)
+{
+ if (m_blockEvents == shouldBlock)
+ return;
+ m_blockEvents = shouldBlock;
+ emit blockEventsChanged();
+}
+
+bool TouchTracker::eventFilter(QObject *obj, QEvent *event)
+{
+ if (obj != m_delegate)
+ return QQuickItem::eventFilter(obj, event);
+
+ if (event->type() == QEvent::Wheel)
+ return m_blockEvents;
+
+ if (!isTouchEvent(event))
+ return QQuickItem::eventFilter(obj, event);
+
+ const QTouchEvent *touch = static_cast(event);
+ const QList &points = touch->touchPoints();
+ m_previousY = m_currentPoint.y();
+ m_currentPoint.pos = m_target->mapToScene(points.at(0).pos());
+ m_currentPoint.ts = QDateTime::currentMSecsSinceEpoch();
+ int currentDiff = m_previousY - m_currentPoint.y();
+
+ if ((currentDiff > 0 && m_diff < 0) || (currentDiff < 0 && m_diff > 0))
+ emit scrollDirectionChanged();
+
+ m_diff = currentDiff;
+
+ emit touchChanged();
+ emit velocityChanged();
+
+ if (event->type() == QEvent::TouchEnd)
+ emit touchEnd();
+
+ return m_blockEvents;
+}
+
+void TouchTracker::touchEvent(QTouchEvent * event)
+{
+ if (!m_target) {
+ if (!m_blockEvents)
+ QQuickItem::touchEvent(event);
+
+ return;
+ }
+
+ event->setAccepted(false);
+
+ const QList &points = event->touchPoints();
+ m_currentPoint.pos = m_target->mapToScene(points.at(0).pos());
+ m_currentPoint.ts = QDateTime::currentMSecsSinceEpoch();
+
+ if (event->type() == QEvent::TouchBegin) {
+ m_startPoint = m_currentPoint;
+ emit touchBegin();
+ }
+
+ emit touchChanged();
+
+ // We have to find the delegate to be able to filter
+ // events from the WebEngineView.
+ // This is a hack and should preferably be made easier
+ // with the API in some way.
+ QQuickItem *child = m_target->childAt(m_currentPoint.x(), m_currentPoint.y());
+ if (child && m_delegate != child) {
+ child->installEventFilter(this);
+ m_delegate = child;
+ }
+}
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/touchtracker.h b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/touchtracker.h
new file mode 100644
index 0000000..dfd2e61
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/src/touchtracker.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt WebBrowser application.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TOUCHTRACKER_H
+#define TOUCHTRACKER_H
+
+#include
+#include
+
+class TouchTracker : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal touchX READ touchX NOTIFY touchChanged)
+ Q_PROPERTY(qreal touchY READ touchY NOTIFY touchChanged)
+ Q_PROPERTY(int xVelocity READ xVelocity NOTIFY velocityChanged)
+ Q_PROPERTY(int yVelocity READ yVelocity NOTIFY velocityChanged)
+ Q_PROPERTY(bool blockEvents READ blockEvents WRITE setBlockEvents NOTIFY blockEventsChanged)
+ Q_PROPERTY(QQuickItem* target READ target WRITE setTarget NOTIFY targetChanged)
+
+ struct PositionInfo
+ {
+ QPointF pos;
+ qint64 ts;
+ qreal x() const { return pos.x(); }
+ qreal y() const { return pos.y(); }
+ };
+
+public:
+ TouchTracker(QQuickItem *parent = 0);
+
+ qreal touchX() const;
+ qreal touchY() const;
+ int xVelocity() const;
+ int yVelocity() const;
+ QQuickItem* target() const;
+ bool blockEvents() const;
+ void setBlockEvents(bool shouldBlock);
+ void setTarget(QQuickItem * target);
+
+signals:
+ void touchChanged();
+ void blockEventsChanged();
+ void targetChanged();
+ void touchBegin();
+ void touchEnd();
+ void velocityChanged();
+ void scrollDirectionChanged();
+
+protected:
+ bool eventFilter(QObject *obj, QEvent *event) override;
+ void touchEvent(QTouchEvent *event) override;
+
+private:
+ bool m_blockEvents;
+ int m_diff;
+ int m_previousY;
+ PositionInfo m_startPoint;
+ PositionInfo m_currentPoint;
+ QQuickItem *m_target;
+ QQuickItem *m_delegate;
+};
+
+#endif // TOUCHTRACKER_H
diff --git a/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/tests/tests.pro b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/tests/tests.pro
new file mode 100644
index 0000000..9671085
--- /dev/null
+++ b/basicsuite/qtwebbrowser/tqtc-qtwebbrowser/tests/tests.pro
@@ -0,0 +1 @@
+TEMPLATE = subdirs
diff --git a/basicsuite/shared/fonts.qrc b/basicsuite/shared/fonts.qrc
new file mode 100644
index 0000000..ccc8864
--- /dev/null
+++ b/basicsuite/shared/fonts.qrc
@@ -0,0 +1,19 @@
+
+
+ fonts/TitilliumWeb-Black.ttf
+ fonts/TitilliumWeb-Bold.ttf
+ fonts/TitilliumWeb-ExtraLight.ttf
+ fonts/TitilliumWeb-Light.ttf
+ fonts/TitilliumWeb-Regular.ttf
+ fonts/TitilliumWeb-SemiBold.ttf
+ fonts/ebike-fonts/fontawesome-webfont.ttf
+ fonts/ebike-fonts/Montserrat-Bold.ttf
+ fonts/ebike-fonts/Montserrat-Light.ttf
+ fonts/ebike-fonts/Montserrat-Medium.ttf
+ fonts/ebike-fonts/Montserrat-Regular.ttf
+ fonts/ebike-fonts/Teko-Bold.ttf
+ fonts/ebike-fonts/Teko-Light.ttf
+ fonts/ebike-fonts/Teko-Medium.ttf
+ fonts/ebike-fonts/Teko-Regular.ttf
+
+
diff --git a/basicsuite/shared/fonts/TitilliumWeb-Black.ttf b/basicsuite/shared/fonts/TitilliumWeb-Black.ttf
new file mode 100644
index 0000000..fc5c4b5
Binary files /dev/null and b/basicsuite/shared/fonts/TitilliumWeb-Black.ttf differ
diff --git a/basicsuite/shared/fonts/TitilliumWeb-Bold.ttf b/basicsuite/shared/fonts/TitilliumWeb-Bold.ttf
new file mode 100644
index 0000000..0af0fe7
Binary files /dev/null and b/basicsuite/shared/fonts/TitilliumWeb-Bold.ttf differ
diff --git a/basicsuite/shared/fonts/TitilliumWeb-BoldItalic.ttf b/basicsuite/shared/fonts/TitilliumWeb-BoldItalic.ttf
new file mode 100644
index 0000000..77425ea
Binary files /dev/null and b/basicsuite/shared/fonts/TitilliumWeb-BoldItalic.ttf differ
diff --git a/basicsuite/shared/fonts/TitilliumWeb-ExtraLight.ttf b/basicsuite/shared/fonts/TitilliumWeb-ExtraLight.ttf
new file mode 100644
index 0000000..2b506ef
Binary files /dev/null and b/basicsuite/shared/fonts/TitilliumWeb-ExtraLight.ttf differ
diff --git a/basicsuite/shared/fonts/TitilliumWeb-ExtraLightItalic.ttf b/basicsuite/shared/fonts/TitilliumWeb-ExtraLightItalic.ttf
new file mode 100644
index 0000000..c1be5ba
Binary files /dev/null and b/basicsuite/shared/fonts/TitilliumWeb-ExtraLightItalic.ttf differ
diff --git a/basicsuite/shared/fonts/TitilliumWeb-Italic.ttf b/basicsuite/shared/fonts/TitilliumWeb-Italic.ttf
new file mode 100644
index 0000000..42f2c10
Binary files /dev/null and b/basicsuite/shared/fonts/TitilliumWeb-Italic.ttf differ
diff --git a/basicsuite/shared/fonts/TitilliumWeb-Light.ttf b/basicsuite/shared/fonts/TitilliumWeb-Light.ttf
new file mode 100644
index 0000000..ca67971
Binary files /dev/null and b/basicsuite/shared/fonts/TitilliumWeb-Light.ttf differ
diff --git a/basicsuite/shared/fonts/TitilliumWeb-LightItalic.ttf b/basicsuite/shared/fonts/TitilliumWeb-LightItalic.ttf
new file mode 100644
index 0000000..2ea724f
Binary files /dev/null and b/basicsuite/shared/fonts/TitilliumWeb-LightItalic.ttf differ
diff --git a/basicsuite/shared/fonts/TitilliumWeb-Regular.ttf b/basicsuite/shared/fonts/TitilliumWeb-Regular.ttf
new file mode 100644
index 0000000..6da8219
Binary files /dev/null and b/basicsuite/shared/fonts/TitilliumWeb-Regular.ttf differ
diff --git a/basicsuite/shared/fonts/TitilliumWeb-SemiBold.ttf b/basicsuite/shared/fonts/TitilliumWeb-SemiBold.ttf
new file mode 100644
index 0000000..dfdcdbe
Binary files /dev/null and b/basicsuite/shared/fonts/TitilliumWeb-SemiBold.ttf differ
diff --git a/basicsuite/shared/fonts/TitilliumWeb-SemiBoldItalic.ttf b/basicsuite/shared/fonts/TitilliumWeb-SemiBoldItalic.ttf
new file mode 100644
index 0000000..b68a669
Binary files /dev/null and b/basicsuite/shared/fonts/TitilliumWeb-SemiBoldItalic.ttf differ
diff --git a/basicsuite/shared/fonts/ebike-fonts/Montserrat-Bold.ttf b/basicsuite/shared/fonts/ebike-fonts/Montserrat-Bold.ttf
new file mode 100644
index 0000000..8e9a5f3
Binary files /dev/null and b/basicsuite/shared/fonts/ebike-fonts/Montserrat-Bold.ttf differ
diff --git a/basicsuite/shared/fonts/ebike-fonts/Montserrat-Light.ttf b/basicsuite/shared/fonts/ebike-fonts/Montserrat-Light.ttf
new file mode 100644
index 0000000..e66dc5b
Binary files /dev/null and b/basicsuite/shared/fonts/ebike-fonts/Montserrat-Light.ttf differ
diff --git a/basicsuite/shared/fonts/ebike-fonts/Montserrat-Medium.ttf b/basicsuite/shared/fonts/ebike-fonts/Montserrat-Medium.ttf
new file mode 100644
index 0000000..88d70b8
Binary files /dev/null and b/basicsuite/shared/fonts/ebike-fonts/Montserrat-Medium.ttf differ
diff --git a/basicsuite/shared/fonts/ebike-fonts/Montserrat-Regular.ttf b/basicsuite/shared/fonts/ebike-fonts/Montserrat-Regular.ttf
new file mode 100644
index 0000000..626355a
Binary files /dev/null and b/basicsuite/shared/fonts/ebike-fonts/Montserrat-Regular.ttf differ
diff --git a/basicsuite/shared/fonts/ebike-fonts/Teko-Bold.ttf b/basicsuite/shared/fonts/ebike-fonts/Teko-Bold.ttf
new file mode 100644
index 0000000..d061824
Binary files /dev/null and b/basicsuite/shared/fonts/ebike-fonts/Teko-Bold.ttf differ
diff --git a/basicsuite/shared/fonts/ebike-fonts/Teko-Light.ttf b/basicsuite/shared/fonts/ebike-fonts/Teko-Light.ttf
new file mode 100644
index 0000000..ec5194a
Binary files /dev/null and b/basicsuite/shared/fonts/ebike-fonts/Teko-Light.ttf differ
diff --git a/basicsuite/shared/fonts/ebike-fonts/Teko-Medium.ttf b/basicsuite/shared/fonts/ebike-fonts/Teko-Medium.ttf
new file mode 100644
index 0000000..cc38086
Binary files /dev/null and b/basicsuite/shared/fonts/ebike-fonts/Teko-Medium.ttf differ
diff --git a/basicsuite/shared/fonts/ebike-fonts/Teko-Regular.ttf b/basicsuite/shared/fonts/ebike-fonts/Teko-Regular.ttf
new file mode 100644
index 0000000..3161e63
Binary files /dev/null and b/basicsuite/shared/fonts/ebike-fonts/Teko-Regular.ttf differ
diff --git a/basicsuite/shared/fonts/ebike-fonts/fontawesome-webfont.ttf b/basicsuite/shared/fonts/ebike-fonts/fontawesome-webfont.ttf
new file mode 100644
index 0000000..35acda2
Binary files /dev/null and b/basicsuite/shared/fonts/ebike-fonts/fontawesome-webfont.ttf differ
diff --git a/basicsuite/shared/main.cpp b/basicsuite/shared/main.cpp
index 3c21bf5..9e27596 100644
--- a/basicsuite/shared/main.cpp
+++ b/basicsuite/shared/main.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of Qt for Device Creation.
@@ -63,6 +63,10 @@
#include
#include
#include
+#include
+#include
+#include
+#include
#if defined(USE_QTWEBENGINE)
#include
@@ -70,13 +74,15 @@
#include "engine.h"
-int main(int argc, char **argv)
+static bool checkGlAvailability()
{
- //qputenv("QT_IM_MODULE", QByteArray("qtvkb"));
-
- QApplication app(argc, argv);
-
+ QQuickWindow window;
+ return ((window.sceneGraphBackend() != "software") &&
+ (window.sceneGraphBackend() != "softwarecontext"));
+}
+int main(int argc, char **argv)
+{
#if defined(USE_QTWEBENGINE)
// This is currently needed by all QtWebEngine applications using the HW accelerated QQuickWebView.
// It enables sharing the QOpenGLContext of all QQuickWindows of the application.
@@ -84,6 +90,31 @@ int main(int argc, char **argv)
QtWebEngine::initialize();
#endif
+ //qputenv("QT_IM_MODULE", QByteArray("qtvkb"));
+ qputenv("QT_QUICK_CONTROLS_CONF", "/data/user/qt/qtquickcontrols2/qtquickcontrols2.conf");
+ QIcon::setThemeName("gallery");
+ QIcon::setThemeSearchPaths(QStringList() << "/data/user/qt/qtquickcontrols2/icons");
+
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+
+ QApplication app(argc, argv);
+
+ QFontDatabase::addApplicationFont(":/fonts/TitilliumWeb-Regular.ttf");
+ QFontDatabase::addApplicationFont(":/fonts/TitilliumWeb-SemiBold.ttf");
+ QFontDatabase::addApplicationFont(":/fonts/TitilliumWeb-Bold.ttf");
+ QFontDatabase::addApplicationFont(":/fonts/TitilliumWeb-Black.ttf");
+
+ //For eBike demo
+ QFontDatabase::addApplicationFont(":/fonts/ebike-fonts/Montserrat-Bold.ttf");
+ QFontDatabase::addApplicationFont(":/fonts/ebike-fonts/Montserrat-Light.ttf");
+ QFontDatabase::addApplicationFont(":/fonts/ebike-fonts/Montserrat-Medium.ttf");
+ QFontDatabase::addApplicationFont(":/fonts/ebike-fonts/Montserrat-Regular.ttf");
+ QFontDatabase::addApplicationFont(":/fonts/ebike-fonts/Teko-Bold.ttf");
+ QFontDatabase::addApplicationFont(":/fonts/ebike-fonts/Teko-Light.ttf");
+ QFontDatabase::addApplicationFont(":/fonts/ebike-fonts/Teko-Medium.ttf");
+ QFontDatabase::addApplicationFont(":/fonts/ebike-fonts/Teko-Regular.ttf");
+ QFontDatabase::addApplicationFont(":/fonts/ebike-fonts/fontawesome-webfont.ttf");
+
QString path = app.applicationDirPath();
QPalette pal;
@@ -114,10 +145,37 @@ int main(int argc, char **argv)
QGuiApplication::setFont(font);
}
+ // Material style can be set only for devices supporting GL
+ QSettings styleSettings;
+ QString style = styleSettings.value("style").toString();
+ if (checkGlAvailability()) {
+ if (style.isEmpty() || style == "Default")
+ styleSettings.setValue("style", "Material");
+ } else {
+ qDebug()<<"No GL available, skipping Material style";
+ }
+ QQuickStyle::setStyle(styleSettings.value("style").toString());
+
DummyEngine engine;
QQmlApplicationEngine applicationengine;
+ QString appFont("TitilliumWeb");
applicationengine.rootContext()->setContextProperty("engine", &engine);
+ applicationengine.rootContext()->setContextProperty("appFont", appFont);
+ applicationengine.rootContext()->setContextProperty("availableStyles", QQuickStyle::availableStyles());
+
+ QSettings demoSettings("Boot2Qt-demos", "demoSettings");
+
+ applicationengine.rootContext()->setContextProperty("_backgroundColor", demoSettings.value("backgroundColor", "#09102b"));
+ applicationengine.rootContext()->setContextProperty("_primaryGreen", demoSettings.value("primaryGreen", "#41cd52"));
+ applicationengine.rootContext()->setContextProperty("_mediumGreen", demoSettings.value("mediumGreen", "#21be2b"));
+ applicationengine.rootContext()->setContextProperty("_darkGreen", demoSettings.value("darkGreen", "#17a81a"));
+ applicationengine.rootContext()->setContextProperty("_primaryGrey", demoSettings.value("primaryGrey", "#9d9faa"));
+ applicationengine.rootContext()->setContextProperty("_secondaryGrey", demoSettings.value("secondaryGrey", "#3a4055"));
+
+ applicationengine.rootContext()->setContextProperty("VideosLocation", demoSettings.value("videosLocation", "file:///data/videos"));
+ applicationengine.rootContext()->setContextProperty("DefaultVideoUrl", demoSettings.value("defaultVideoUrl", "file:///data/videos/Qt+for+Designers+and+Developers.mp4"));
+
applicationengine.load(QUrl::fromLocalFile(path + "/SharedMain.qml"));
app.exec();
diff --git a/basicsuite/shared/settings.js b/basicsuite/shared/settings.js
new file mode 100644
index 0000000..8dcc976
--- /dev/null
+++ b/basicsuite/shared/settings.js
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qt for Device Creation.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+.pragma library
+
+var backgroundColor = "#09102b"
+
+var primaryGreen = "#41cd52"
+var mediumGreen = "#21be2b"
+var darkGreen = "#17a81a"
+
+var primaryGrey = "#9d9faa"
+var secondaryGrey = "#3a4055"
+
diff --git a/basicsuite/shared/settings.qrc b/basicsuite/shared/settings.qrc
new file mode 100644
index 0000000..576a1e9
--- /dev/null
+++ b/basicsuite/shared/settings.qrc
@@ -0,0 +1,5 @@
+
+
+ settings.js
+
+
diff --git a/basicsuite/shared/shared.pri b/basicsuite/shared/shared.pri
index bc1c222..9277275 100644
--- a/basicsuite/shared/shared.pri
+++ b/basicsuite/shared/shared.pri
@@ -1,12 +1,12 @@
# widget dependecy is required by QtCharts demo
-QT += quick widgets
+QT += quick widgets quickcontrols2
qtHaveModule(webengine) {
DEFINES += USE_QTWEBENGINE
QT += webengine
}
-DESTPATH = /data/user/$$TARGET
+DESTPATH = /data/user/qt/$$TARGET
target.path = $$DESTPATH
SOURCES += $$PWD/main.cpp \
@@ -16,7 +16,9 @@ HEADERS += $$PWD/engine.h
defineTest(b2qtdemo_deploy_defaults) {
commonFiles.files = \
- ../shared/SharedMain.qml
+ ../shared/SharedMain.qml \
+ preview_l.jpg \
+ demo.xml
commonFiles.path = $$DESTPATH
OTHER_FILES += $${commonFiles.files}
INSTALLS += commonFiles
@@ -25,3 +27,22 @@ defineTest(b2qtdemo_deploy_defaults) {
export(OTHER_FILES)
export(INSTALLS)
}
+
+DISTFILES += $$PWD/fonts/TitilliumWeb-Black.ttf \
+ $$PWD/fonts/TitilliumWeb-Bold.ttf \
+ $$PWD/fonts/TitilliumWeb-ExtraLight.ttf \
+ $$PWD/fonts/TitilliumWeb-Light.ttf \
+ $$PWD/fonts/TitilliumWeb-Regular.ttf \
+ $$PWD/fonts/TitilliumWeb-SemiBold.ttf \
+ $$PWD/fonts/ebike-fonts/fontawesome-webfont.ttf \
+ $$PWD/fonts/ebike-fonts/Montserrat-Bold.ttf \
+ $$PWD/fonts/ebike-fonts/Montserrat-Light.ttf \
+ $$PWD/fonts/ebike-fonts/Montserrat-Medium.ttf \
+ $$PWD/fonts/ebike-fonts/Montserrat-Regular.ttf \
+ $$PWD/fonts/ebike-fonts/Teko-Bold.ttf \
+ $$PWD/fonts/ebike-fonts/Teko-Light.ttf \
+ $$PWD/fonts/ebike-fonts/Teko-Medium.ttf \
+ $$PWD/fonts/ebike-fonts/Teko-Regular.ttf
+
+RESOURCES += \
+ $$PWD/fonts.qrc
diff --git a/basicsuite/textinput/demo.xml b/basicsuite/textinput/demo.xml
new file mode 100644
index 0000000..fadfc67
--- /dev/null
+++ b/basicsuite/textinput/demo.xml
@@ -0,0 +1,9 @@
+
+
+
+
+This example illustrates how to handle input on touch devices.
+
+Qt for Device Creation comes with Qt Virtual Keyboard - a framework that consists of a C++ backend with support for custom input methods, as well as a reference keyboard front end implemented in QML, supporting multiple languages.
+
+
diff --git a/doc/b2qt-demos.qdoc b/doc/b2qt-demos.qdoc
index b147df2..a2e7973 100644
--- a/doc/b2qt-demos.qdoc
+++ b/doc/b2qt-demos.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of Qt for Device Creation.
@@ -50,7 +50,7 @@
/*!
\page index.html
- \title Qt 5.7 for Device Creation Examples and Demos
+ \title Qt 5.14.2 for Device Creation Examples and Demos
\SDK has a number of examples and demos. These are included in the
\B2Q images, available in the launcher that is run by default at
@@ -63,32 +63,20 @@
*/
/*!
- \example basicsuite/about-b2qt
- \title About Qt for Device Creation
+ \example basicsuite/ebike-ui
+ \title e-bike Demo
\ingroup b2qt-demos
- \brief Displays information about Qt for Device Creation.
+ \brief An E-bike instrument cluster concept.
- \image b2qt-demo-about-b2qt.jpg
+ \image b2qt-demo-ebike-ui.jpg
- A demo that provides an introduction to what Qt for Device Creation is all about.
-*/
-
-/*!
- \example basicsuite/camera
- \title Camera
- \ingroup b2qt-demos
- \brief Demonstrates using camera in a QML application.
-
- \image b2qt-demo-camera.jpg
+ An E-bike instrument cluster concept designed and implemented by Qt.
- This example demonstrates the use of the camera features provided by Qt Multimedia with
- Qt Quick.
-
- Demo can be used to take pictures. Files are saved inside the \c {/data/images/} folder
- and can be then viewed with the \l {Photo Gallery} demo application.
+ The entire concept is a testament that Qt brings the HMI designers and Software engineers together
+ by using the same tools, allowing them to fast prototyping through collaborative workflow.
+ In addition to that, Qt is optimized for running on low end SoC even the ones that don't have GPU acceleration
+ for graphics.
- Camera parameters such as flash mode, scene mode or white balance can be changed. The
- availability of parameters depends on what the camera driver provides.
*/
/*!
@@ -119,40 +107,6 @@
It can play from a file or from a network source, both videos and music.
*/
-/*!
- \example basicsuite/canvas3d-planets
- \title Qt Canvas3D Planets
- \ingroup b2qt-demos
- \brief Demonstrates the usage of Qt Canvas 3D, a WebGL-like API for QML, and popular JavaScript frameworks like three.js.
-
- \image b2qt-demo-canvas3d-planets.jpg
-
- The demo uses Qt Quick and Canvas 3D in combination with \l{http://threejs.org/}{three.js},
- \l{https://github.com/jeromeetienne/threex.planets}{threex.planets}, and Qt Quick
- Controls. Tapping on a planet changes the view and moves to the chosen planet. Use the sliders
- to adjust the zoom levels and viewing distance. Tapping outside the controls moves the focus
- back to the solar view.
-*/
-
-/*!
- \example basicsuite/qt5-cinematicdemo
- \title Qt 5 Cinematic Demo
- \ingroup b2qt-demos
- \brief A cool demonstration of the graphical prowess of Qt 5 and Qt Quick 2.
-
- \image b2qt-demo-qt5-cinematicdemo.jpg
-
- The Qt5 Cinematic Experience is a demo by "QUIt Coding", a small group of talented individuals
- enjoying software development with cutting edge technologies. They are official members of the
- Qt Ambassador Program.
-
- The demo shows off a number features of Qt Quick 2.0. A nicely styled list control of movie
- covers with lighting effects, particles and transitions. The information roll-down curvy
- curtain is implemented using inline GLSL in the QML file.
-
- More awesome looking Qt Quick examples are available from \l {http://quitcoding.com}.
-*/
-
/*!
\example basicsuite/textinput
\title Text Input
@@ -181,49 +135,16 @@
*/
/*!
- \example basicsuite/enterprise-dashboard
- \title Dashboard
- \ingroup b2qt-demos
- \brief A car dashboard created using Qt Quick Enterprise Controls.
-
- \image b2qt-demo-enterprise-dashboard.jpg
-
- This example project demonstrates using several CircularGauge controls to create a car dashboard.
-*/
-
-/*!
- \example basicsuite/enterprise-qtdatavis3d
- \title Qt Data Visualization
- \ingroup b2qt-demos
- \brief An interactive showcase for Qt Data Visualization 3D.
-
- \image b2qt-demo-enterprise-qtdatavis3d.jpg
-
- This example demonstrates how to use the Qt Data Visualization module to display 3D data visualizations in QML.
-*/
-
-/*!
- \example basicsuite/enterprise-gallery
- \title Enterprise Controls Gallery
- \ingroup b2qt-demos
- \brief An interactive showcase for Qt Quick Enterprise Controls.
-
- \image b2qt-demo-enterprise-gallery.jpg
-
- This example project demonstrates the various UI controls provided by Qt Quick Enterprise Controls.
-*/
-
-/*!
- \example basicsuite/enterprise-flat-controls
- \title Enterprise Flat Controls
+ \example basicsuite/qtquickcontrols2
+ \title Qt Quick Controls 2 - Gallery
\ingroup b2qt-demos
- \brief The Flat Style Gallery example showcases the Qt Quick Controls.
+ \brief A gallery of controls.
- \image b2qt-demo-enterprise-flat-controls.jpg
+ \image b2qt-demo-qtquickcontrols2.jpg
- This demo combines both the standard Quick Controls as well as the Qt Quick Enterprise Controls
- both of which are using the new Flat style. The Flat style for Qt Quick Controls has a modern
- look and feel and is perfect for the touch driven interfaces commonly developed by device creators.
+ The gallery example is a simple application with a drawer menu that contains all the Qt Quick Controls 2. Each
+ menu item opens a page that shows the graphical appearance of a control, allows you to interact with the control,
+ and explains in which circumstances it is handy to use this control.
*/
/*!
diff --git a/doc/b2qt-demos.qdocconf b/doc/b2qt-demos.qdocconf
index d3cca4f..2409f36 100644
--- a/doc/b2qt-demos.qdocconf
+++ b/doc/b2qt-demos.qdocconf
@@ -5,8 +5,8 @@ outputencoding = UTF-8
sourceencoding = UTF-8
project = QtforDeviceCreationDemos
-description = Qt 5.7 for Device Creation Examples and Demos
-version = 5.7.0
+description = Qt 5.14.2 for Device Creation Examples and Demos
+version = 5.14.2
sourcedirs = .
imagedirs += images
@@ -21,9 +21,9 @@ exampledirs = ..
qhp.projects = QtforDeviceCreationDemos
qhp.QtforDeviceCreationDemos.file = b2qt-demos.qhp
-qhp.QtforDeviceCreationDemos.namespace = com.digia.b2qt-demos.570
+qhp.QtforDeviceCreationDemos.namespace = org.qt-project.b2qt-demos.5142
qhp.QtforDeviceCreationDemos.virtualFolder = b2qt-demos
-qhp.QtforDeviceCreationDemos.indexTitle = Qt 5.7 for Device Creation Examples and Demos
+qhp.QtforDeviceCreationDemos.indexTitle = Qt 5.14.2 for Device Creation Examples and Demos
qhp.QtforDeviceCreationDemos.indexRoot =
qhp.QtforDeviceCreationDemos.subprojects = demos
@@ -35,4 +35,4 @@ manifestmeta.b2qt.names = "QtforDeviceCreationDemos/*"
macro.B2Q = "Boot to Qt"
macro.SDK = "Qt for Device Creation"
-navigation.landingpage = "Qt 5.7 for Device Creation Examples and Demos"
+navigation.landingpage = "Qt 5.14.2 for Device Creation Examples and Demos"
diff --git a/doc/images/b2qt-demo-advancedcustommaterial.jpg b/doc/images/b2qt-demo-advancedcustommaterial.jpg
new file mode 100644
index 0000000..cbd6500
Binary files /dev/null and b/doc/images/b2qt-demo-advancedcustommaterial.jpg differ
diff --git a/doc/images/b2qt-demo-ebike-ui.jpg b/doc/images/b2qt-demo-ebike-ui.jpg
new file mode 100644
index 0000000..570e609
Binary files /dev/null and b/doc/images/b2qt-demo-ebike-ui.jpg differ
diff --git a/doc/images/b2qt-demo-enterprise-charts.jpg b/doc/images/b2qt-demo-enterprise-charts.jpg
deleted file mode 120000
index e2f9e6c..0000000
--- a/doc/images/b2qt-demo-enterprise-charts.jpg
+++ /dev/null
@@ -1 +0,0 @@
-../../basicsuite/enterprise-charts/preview_l.jpg
\ No newline at end of file
diff --git a/doc/images/b2qt-demo-enterprise-charts.jpg b/doc/images/b2qt-demo-enterprise-charts.jpg
new file mode 100644
index 0000000..b472087
Binary files /dev/null and b/doc/images/b2qt-demo-enterprise-charts.jpg differ
diff --git a/doc/images/b2qt-demo-graphicaleffects.jpg b/doc/images/b2qt-demo-graphicaleffects.jpg
deleted file mode 120000
index 5a092e2..0000000
--- a/doc/images/b2qt-demo-graphicaleffects.jpg
+++ /dev/null
@@ -1 +0,0 @@
-../../basicsuite/graphicaleffects/preview_l.jpg
\ No newline at end of file
diff --git a/doc/images/b2qt-demo-graphicaleffects.jpg b/doc/images/b2qt-demo-graphicaleffects.jpg
new file mode 100644
index 0000000..da1255b
Binary files /dev/null and b/doc/images/b2qt-demo-graphicaleffects.jpg differ
diff --git a/doc/images/b2qt-demo-mediaplayer.jpg b/doc/images/b2qt-demo-mediaplayer.jpg
deleted file mode 120000
index cce5a00..0000000
--- a/doc/images/b2qt-demo-mediaplayer.jpg
+++ /dev/null
@@ -1 +0,0 @@
-../../basicsuite/mediaplayer/preview_l.jpg
\ No newline at end of file
diff --git a/doc/images/b2qt-demo-mediaplayer.jpg b/doc/images/b2qt-demo-mediaplayer.jpg
new file mode 100644
index 0000000..d61efbc
Binary files /dev/null and b/doc/images/b2qt-demo-mediaplayer.jpg differ
diff --git a/doc/images/b2qt-demo-qtquickcontrols2.jpg b/doc/images/b2qt-demo-qtquickcontrols2.jpg
new file mode 100644
index 0000000..89a4fcb
Binary files /dev/null and b/doc/images/b2qt-demo-qtquickcontrols2.jpg differ
diff --git a/doc/images/b2qt-demo-qtwebbrowser.jpg b/doc/images/b2qt-demo-qtwebbrowser.jpg
deleted file mode 120000
index 13dea2f..0000000
--- a/doc/images/b2qt-demo-qtwebbrowser.jpg
+++ /dev/null
@@ -1 +0,0 @@
-../../basicsuite/qtwebbrowser/preview_l.jpg
\ No newline at end of file
diff --git a/doc/images/b2qt-demo-qtwebbrowser.jpg b/doc/images/b2qt-demo-qtwebbrowser.jpg
new file mode 100644
index 0000000..c63de25
Binary files /dev/null and b/doc/images/b2qt-demo-qtwebbrowser.jpg differ
diff --git a/tradeshow/iot-sensortag/README b/tradeshow/iot-sensortag/README
new file mode 100644
index 0000000..8c83e7e
--- /dev/null
+++ b/tradeshow/iot-sensortag/README
@@ -0,0 +1,11 @@
+This is a work-in-progress project targeted for Embedded World conference 2017. With the application you can read sensor information and publish it to the Microsoft Azure cloud service for clients to read it. There is three form factors supported for the client device, and the correct form factor is automatically determined by the screen dimensions.
+
+Data is published to the cloud when the application is run either in sensor or mock mode.
+
+Usage: SensorTagDemo --source[=cloud]
+
+--source cloud sensor data is read from cloud
+ sensor sensor data is read from a Bluetooth sensor
+ mock sensor data is read from a mock data provider
+
+You can also set the environment variable QT_IOS_DEMO_NO_FULLSCREEN to force the application not to go to fullscreen mode. In this case the application is drawn in a window with dimensions specific to the selected screen form factor. Note: this setting is mainly intended for development purposes.
diff --git a/tradeshow/iot-sensortag/SensorTagDemo.pro b/tradeshow/iot-sensortag/SensorTagDemo.pro
new file mode 100644
index 0000000..7393afc
--- /dev/null
+++ b/tradeshow/iot-sensortag/SensorTagDemo.pro
@@ -0,0 +1,151 @@
+TEMPLATE = app
+
+QT += \
+ bluetooth \
+ core \
+ charts \
+ gui \
+ network \
+ qml \
+ quick \
+ widgets
+
+CONFIG += c++11
+DEFINES += QT_NO_FOREACH
+
+# Specify UI layout to use: UI_SMALL or UI_WATCH
+DEFINES += UI_SMALL
+
+# To overcome the bug QTBUG-58648, uncomment this define
+# Needed at least for RPi3 and iMX
+#CONFIG += DEPLOY_TO_FS
+
+win32|linux|android:!qnx {
+ CONFIG += BLUETOOTH_HOST
+} else {
+ message(Unsupported target platform)
+}
+
+# For using MQTT upload enable this config.
+# This enables both, host and client mode
+CONFIG += UPDATE_TO_MQTT_BROKER
+
+# For using Azure cloud connectivity enable
+# this config. This enabled both, host and
+# client mode
+# CONFIG += UPDATE_TO_AZURE
+
+win32:!contains(CONFIG, UPDATE_TO_MQTT_BROKER) {
+ WASTORAGE_PATH = $$(WASTORAGE_LOCATION)
+ isEmpty(WASTORAGE_PATH): message("Location for Azure Storage libs unknown. Please specify WASTORAGE_LOCATION")
+ CPPRESTSDK_PATH = $$(CPPRESTSDK_LOCATION)
+ isEmpty(CPPRESTSDK_PATH): message("Location for CppRest library unknown. Please specify CPPREST_LOCATION")
+
+ INCLUDEPATH += $$WASTORAGE_PATH/build/native/include \
+ $$WASTORAGE_PATH/build/native/include/was \
+ $$WASTORAGE_PATH/build/native/include/wascore \
+ $$CPPRESTSDK_PATH/build/native/include
+ LIBS += -L$$WASTORAGE_PATH/lib/native/v140/Win32/Release
+}
+
+SOURCES += main.cpp \
+ mockdataprovider.cpp \
+ sensortagdataprovider.cpp \
+ clouddataprovider.cpp \
+ dataproviderpool.cpp \
+ clouddataproviderpool.cpp \
+ seriesstorage.cpp \
+ mockdataproviderpool.cpp
+
+HEADERS += \
+ sensortagdataprovider.h \
+ mockdataprovider.h \
+ clouddataprovider.h \
+ cloudservice.h \
+ dataproviderpool.h \
+ clouddataproviderpool.h \
+ bluetoothapiconstants.h \
+ seriesstorage.h \
+ mockdataproviderpool.h
+
+BLUETOOTH_HOST {
+ DEFINES += RUNS_AS_HOST
+
+ SOURCES += \
+ sensortagdataproviderpool.cpp \
+ bluetoothdataprovider.cpp \
+ demodataproviderpool.cpp \
+ serviceinfo.cpp \
+ bluetoothdevice.cpp
+
+ HEADERS += \
+ sensortagdataproviderpool.h \
+ bluetoothdataprovider.h \
+ demodataproviderpool.h \
+ serviceinfo.h \
+ bluetoothdevice.h
+}
+
+UPDATE_TO_MQTT_BROKER {
+ CONFIG -= UPDATE_TO_AZURE
+
+ !qtHaveModule(mqtt): error("Could not find MQTT module for Qt version")
+ QT += mqtt
+ DEFINES += MQTT_UPLOAD
+
+ SOURCES += mqttupdate.cpp \
+ mqttdataproviderpool.cpp \
+ mqttdataprovider.cpp
+ HEADERS += mqttupdate.h \
+ mqttdataproviderpool.h \
+ mqttdataprovider.h
+}
+
+UPDATE_TO_AZURE {
+ SOURCES += cloudupdate.cpp
+ HEADERS += cloudupdate.h
+ DEFINES += AZURE_UPLOAD
+ # For Azure libs
+ win32 {
+ LIBS += -lwastorage
+ } else {
+ LIBS += -lboost_system -lcrypto -lssl -lcpprest -lazurestorage
+ QMAKE_CXXFLAGS += -fpermissive
+ QMAKE_CXXFLAGS += -fexceptions
+ }
+ QMAKE_CXXFLAGS_EXCEPTIONS_OFF =
+}
+
+RESOURCES += base.qrc
+
+android: ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android-sources
+
+contains(DEFINES, UI_SMALL) {
+ !DEPLOY_TO_FS: RESOURCES += uismall.qrc
+ uiVariant.files = resources/small
+} else:contains(DEFINES, UI_WATCH) {
+ !DEPLOY_TO_FS: RESOURCES += uiwatch.qrc
+ uiVariant.files = resources/watch
+} else: error("No layout specified")
+
+uiVariant.path = /opt/$${TARGET}/resources
+
+# Additional import path used to resolve QML modules in Qt Creator's code model
+QML_IMPORT_PATH =
+
+# Default rules for deployment.
+qnx: target.path = /tmp/$${TARGET}/bin
+else: unix:!android: target.path = /opt/$${TARGET}
+!isEmpty(target.path): INSTALLS += target
+
+DISTFILES += \
+ android-sources/AndroidManifest.xml
+
+DEPLOY_TO_FS {
+ message("Files will be deployed to the file system")
+ DEFINES += DEPLOY_TO_FS
+
+ baseFiles.files = resources/base
+ baseFiles.path = /opt/$${TARGET}/resources
+ INSTALLS += baseFiles uiVariant
+}
diff --git a/tradeshow/iot-sensortag/android-sources/AndroidManifest.xml b/tradeshow/iot-sensortag/android-sources/AndroidManifest.xml
new file mode 100644
index 0000000..a40a59c
--- /dev/null
+++ b/tradeshow/iot-sensortag/android-sources/AndroidManifest.xml
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tradeshow/iot-sensortag/base.qrc b/tradeshow/iot-sensortag/base.qrc
new file mode 100644
index 0000000..db038ef
--- /dev/null
+++ b/tradeshow/iot-sensortag/base.qrc
@@ -0,0 +1,26 @@
+
+
+ resources/base/BaseChart.qml
+ resources/base/ChartPage.qml
+ resources/base/HumidityChart.qml
+ resources/base/LightChart.qml
+ resources/base/LocationPage.qml
+ resources/base/MagnetometerChart.qml
+ resources/base/main.qml
+ resources/base/ObjectTemperatureChart.qml
+ resources/base/TemperatureChart.qml
+ resources/base/TopToolbar.qml
+ resources/base/CircularGauge.qml
+ resources/base/GyroChart.qml
+ resources/base/AccelChart.qml
+ resources/base/SensorSettings.qml
+ resources/base/CloudSettings.qml
+ resources/base/fonts/titilliumweb/TitilliumWeb-Bold.ttf
+ resources/base/fonts/titilliumweb/TitilliumWeb-Regular.ttf
+ resources/base/fonts/titilliumweb/TitilliumWeb-SemiBold.ttf
+ resources/base/images/bg_blue.jpg
+ resources/base/RotationPage.qml
+ resources/base/AltitudeChart.qml
+ resources/base/BlinkingIcon.qml
+
+
diff --git a/tradeshow/iot-sensortag/bluetoothapiconstants.h b/tradeshow/iot-sensortag/bluetoothapiconstants.h
new file mode 100644
index 0000000..8e0672a
--- /dev/null
+++ b/tradeshow/iot-sensortag/bluetoothapiconstants.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qt for Device Creation.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef BLUETOOTHAPICONSTANTS_H
+#define BLUETOOTHAPICONSTANTS_H
+
+// NOTE! This file should only contain defines, no implementation
+
+// These service UUIDs come from the Texas Intruments SensorTag Bluetooth LE API specification
+#define IRTEMPERATURESENSOR_SERVICE_UUID "f000aa00-0451-4000-b000-000000000000"
+#define BAROMETER_SERVICE_UUID "f000aa40-0451-4000-b000-000000000000"
+#define HUMIDITYSENSOR_SERVICE_UUID "f000aa20-0451-4000-b000-000000000000"
+#define LIGHTSENSOR_SERVICE_UUID "f000aa70-0451-4000-b000-000000000000"
+#define MOTIONSENSOR_SERVICE_UUID "f000aa80-0451-4000-b000-000000000000"
+
+/* Timeouts (values between 100ms and 2500ms allowed by API specification.
+ * API values are passed in hex as strings and multiplied by 10 in SensorTag.
+ * These values can be modifed as needed by performance.
+ * Keep defines and strings in sync!
+ */
+#define SENSORTAG_SLOW_TIMER_TIMEOUT_MS 1000 /* 1 second */
+#define SENSORTAG_SLOW_TIMER_TIMEOUT_STR "64" /* 64hex -> 100 -> 1000ms */
+#define SENSORTAG_MEDIUM_TIMER_TIMEOUT_MS 500 /* 500ms */
+#define SENSORTAG_MEDIUM_TIMER_TIMEOUT_STR "32" /* 32hex -> 50 -> 500ms */
+#define SENSORTAG_RAPID_TIMER_TIMEOUT_MS 100 /* 100ms */
+#define SENSORTAG_RAPID_TIMER_TIMEOUT_STR "0A" /* A(hex) -> 10 -> 100ms */
+
+// These modifiers come from the Texas Intruments SensorTag Bluetooth LE API specification
+#define GYROSCOPE_API_READING_MULTIPLIER (500.0 / 65536.0)
+#define ACCELOMETER_API_READING_MULTIPLIER (8.0 / 32768.0)
+#define HUMIDITY_API_READING_MULTIPLIER (100.0 / 65536.0)
+#define IR_TEMPERATURE_API_READING_DIVIDER 128.0
+#define BAROMETER_API_READING_DIVIDER 100
+
+// These are parameters from the Texas Intruments SensorTag Bluetooth LE API specification
+#define START_MEASUREMENT_STR "01" /* 01 start, 00 stop */
+#define DISABLE_NOTIF_STR "0000" /* 0100 enable, 0000 disable */
+#define ENABLE_NOTIF_STR "0100" /* 0100 enable, 0000 disable */
+#define MOVEMENT_ENABLE_SENSORS_BITMASK_VALUE "7F02" /* see below */
+//Enable motion axis: 0b0000_0010_0111_1111 = 0x7F 0x02 (all sensors, 8G, no wake on motion)
+//bits of first byte:
+//MPU9250_GYROSCOPE = 0b0000_0111 all 3 xyz axes, 1 bit per axis
+//MPU9250_ACCELEROMETER = 0b0011_1000 all 3 xyz axes, 1 bit per axis
+//MPU9250_MAGNETOMETER = 0b0100_0000 all 3 xyz axes with one bit
+//MPU9250_WAKEONMOTION = 0b1000_0000 enables wake on motion
+//bits of second byte (only 2 bits used) Accelerometer range in G
+//MPU9250_ACCELEROMETER_RANGE_0 =0b0000_0000 = 2 G
+//MPU9250_ACCELEROMETER_RANGE_1 =0b0000_0001 = 4 G
+//MPU9250_ACCELEROMETER_RANGE_2 =0b0000_0010 = 8 G (default)
+//MPU9250_ACCELEROMETER_RANGE_3 =0b0000_0011 = 16 G
+
+#endif // BLUETOOTHAPICONSTANTS_H
diff --git a/tradeshow/iot-sensortag/bluetoothdataprovider.cpp b/tradeshow/iot-sensortag/bluetoothdataprovider.cpp
new file mode 100644
index 0000000..3c81d92
--- /dev/null
+++ b/tradeshow/iot-sensortag/bluetoothdataprovider.cpp
@@ -0,0 +1,298 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qt for Device Creation.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "bluetoothdataprovider.h"
+#include
+#include "bluetoothapiconstants.h"
+
+Q_DECLARE_LOGGING_CATEGORY(boot2QtDemos)
+
+#define SAMPLE_COUNT_FOR_ZERO_ALTITUDE 10
+
+BluetoothDataProvider::BluetoothDataProvider(const QBluetoothDeviceInfo &id, QObject *parent)
+ : SensorTagDataProvider(id.address().toString(), parent)
+ , m_info(id)
+ , m_btDevice(nullptr)
+ , m_smaSamples(0)
+ , m_zeroAltitudeSamples(0)
+ , gyroscopeX_calibration(0)
+ , gyroscopeY_calibration(0)
+ , gyroscopeZ_calibration(0)
+{
+ m_state = NotFound;
+ intervalRotation = SENSORTAG_RAPID_TIMER_TIMEOUT_MS;
+}
+
+BluetoothDataProvider::~BluetoothDataProvider()
+{
+ if (m_btDevice)
+ delete m_btDevice;
+}
+
+bool BluetoothDataProvider::startDataFetching()
+{
+ qCDebug(boot2QtDemos) << Q_FUNC_INFO << " :" << m_btDevice;
+
+ m_btDevice = new BluetoothDevice(m_info);
+
+ connect(m_btDevice, &BluetoothDevice::statusUpdated, this, [=](const QString& statusMsg) {
+ qCDebug(boot2QtDemos) << id() << "----------" << statusMsg;
+ });
+ connect(m_btDevice, &BluetoothDevice::stateChanged,
+ this, &BluetoothDataProvider::updateState);
+ connect(m_btDevice, &BluetoothDevice::temperatureChanged,
+ this, &BluetoothDataProvider::temperatureReceived);
+ connect(m_btDevice, &BluetoothDevice::barometerChanged,
+ this, &BluetoothDataProvider::barometerReceived);
+ connect(m_btDevice, &BluetoothDevice::humidityChanged,
+ this, &BluetoothDataProvider::humidityReceived);
+ connect(m_btDevice, &BluetoothDevice::lightIntensityChanged,
+ this, &BluetoothDataProvider::lightIntensityReceived);
+ connect(m_btDevice, &BluetoothDevice::motionChanged,
+ this, &BluetoothDataProvider::motionReceived);
+ startServiceScan();
+
+ return true;
+}
+
+void BluetoothDataProvider::endDataFetching()
+{
+ // BluetoothDevice is not capable of restarting
+ qCDebug(boot2QtDemos) << Q_FUNC_INFO << " :" << m_btDevice;
+ m_btDevice->disconnectFromDevice();
+ setState(Scanning);
+
+ m_btDevice->deleteLater();
+ m_btDevice = nullptr;
+}
+
+void BluetoothDataProvider::startServiceScan()
+{
+ qCDebug(boot2QtDemos) << Q_FUNC_INFO << m_btDevice;
+ if (m_btDevice) {
+ setState(Scanning);
+ m_btDevice->scanServices();
+ }
+}
+
+void BluetoothDataProvider::temperatureReceived(double newAmbientTemperature,
+ double newObjectTemperature)
+{
+ /* NOTE: We emit the signals even if value is unchanged.
+ * Otherwise the scrolling graphs in UI will not scroll.
+ */
+ irAmbientTemperature = newAmbientTemperature;
+ emit infraredAmbientTemperatureChanged();
+ irObjectTemperature = newObjectTemperature;
+ emit infraredObjectTemperatureChanged();
+}
+
+void BluetoothDataProvider::barometerReceived(double temperature, double barometer)
+{
+ /* NOTE: We emit the signals even if value is unchanged.
+ * Otherwise the scrolling graphs in UI will not scroll.
+ */
+ barometerCelsiusTemperature = temperature;
+ emit barometerCelsiusTemperatureChanged();
+ barometerTemperatureAverage = (temperature + m_smaSamples * barometerTemperatureAverage)
+ / (m_smaSamples + 1);
+ m_smaSamples++;
+ emit barometerCelsiusTemperatureAverageChanged();
+ // Use a limited number of samples. It will eventually give wrong avg values,
+ // but this is just a demo...
+ if (m_smaSamples > 10000)
+ m_smaSamples = 0;
+ barometerHPa = barometer;
+ emit barometer_hPaChanged();
+
+ recalibrateZeroAltitude();
+ calculateZeroAltitude();
+}
+
+void BluetoothDataProvider::humidityReceived(double humidity)
+{
+ /* NOTE: We emit the signals even if value is unchanged.
+ * Otherwise the scrolling graphs in UI will not scroll.
+ */
+ this->humidity = humidity;
+ emit relativeHumidityChanged();
+}
+void BluetoothDataProvider::lightIntensityReceived(double lightIntensity)
+{
+ /* NOTE: We emit the signals even if value is unchanged.
+ * Otherwise the scrolling graphs in UI will not scroll.
+ */
+ lightIntensityLux = lightIntensity;
+ emit lightIntensityChanged();
+}
+
+float BluetoothDataProvider::countRotationDegrees(double degreesPerSecond, quint64 milliseconds)
+{
+ const quint32 mseconds = milliseconds;
+ const float seconds = ((float)mseconds)/float(1000);
+ return ((float)degreesPerSecond) * seconds;
+}
+
+void BluetoothDataProvider::motionReceived(const MotionSensorData &data)
+{
+ /* NOTE: We emit the signals even if value is unchanged.
+ * Otherwise the scrolling graphs in UI will not scroll.
+ */
+ latestData = data;
+ gyroscopeX_degPerSec = data.gyroScope_x - gyroscopeX_calibration;
+ gyroscopeY_degPerSec = data.gyroScope_y - gyroscopeY_calibration;
+ gyroscopeZ_degPerSec = data.gyroScope_z - gyroscopeZ_calibration;
+ emit gyroscopeDegPerSecChanged();
+
+ rotation_x += countRotationDegrees(gyroscopeX_degPerSec, data.msSincePreviousData);
+ rotation_y += countRotationDegrees(gyroscopeY_degPerSec, data.msSincePreviousData);
+ rotation_z += countRotationDegrees(gyroscopeZ_degPerSec, data.msSincePreviousData);
+
+ if (rotation_x > 360)
+ rotation_x -= 360;
+ else if (rotation_x < 0)
+ rotation_x += 360;
+ if (rotation_y > 360)
+ rotation_y -= 360;
+ else if (rotation_y < 0)
+ rotation_y += 360;
+ if (rotation_z > 360)
+ rotation_z -= 360;
+ else if (rotation_z < 0)
+ rotation_z += 360;
+ emit rotationXChanged();
+ emit rotationYChanged();
+ emit rotationZChanged();
+ accelometerX = data.accelometer_x;
+ accelometerY = data.accelometer_y;
+ accelometerZ = data.accelometer_z;
+ emit accelometerChanged();
+ magnetometerMicroT_xAxis = data.magnetometer_x;
+ magnetometerMicroT_yAxis = data.magnetometer_y;
+ magnetometerMicroT_zAxis = data.magnetometer_z;
+ emit magnetometerMicroTChanged();
+ // Signal that all values have changed, for easier
+ // value change handling in clients
+ emit rotationValuesChanged();
+}
+
+QString BluetoothDataProvider::sensorType() const
+{
+ return QString("Bluetooth data");
+}
+
+QString BluetoothDataProvider::versionString() const
+{
+ return QString("1.1");
+}
+
+void BluetoothDataProvider::updateState()
+{
+ if (!m_btDevice)
+ return;
+
+ switch (m_btDevice->state()) {
+ case BluetoothDevice::Disconnected:
+ break;
+ case BluetoothDevice::Scanning:
+ setState(Scanning);
+ break;
+ case BluetoothDevice::Connected:
+ setState(Connected);
+ break;
+ case BluetoothDevice::Error:
+ setState(Error);
+ break;
+ default:
+ break;
+ }
+}
+
+void BluetoothDataProvider::reset()
+{
+ qCDebug(boot2QtDemos) << "Reset bluetooth data provider";
+
+ rotation_x = 0;
+ rotation_y = 0;
+ rotation_z = 0;
+ gyroscopeX_calibration = latestData.gyroScope_x;
+ gyroscopeY_calibration = latestData.gyroScope_y;
+ gyroscopeZ_calibration = latestData.gyroScope_z;
+ emit rotationXChanged();
+ emit rotationYChanged();
+ emit rotationZChanged();
+
+ // Forces recalculation of zero altitude
+ m_zeroAltitudeSamples = 0;
+ pressureAtZeroAltitude = 0;
+}
+
+void BluetoothDataProvider::recalibrateZeroAltitude()
+{
+ if (m_zeroAltitudeSamples < SAMPLE_COUNT_FOR_ZERO_ALTITUDE) {
+ pressureAtZeroAltitude = (barometerHPa
+ + m_zeroAltitudeSamples * pressureAtZeroAltitude)
+ / (m_zeroAltitudeSamples + 1);
+ m_zeroAltitudeSamples++;
+ }
+}
+
+void BluetoothDataProvider::unbindDevice()
+{
+ if (m_btDevice) {
+ delete m_btDevice;
+ m_btDevice = 0;
+ setState(NotFound);
+ }
+}
+
+BluetoothDevice *BluetoothDataProvider::device()
+{
+ return m_btDevice;
+}
diff --git a/tradeshow/iot-sensortag/bluetoothdataprovider.h b/tradeshow/iot-sensortag/bluetoothdataprovider.h
new file mode 100644
index 0000000..5c28725
--- /dev/null
+++ b/tradeshow/iot-sensortag/bluetoothdataprovider.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qt for Device Creation.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef BLUETOOTHDATAPROVIDER_H
+#define BLUETOOTHDATAPROVIDER_H
+
+#include "sensortagdataprovider.h"
+#include "sensortagdataproviderpool.h"
+#include
+#include
+#include
+#include
+
+class BluetoothDataProvider : public SensorTagDataProvider
+{
+ Q_OBJECT
+public:
+ BluetoothDataProvider(const QBluetoothDeviceInfo &id, QObject *parent = 0);
+
+ virtual ~BluetoothDataProvider();
+
+ bool startDataFetching() override;
+ void endDataFetching() override;
+ QString sensorType() const;
+ QString versionString() const;
+
+ void unbindDevice();
+ BluetoothDevice *device();
+
+public slots:
+ void startServiceScan();
+
+ void temperatureReceived(double newAmbientTemperature, double newObjectTemperature);
+ void barometerReceived(double temperature, double barometer);
+ void humidityReceived(double humidity);
+ void lightIntensityReceived(double lightIntensity);
+ void motionReceived(const MotionSensorData &data);
+
+protected:
+ void reset() override;
+ virtual void recalibrateZeroAltitude();
+
+private:
+ void updateState();
+ float countRotationDegrees(double degreesPerSecond, quint64 milliseconds);
+ QBluetoothDeviceInfo m_info;
+ BluetoothDevice *m_btDevice;
+ int m_smaSamples;
+ int m_zeroAltitudeSamples;
+ float gyroscopeX_calibration;
+ float gyroscopeY_calibration;
+ float gyroscopeZ_calibration;
+ MotionSensorData latestData;
+};
+
+#endif // BLUETOOTHDATAPROVIDER_H
diff --git a/tradeshow/iot-sensortag/bluetoothdevice.cpp b/tradeshow/iot-sensortag/bluetoothdevice.cpp
new file mode 100644
index 0000000..2ede116
--- /dev/null
+++ b/tradeshow/iot-sensortag/bluetoothdevice.cpp
@@ -0,0 +1,639 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qt for Device Creation.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "bluetoothdevice.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "bluetoothapiconstants.h"
+
+Q_DECLARE_LOGGING_CATEGORY(boot2QtDemos)
+
+typedef struct {
+ qint16 gyrox;
+ qint16 gyroy;
+ qint16 gyroz;
+ qint16 accelx;
+ qint16 accely;
+ qint16 accelz;
+ qint16 magnetomx;
+ qint16 magnetomy;
+ qint16 magnetomz;
+} movement_data_t;
+
+BluetoothDevice::BluetoothDevice()
+ : m_controller(0)
+ , m_irTemperatureService(0)
+ , m_baroService(0)
+ , m_humidityService(0)
+ , m_lightService(0)
+ , m_motionService(0)
+ , m_deviceState(DeviceState::Disconnected)
+ , m_temperatureMeasurementStarted(false)
+ , m_barometerMeasurementStarted(false)
+ , m_humidityMeasurementStarted(false)
+ , m_lightIntensityMeasurementStarted(false)
+ , m_motionMeasurementStarted(false)
+{
+ m_lastMilliseconds = QDateTime::currentMSecsSinceEpoch();
+ statusUpdated("Device created");
+
+ m_serviceDetailsTimer = new QTimer(this);
+ m_serviceDetailsTimer->setInterval(5000);
+ m_serviceDetailsTimer->setSingleShot(true);
+ connect(m_serviceDetailsTimer, &QTimer::timeout, [=]() {
+ qCDebug(boot2QtDemos) << "Service details timer timeout. No more services details found";
+ if (isDeviceReady())
+ setState(Connected);
+ else
+ setState(Disconnected);
+ });
+}
+
+BluetoothDevice::BluetoothDevice(const QBluetoothDeviceInfo &d)
+ : BluetoothDevice()
+{
+ m_deviceInfo = d;
+}
+
+BluetoothDevice::~BluetoothDevice()
+{
+ if (m_controller) {
+ m_controller->disconnect();
+ delete m_controller;
+ }
+}
+
+QString BluetoothDevice::getAddress() const
+{
+#if defined(Q_OS_DARWIN)
+ // On Apple platforms we do not have addresses,
+ // only unique UUIDs generated by Core Bluetooth.
+ return m_deviceInfo.deviceUuid().toString();
+#else
+ return m_deviceInfo.address().toString();
+#endif
+}
+
+QString BluetoothDevice::getName() const
+{
+ return m_deviceInfo.name();
+}
+
+void BluetoothDevice::scanServices()
+{
+ setState(Scanning);
+ if (!m_controller) {
+ statusUpdated("(Connecting to device...)");
+ // Connecting signals and slots for connecting to LE services.
+ m_controller = new QLowEnergyController(m_deviceInfo);
+ connect(m_controller, &QLowEnergyController::connected,
+ this, &BluetoothDevice::deviceConnected);
+ connect(m_controller, QOverload::of(&QLowEnergyController::error),
+ this, &BluetoothDevice::errorReceived);
+ connect(m_controller, &QLowEnergyController::disconnected,
+ this, &BluetoothDevice::deviceDisconnected);
+ connect(m_controller, &QLowEnergyController::serviceDiscovered,
+ this, &BluetoothDevice::addLowEnergyService);
+ connect(m_controller, &QLowEnergyController::discoveryFinished,
+ this, &BluetoothDevice::serviceScanDone);
+
+ m_controller->setRemoteAddressType(QLowEnergyController::PublicAddress);
+ }
+ m_controller->connectToDevice();
+}
+
+void BluetoothDevice::addLowEnergyService(const QBluetoothUuid &serviceUuid)
+{
+ if (serviceUuid == QBluetoothUuid(QLatin1String(IRTEMPERATURESENSOR_SERVICE_UUID))) {
+ qCDebug(boot2QtDemos) << "Found infrared temperature service.";
+ m_irTemperatureService = m_controller->createServiceObject(serviceUuid);
+ if (!m_irTemperatureService) {
+ qWarning() << "Could not create infrared temperature service object.";
+ return;
+ }
+ connect(m_irTemperatureService, &QLowEnergyService::stateChanged,
+ this, &BluetoothDevice::temperatureDetailsDiscovered);
+ connect(m_irTemperatureService, &QLowEnergyService::characteristicChanged,
+ this, &BluetoothDevice::updateTemperature);
+ m_irTemperatureService->discoverDetails();
+ } else if (serviceUuid == QBluetoothUuid(QLatin1String(BAROMETER_SERVICE_UUID))) {
+ qCDebug(boot2QtDemos) << "Found barometer service.";
+ m_baroService = m_controller->createServiceObject(serviceUuid);
+ if (!m_baroService) {
+ qWarning() << "Could not create barometer service object.";
+ return;
+ }
+ connect(m_baroService, &QLowEnergyService::stateChanged,
+ this, &BluetoothDevice::barometerDetailsDiscovered);
+ connect(m_baroService, &QLowEnergyService::characteristicChanged,
+ this, &BluetoothDevice::updatePressure);
+ m_baroService->discoverDetails();
+ } else if (serviceUuid == QBluetoothUuid(QLatin1String(HUMIDITYSENSOR_SERVICE_UUID))) {
+ qCDebug(boot2QtDemos) << "Found humidity service.";
+ m_humidityService = m_controller->createServiceObject(serviceUuid);
+ if (!m_humidityService) {
+ qWarning() << "Could not create humidity service object.";
+ return;
+ }
+ connect(m_humidityService, &QLowEnergyService::stateChanged,
+ this, &BluetoothDevice::humidityDetailsDiscovered);
+ connect(m_humidityService, &QLowEnergyService::characteristicChanged,
+ this, &BluetoothDevice::updateHumidity);
+ m_humidityService->discoverDetails();
+ } else if (serviceUuid == QBluetoothUuid(QLatin1String(LIGHTSENSOR_SERVICE_UUID))) {
+ qCDebug(boot2QtDemos) << "Found light service.";
+ m_lightService = m_controller->createServiceObject(serviceUuid);
+ if (!m_lightService) {
+ qWarning() << "Could not create light service object.";
+ return;
+ }
+ connect(m_lightService, &QLowEnergyService::stateChanged,
+ this, &BluetoothDevice::lightIntensityDetailsDiscovered);
+ connect(m_lightService, &QLowEnergyService::characteristicChanged,
+ this, &BluetoothDevice::updateLight);
+ m_lightService->discoverDetails();
+ } else if (serviceUuid == QBluetoothUuid(QLatin1String(MOTIONSENSOR_SERVICE_UUID))) {
+ qCDebug(boot2QtDemos) << "Found motion service.";
+ m_motionService = m_controller->createServiceObject(serviceUuid);
+ if (!m_motionService) {
+ qWarning() << "Could not create motion service object.";
+ return;
+ }
+ connect(m_motionService, &QLowEnergyService::stateChanged,
+ this, &BluetoothDevice::motionDetailsDiscovered);
+ connect(m_motionService, &QLowEnergyService::characteristicChanged,
+ this, &BluetoothDevice::updateMotionValue);
+ m_motionService->discoverDetails();
+ } else {
+ qCDebug(boot2QtDemos) << "Found unhandled service with id" << serviceUuid << ".";
+ }
+}
+
+void BluetoothDevice::serviceScanDone()
+{
+ statusUpdated("(Service scan done!)");
+ qCDebug(boot2QtDemos) << "ServiceScan done.";
+ if (!m_irTemperatureService)
+ qCDebug(boot2QtDemos) << "Infrared temperature service not found.";
+
+ if (!m_baroService)
+ qCDebug(boot2QtDemos) << "Barometer service not found.";
+
+ if (!m_humidityService)
+ qCDebug(boot2QtDemos) << "Humidity service not found.";
+
+ if (!m_lightService)
+ qCDebug(boot2QtDemos) << "Light service not found.";
+
+ if (!m_motionService)
+ qCDebug(boot2QtDemos) << "Motion service not found.";
+
+ m_serviceDetailsTimer->start();
+}
+
+void BluetoothDevice::temperatureDetailsDiscovered(QLowEnergyService::ServiceState newstate)
+{
+ if (newstate == QLowEnergyService::ServiceDiscovered) {
+ connect(m_irTemperatureService, &QLowEnergyService::characteristicWritten, [=]() {
+ qCDebug(boot2QtDemos) << "Wrote Characteristic - temperature";
+ });
+
+ connect(m_irTemperatureService, QOverload::of(&QLowEnergyService::error),
+ [=](QLowEnergyService::ServiceError newError) {
+ qCDebug(boot2QtDemos) << "error while writing - temperature:" << newError;
+ });
+
+ // data characteristic
+ QLowEnergyCharacteristic characteristic = m_irTemperatureService->characteristic(
+ QBluetoothUuid(QLatin1String("f000aa01-0451-4000-b000-000000000000")));
+ if (characteristic.isValid()) {
+ const QLowEnergyDescriptor notificationDescriptor = characteristic.descriptor(
+ QBluetoothUuid::ClientCharacteristicConfiguration);
+ if (notificationDescriptor.isValid())
+ m_irTemperatureService->writeDescriptor(notificationDescriptor, QByteArray::fromHex(ENABLE_NOTIF_STR));
+ }
+
+ // configuration characteristic
+ characteristic = m_irTemperatureService->characteristic(
+ QBluetoothUuid(QLatin1String("f000aa02-0451-4000-b000-000000000000")));
+ if (characteristic.isValid())
+ m_irTemperatureService->writeCharacteristic(characteristic, QByteArray::fromHex(START_MEASUREMENT_STR), QLowEnergyService::WriteWithResponse);
+
+ // timeout characteristic
+ characteristic = m_irTemperatureService->characteristic(
+ QBluetoothUuid(QLatin1String("f000aa03-0451-4000-b000-000000000000")));
+ if (characteristic.isValid()) {
+ m_irTemperatureService->writeCharacteristic(characteristic, QByteArray::fromHex(SENSORTAG_SLOW_TIMER_TIMEOUT_STR), QLowEnergyService::WriteWithResponse); // Period 1 second
+ }
+
+ m_temperatureMeasurementStarted = true;
+ updateServiceDetails();
+ }
+}
+
+void BluetoothDevice::barometerDetailsDiscovered(QLowEnergyService::ServiceState newstate) {
+ if (newstate == QLowEnergyService::ServiceDiscovered) {
+ connect(m_baroService, &QLowEnergyService::characteristicWritten, [=]() {
+ qCDebug(boot2QtDemos) << "Wrote Characteristic - barometer";
+ });
+
+ connect(m_baroService, QOverload::of(&QLowEnergyService::error),
+ [=](QLowEnergyService::ServiceError newError) {
+ qCDebug(boot2QtDemos) << "error while writing - barometer:" << newError;
+ });
+
+ // data characteristic
+ QLowEnergyCharacteristic characteristic = m_baroService->characteristic(
+ QBluetoothUuid(QLatin1String("f000aa41-0451-4000-b000-000000000000")));
+ if (characteristic.isValid()) {
+ const QLowEnergyDescriptor notificationDescriptor = characteristic.descriptor(
+ QBluetoothUuid::ClientCharacteristicConfiguration);
+ if (notificationDescriptor.isValid())
+ m_baroService->writeDescriptor(notificationDescriptor, QByteArray::fromHex(ENABLE_NOTIF_STR));
+ }
+
+ // configuration characteristic
+ characteristic = m_baroService->characteristic(
+ QBluetoothUuid(QLatin1String("f000aa42-0451-4000-b000-000000000000")));
+ if (characteristic.isValid())
+ m_baroService->writeCharacteristic(characteristic, QByteArray::fromHex(START_MEASUREMENT_STR), QLowEnergyService::WriteWithResponse);
+
+ // timeout characteristic
+ characteristic = m_baroService->characteristic(
+ QBluetoothUuid(QLatin1String("f000aa44-0451-4000-b000-000000000000")));
+ if (characteristic.isValid()) {
+ m_baroService->writeCharacteristic(characteristic, QByteArray::fromHex(SENSORTAG_MEDIUM_TIMER_TIMEOUT_STR), QLowEnergyService::WriteWithResponse); // Period 500 ms
+ }
+
+ m_barometerMeasurementStarted = true;
+ updateServiceDetails();
+ }
+}
+
+void BluetoothDevice::humidityDetailsDiscovered(QLowEnergyService::ServiceState newstate)
+{
+ if (newstate == QLowEnergyService::ServiceDiscovered) {
+ connect(m_humidityService, &QLowEnergyService::characteristicWritten, [=]() {
+ qCDebug(boot2QtDemos) << "Wrote Characteristic - humidity";
+ });
+
+ connect(m_humidityService, QOverload::of(&QLowEnergyService::error),
+ [=](QLowEnergyService::ServiceError newError) {
+ qCDebug(boot2QtDemos) << "error while writing - humidity:" << newError;
+ });
+
+ // data characteristic
+ QLowEnergyCharacteristic characteristic = m_humidityService->characteristic(
+ QBluetoothUuid(QLatin1String("f000aa21-0451-4000-b000-000000000000")));
+ if (characteristic.isValid()) {
+ const QLowEnergyDescriptor notificationDescriptor = characteristic.descriptor(
+ QBluetoothUuid::ClientCharacteristicConfiguration);
+ if (notificationDescriptor.isValid())
+ m_humidityService->writeDescriptor(notificationDescriptor, QByteArray::fromHex(ENABLE_NOTIF_STR));
+ }
+
+ // configuration characteristic
+ characteristic = m_humidityService->characteristic(
+ QBluetoothUuid(QLatin1String("f000aa22-0451-4000-b000-000000000000")));
+ if (characteristic.isValid())
+ m_humidityService->writeCharacteristic(characteristic, QByteArray::fromHex(START_MEASUREMENT_STR), QLowEnergyService::WriteWithResponse);
+
+ // timeout characteristic
+ characteristic = m_humidityService->characteristic(
+ QBluetoothUuid(QLatin1String("f000aa23-0451-4000-b000-000000000000")));
+ if (characteristic.isValid()) {
+ m_humidityService->writeCharacteristic(characteristic, QByteArray::fromHex(SENSORTAG_SLOW_TIMER_TIMEOUT_STR), QLowEnergyService::WriteWithResponse); // Period 500 ms
+ }
+
+ m_humidityMeasurementStarted = true;
+ updateServiceDetails();
+ }
+}
+
+void BluetoothDevice::lightIntensityDetailsDiscovered(QLowEnergyService::ServiceState newstate)
+{
+ if (newstate == QLowEnergyService::ServiceDiscovered) {
+ connect(m_lightService, &QLowEnergyService::characteristicWritten, [=]() {
+ qCDebug(boot2QtDemos) << "Wrote Characteristic - light intensity";
+ });
+
+ connect(m_lightService, QOverload::of(&QLowEnergyService::error),
+ [=](QLowEnergyService::ServiceError newError) {
+ qCDebug(boot2QtDemos) << "error while writing - light intensity:" << newError;
+ });
+
+ // data characteristic
+ QLowEnergyCharacteristic characteristic = m_lightService->characteristic(
+ QBluetoothUuid(QLatin1String("f000aa71-0451-4000-b000-000000000000")));
+ if (characteristic.isValid()) {
+ const QLowEnergyDescriptor notificationDescriptor = characteristic.descriptor(
+ QBluetoothUuid::ClientCharacteristicConfiguration);
+ if (notificationDescriptor.isValid())
+ m_lightService->writeDescriptor(notificationDescriptor, QByteArray::fromHex(ENABLE_NOTIF_STR));
+ }
+
+ // configuration characteristic
+ characteristic = m_lightService->characteristic(
+ QBluetoothUuid(QLatin1String("f000aa72-0451-4000-b000-000000000000")));
+ if (characteristic.isValid())
+ m_lightService->writeCharacteristic(characteristic, QByteArray::fromHex(START_MEASUREMENT_STR), QLowEnergyService::WriteWithResponse);
+
+ // timeout characteristic
+ characteristic = m_lightService->characteristic(
+ QBluetoothUuid(QLatin1String("f000aa73-0451-4000-b000-000000000000")));
+ if (characteristic.isValid()) {
+ m_lightService->writeCharacteristic(characteristic, QByteArray::fromHex(SENSORTAG_MEDIUM_TIMER_TIMEOUT_STR), QLowEnergyService::WriteWithResponse); // Period 500 ms
+ }
+
+ m_lightIntensityMeasurementStarted = true;
+ updateServiceDetails();
+ }
+}
+
+void BluetoothDevice::motionDetailsDiscovered(QLowEnergyService::ServiceState newstate)
+{
+ // reset the time once more before we start to receive measurements.
+ m_lastMilliseconds = QDateTime::currentMSecsSinceEpoch();
+
+ if (newstate == QLowEnergyService::ServiceDiscovered) {
+ connect(m_motionService, &QLowEnergyService::characteristicWritten, [=]() {
+ qCDebug(boot2QtDemos) << "Wrote Characteristic - gyro";
+ });
+
+ connect(m_motionService, QOverload::of(&QLowEnergyService::error),
+ [=](QLowEnergyService::ServiceError newError) {
+ qCDebug(boot2QtDemos) << "error while writing - gyro:" << newError;
+ });
+
+ // data characteristic
+ QLowEnergyCharacteristic characteristic = m_motionService->characteristic(
+ QBluetoothUuid(QLatin1String("f000aa81-0451-4000-b000-000000000000")));
+ if (characteristic.isValid()) {
+ const QLowEnergyDescriptor notificationDescriptor = characteristic.descriptor(
+ QBluetoothUuid::ClientCharacteristicConfiguration);
+ if (notificationDescriptor.isValid())
+ m_motionService->writeDescriptor(notificationDescriptor, QByteArray::fromHex(ENABLE_NOTIF_STR));
+ }
+
+ // configuration characteristic
+ characteristic = m_motionService->characteristic(
+ QBluetoothUuid(QLatin1String("f000aa82-0451-4000-b000-000000000000")));
+ if (characteristic.isValid())
+ m_motionService->writeCharacteristic(characteristic, QByteArray::fromHex(MOVEMENT_ENABLE_SENSORS_BITMASK_VALUE), QLowEnergyService::WriteWithResponse);
+
+ // timeout characteristic
+ characteristic = m_motionService->characteristic(
+ QBluetoothUuid(QLatin1String("f000aa83-0451-4000-b000-000000000000")));
+ if (characteristic.isValid()) {
+ m_motionService->writeCharacteristic(characteristic, QByteArray::fromHex(SENSORTAG_RAPID_TIMER_TIMEOUT_STR), QLowEnergyService::WriteWithResponse);
+ }
+ m_motionMeasurementStarted = true;
+ updateServiceDetails();
+ }
+}
+
+void BluetoothDevice::updateTemperature(const QLowEnergyCharacteristic &, const QByteArray &value)
+{
+ irTemperatureReceived(value);
+}
+
+void BluetoothDevice::updatePressure(const QLowEnergyCharacteristic &, const QByteArray &value)
+{
+ barometerReceived(value);
+}
+
+void BluetoothDevice::updateHumidity(const QLowEnergyCharacteristic &, const QByteArray &value)
+{
+ humidityReceived(value);
+}
+
+void BluetoothDevice::updateLight(const QLowEnergyCharacteristic &, const QByteArray &value)
+{
+ lightIntensityReceived(value);
+}
+
+void BluetoothDevice::updateMotionValue(const QLowEnergyCharacteristic &, const QByteArray &value)
+{
+ motionReceived(value);
+}
+
+void BluetoothDevice::setState(BluetoothDevice::DeviceState state)
+{
+ if (m_deviceState != state) {
+ m_deviceState = state;
+ emit stateChanged();
+ }
+}
+
+double BluetoothDevice::convertIrTemperatureAPIReadingToCelsius(quint16 rawReading)
+{
+ // Compute and filter final value according to TI Bluetooth LE API
+ const float SCALE_LSB = 0.03125;
+ int it = (int)((rawReading) >> 2);
+ float t = (float)it;
+ return t * SCALE_LSB;
+}
+
+bool BluetoothDevice::isDeviceReady() const
+{
+ if (m_temperatureMeasurementStarted
+ || m_barometerMeasurementStarted
+ || m_humidityMeasurementStarted
+ || m_lightIntensityMeasurementStarted
+ || m_motionMeasurementStarted) {
+ return true;
+ }
+ return false;
+}
+
+void BluetoothDevice::updateServiceDetails()
+{
+ if (m_temperatureMeasurementStarted
+ && m_barometerMeasurementStarted
+ && m_humidityMeasurementStarted
+ && m_lightIntensityMeasurementStarted
+ && m_motionMeasurementStarted) {
+ qCDebug(boot2QtDemos) << "Service details timer stop. All service details found";
+ m_serviceDetailsTimer->stop();
+ setState(Connected);
+ } else {
+ m_serviceDetailsTimer->start();
+ }
+}
+
+void BluetoothDevice::irTemperatureReceived(const QByteArray &value)
+{
+ const unsigned int rawObjectTemperature = (((quint8)value.at(3)) << 8) + ((quint8)value.at(2));
+ const double objectTemperature = convertIrTemperatureAPIReadingToCelsius(rawObjectTemperature);
+ const unsigned int rawAmbientTemperature = (((quint8)value.at(1)) << 8) + ((quint8)value.at(0));
+ const double ambientTemperature = convertIrTemperatureAPIReadingToCelsius(rawAmbientTemperature);
+ emit temperatureChanged(ambientTemperature, objectTemperature);
+}
+
+void BluetoothDevice::barometerReceived(const QByteArray &value)
+{
+ //Merge bytes
+ unsigned int temperature_raw;
+ unsigned int barometer_raw;
+ if (value.length() == 6) {
+ temperature_raw = (((quint8)value.at(2)) << 16) + (((quint8)value.at(1)) << 8) + ((quint8)value.at(0));
+ barometer_raw = (((quint8)value.at(5)) << 16) + (((quint8)value.at(4)) << 8) + ((quint8)value.at(3));
+ } else {
+ temperature_raw = (((quint8)value.at(1)) << 8) + ((quint8)value.at(0));
+ barometer_raw = (((quint8)value.at(3)) << 8) + ((quint8)value.at(2));
+ }
+
+ double temperature = static_cast(temperature_raw);
+ temperature /= BAROMETER_API_READING_DIVIDER;
+
+ double barometer = static_cast(barometer_raw);
+ barometer /= BAROMETER_API_READING_DIVIDER;
+ emit barometerChanged(temperature, barometer);
+}
+
+void BluetoothDevice::humidityReceived(const QByteArray &value)
+{
+ //Merge bytes
+ unsigned int humidity_raw = (((quint8)value.at(3)) << 8) + ((quint8)value.at(2));
+ double humidity = static_cast(humidity_raw);
+ humidity = humidity * HUMIDITY_API_READING_MULTIPLIER;
+ emit humidityChanged(humidity);
+}
+
+void BluetoothDevice::lightIntensityReceived(const QByteArray &value)
+{
+ //Merge bytes
+ uint16_t lightIntensity_raw;
+ lightIntensity_raw = (((quint8)value.at(1)) << 8) + ((quint8)value.at(0));
+ uint16_t e, m;
+ m = lightIntensity_raw & 0x0FFF;
+ e = (lightIntensity_raw & 0xF000) >> 12;
+
+ // Compute and final value according to TI Bluetooth LE API
+ double lightIntensity = ((double)m) * (0.01 * (double)qPow(2.0,(qreal)e));
+ emit lightIntensityChanged(lightIntensity);
+}
+
+void BluetoothDevice::motionReceived(const QByteArray &value)
+{
+ static MotionSensorData data;
+ data.msSincePreviousData = m_lastMilliseconds;
+ m_lastMilliseconds = QDateTime::currentMSecsSinceEpoch();
+ data.msSincePreviousData = m_lastMilliseconds - data.msSincePreviousData;
+ movement_data_t values;
+ quint8* writePtr = (quint8*)(&values);
+
+ for (int i = 0; i < 18; ++i) {
+ *writePtr = (quint8)value.at(i);
+ writePtr++;
+ }
+
+ // Data is in little endian. Fix here if needed.
+
+ //Convert gyroscope and accelometer readings to proper units
+ data.gyroScope_x = double(values.gyrox) * GYROSCOPE_API_READING_MULTIPLIER;
+ data.gyroScope_y = double(values.gyroy) * GYROSCOPE_API_READING_MULTIPLIER;
+ data.gyroScope_z = double(values.gyroz) * GYROSCOPE_API_READING_MULTIPLIER;
+ // Accelometer at 8G
+ data.accelometer_x = double(values.accelx) * ACCELOMETER_API_READING_MULTIPLIER;
+ data.accelometer_y = double(values.accely) * ACCELOMETER_API_READING_MULTIPLIER;
+ data.accelometer_z = double(values.accelz) * ACCELOMETER_API_READING_MULTIPLIER;
+ data.magnetometer_x = double(values.magnetomx);
+ data.magnetometer_y = double(values.magnetomy);
+ data.magnetometer_z = double(values.magnetomz);
+ emit motionChanged(data);
+}
+
+void BluetoothDevice::deviceConnected()
+{
+ if (isDeviceReady()) {
+ setState(Connected);
+ } else {
+ setState(DeviceState::Scanning);
+ statusUpdated("(Discovering services...)");
+ m_controller->discoverServices();
+ }
+}
+
+void BluetoothDevice::errorReceived(QLowEnergyController::Error /*error*/)
+{
+ setState(DeviceState::Error);
+ statusUpdated(QString("Error: %1)").arg(m_controller->errorString()));
+}
+
+void BluetoothDevice::disconnectFromDevice()
+{
+ // UI always expects disconnect() signal when calling this signal
+ // TODO what is really needed is to extend state() to a multi value
+ // and thus allowing UI to keep track of controller progress in addition to
+ // device scan progress
+
+ if (m_controller->state() != QLowEnergyController::UnconnectedState)
+ m_controller->disconnectFromDevice();
+ else
+ deviceDisconnected();
+}
+
+void BluetoothDevice::deviceDisconnected()
+{
+ statusUpdated("Disconnect from device");
+ setState(BluetoothDevice::Disconnected);
+}
+
+BluetoothDevice::DeviceState BluetoothDevice::state() const
+{
+ return m_deviceState;
+}
diff --git a/tradeshow/iot-sensortag/bluetoothdevice.h b/tradeshow/iot-sensortag/bluetoothdevice.h
new file mode 100644
index 0000000..5f114ea
--- /dev/null
+++ b/tradeshow/iot-sensortag/bluetoothdevice.h
@@ -0,0 +1,183 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qt for Device Creation.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef BLUETOOTHDEVICE_H
+#define BLUETOOTHDEVICE_H
+
+#include "serviceinfo.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+class MotionSensorData
+{
+public:
+ double gyroScope_x{};
+ double gyroScope_y{};
+ double gyroScope_z{};
+ double accelometer_x{};
+ double accelometer_y{};
+ double accelometer_z{};
+ double magnetometer_x{};
+ double magnetometer_y{};
+ double magnetometer_z{};
+ quint64 msSincePreviousData{};
+};
+
+typedef enum CharacteristicType {
+ temperatureCharacteristic = 0,
+ humidityCharacteristic,
+ barometerCharacteristic,
+ motionCharacteristic,
+ lightCharacteristic
+} CharacteristicType;
+
+class SensorTagDataProvider;
+
+class BluetoothDevice: public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString deviceName READ getName CONSTANT)
+ Q_PROPERTY(QString deviceAddress READ getAddress CONSTANT)
+ Q_PROPERTY(DeviceState state READ state NOTIFY stateChanged)
+
+public:
+ enum DeviceState {
+ Disconnected = 0,
+ Scanning,
+ Connected,
+ Error
+ };
+ Q_ENUM(DeviceState)
+
+ BluetoothDevice();
+ BluetoothDevice(const QBluetoothDeviceInfo &d);
+ ~BluetoothDevice();
+
+ QString getAddress() const;
+ QString getName() const;
+
+ DeviceState state() const;
+
+signals:
+ void updateChanged();
+ void stateChanged();
+ void temperatureChanged(double ambientTemperature, double objectTemperature);
+ void barometerChanged(double temperature, double barometer);
+ void humidityChanged(double humidity);
+ void lightIntensityChanged(double intensity);
+ void motionChanged(MotionSensorData data);
+ void statusUpdated(QString statusMsg);
+
+public slots:
+ void scanServices();
+ void disconnectFromDevice();
+ void temperatureDetailsDiscovered(QLowEnergyService::ServiceState newstate);
+ void barometerDetailsDiscovered(QLowEnergyService::ServiceState newstate);
+ void humidityDetailsDiscovered(QLowEnergyService::ServiceState newstate);
+ void lightIntensityDetailsDiscovered(QLowEnergyService::ServiceState newstate);
+ void motionDetailsDiscovered(QLowEnergyService::ServiceState newstate);
+
+private slots:
+ // QLowEnergyController realted
+ void addLowEnergyService(const QBluetoothUuid &uuid);
+ void deviceConnected();
+ void errorReceived(QLowEnergyController::Error);
+ void serviceScanDone();
+ void deviceDisconnected();
+
+ // QLowEnergyService related
+ void updateTemperature(const QLowEnergyCharacteristic &info,
+ const QByteArray &value);
+ void updatePressure(const QLowEnergyCharacteristic &info,
+ const QByteArray &value);
+ void updateHumidity(const QLowEnergyCharacteristic &info,
+ const QByteArray &value);
+ void updateLight(const QLowEnergyCharacteristic &info,
+ const QByteArray &value);
+ void updateMotionValue(const QLowEnergyCharacteristic &info,
+ const QByteArray &value);
+
+private:
+ void setState(DeviceState state);
+
+private:
+ void irTemperatureReceived(const QByteArray &value);
+ void barometerReceived(const QByteArray &value);
+ void humidityReceived(const QByteArray &value);
+ void lightIntensityReceived(const QByteArray &value);
+ void motionReceived(const QByteArray &value);
+ double convertIrTemperatureAPIReadingToCelsius(quint16 rawReading);
+ bool isDeviceReady() const;
+ void updateServiceDetails();
+
+ QLowEnergyController *m_controller;
+ QLowEnergyService *m_irTemperatureService;
+ QLowEnergyService *m_baroService;
+ QLowEnergyService *m_humidityService;
+ QLowEnergyService *m_lightService;
+ QLowEnergyService *m_motionService;
+ DeviceState m_deviceState;
+ bool m_temperatureMeasurementStarted;
+ bool m_barometerMeasurementStarted;
+ bool m_humidityMeasurementStarted;
+ bool m_lightIntensityMeasurementStarted;
+ bool m_motionMeasurementStarted;
+ quint64 m_lastMilliseconds;
+ QBluetoothDeviceInfo m_deviceInfo;
+ SensorTagDataProvider *m_dataProvider;
+ QTimer *m_serviceDetailsTimer;
+};
+
+#endif // BLUETOOTHBLUETOOTHDEVICE_H
diff --git a/tradeshow/iot-sensortag/clouddataprovider.cpp b/tradeshow/iot-sensortag/clouddataprovider.cpp
new file mode 100644
index 0000000..aa5a26c
--- /dev/null
+++ b/tradeshow/iot-sensortag/clouddataprovider.cpp
@@ -0,0 +1,262 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qt for Device Creation.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "clouddataprovider.h"
+
+#include
+#include
+#include
+
+#define MAJOR_VERSION_NUMBER 1
+#define MINOR_VERSION_NUMBER 1
+#define CLOUD_DATA_POLL_INTERVAL_MS 1000 /* 1 second update interval */
+#ifndef QT_NO_SSL
+static QString dataFetchUrl = "https://ottoryynanenqt.blob.core.windows.net/btsensortagreadings/sensorTagReadings.txt";
+#else
+static QString dataFetchUrl = "http://ottoryynanenqt.blob.core.windows.net/btsensortagreadings/sensorTagReadings.txt";
+#endif
+
+Q_DECLARE_LOGGING_CATEGORY(boot2QtDemos)
+
+CloudDataProvider::CloudDataProvider(QString id, QObject *parent)
+ : SensorTagDataProvider(id, parent)
+ , reply(nullptr)
+{
+ intervalRotation = CLOUD_DATA_POLL_INTERVAL_MS;
+ connect(&qnam, &QNetworkAccessManager::authenticationRequired,
+ this, &CloudDataProvider::slotAuthenticationRequired);
+#ifndef QT_NO_SSL
+ connect(&qnam, &QNetworkAccessManager::sslErrors,
+ this, &CloudDataProvider::sslErrors);
+#endif
+}
+
+bool CloudDataProvider::startDataFetching()
+{
+ setState(Connected);
+ pollTimer = new QTimer(this);
+ connect(pollTimer, &QTimer::timeout, this, &CloudDataProvider::pollTimerExpired);
+ pollTimer->start(CLOUD_DATA_POLL_INTERVAL_MS);
+ return true;
+}
+
+void CloudDataProvider::endDataFetching()
+{
+ httpRequestAborted = true;
+ reply->abort();
+}
+
+void CloudDataProvider::parseReceivedText()
+{
+ QList dataList = dataFetched.split('\n');
+ if (dataList[2] != "Version:") {
+ qWarning() << Q_FUNC_INFO << "Invalid file header:" << dataList[2];
+ return;
+ }
+
+ QList versionNumberList = dataList[3].split('.');
+ const int dataMajorVersion = QString(versionNumberList[0]).toInt();
+ const int dataMinorVersion = QString(versionNumberList[1]).toInt();
+ if ((MAJOR_VERSION_NUMBER < dataMajorVersion) || // Major version not supported OR
+ ((MAJOR_VERSION_NUMBER == dataMajorVersion) && // Major version OK but
+ (MINOR_VERSION_NUMBER < dataMinorVersion))) { // Minor version not supported
+ qWarning() << Q_FUNC_INFO << "Version" << dataList[3] << "not supported by version"
+ << QString::number(MAJOR_VERSION_NUMBER)+"."+QString::number(MINOR_VERSION_NUMBER);
+ return;
+ }
+ // Header OK, parse data.
+ bool gyroscopeReadingGot = false;
+ bool accelometerReadingGot = false;
+ bool magnetometerReadingGot = false;
+ bool rotationReadingsGot = false;
+ for (int stringIndex = 4; stringIndex < (dataList.length() - 1); stringIndex += 2) {
+ const QString headerText(dataList[stringIndex]);
+ const double doubleValue = QString(dataList[stringIndex + 1]).toDouble();
+ const float floatValue = QString(dataList[stringIndex + 1]).toFloat();
+ /* NOTE: We emit the signals even if value is unchanged.
+ * Otherwise the scrolling graphs in UI will not scroll.
+ */
+ if ("Humid:" == headerText) {
+ humidity = doubleValue;
+ emit relativeHumidityChanged();
+ } else if ("Temp(Ambient):" == headerText) {
+ irAmbientTemperature = doubleValue;
+ emit infraredAmbientTemperatureChanged();
+ } else if ("Temp(Object):" == headerText) {
+ irObjectTemperature = doubleValue;
+ emit infraredObjectTemperatureChanged();
+ } else if ("Light:" == headerText) {
+ lightIntensityLux = doubleValue;
+ emit lightIntensityChanged();
+ } else if ("Temp(Baro):" == headerText) {
+ barometerCelsiusTemperature = doubleValue;
+ emit barometerCelsiusTemperatureChanged();
+ } else if ("hPa:" == headerText) {
+ barometerHPa = doubleValue;
+ emit barometer_hPaChanged();
+ } else if ("gyroX:" == headerText) {
+ gyroscopeReadingGot = true;
+ gyroscopeX_degPerSec = floatValue;
+ } else if ("gyroY:" == headerText) {
+ gyroscopeReadingGot = true;
+ gyroscopeY_degPerSec = floatValue;
+ } else if ("gyroZ:" == headerText) {
+ gyroscopeReadingGot = true;
+ gyroscopeZ_degPerSec = floatValue;
+ } else if ("AccX:" == headerText) {
+ accelometerReadingGot = true;
+ accelometerX = floatValue;
+ } else if ("AccY:" == headerText) {
+ accelometerReadingGot = true;
+ accelometerY = floatValue;
+ } else if ("AccZ:" == headerText) {
+ accelometerReadingGot = true;
+ accelometerZ = floatValue;
+ } else if ("MagnX:" == headerText) {
+ magnetometerReadingGot = true;
+ magnetometerMicroT_xAxis = floatValue;
+ } else if ("MagnY:" == headerText) {
+ magnetometerReadingGot = true;
+ magnetometerMicroT_yAxis = floatValue;
+ } else if ("MagnZ:" == headerText) {
+ magnetometerReadingGot = true;
+ magnetometerMicroT_zAxis = floatValue;
+ } else if ("RotX:" == headerText) {
+ rotation_x = floatValue;
+ rotationReadingsGot = true;
+ emit rotationXChanged();
+ } else if ("RotY:" == headerText) {
+ rotation_y = floatValue;
+ rotationReadingsGot = true;
+ emit rotationYChanged();
+ } else if ("RotZ:" == headerText) {
+ rotation_z = floatValue;
+ rotationReadingsGot = true;
+ emit rotationZChanged();
+ } else {
+ qCDebug(boot2QtDemos) << "Unsupported Header:" << headerText;
+ }
+ }
+ if (gyroscopeReadingGot)
+ emit gyroscopeDegPerSecChanged();
+ if (accelometerReadingGot)
+ emit accelometerChanged();
+ if (magnetometerReadingGot)
+ emit magnetometerMicroTChanged();
+ if (rotationReadingsGot)
+ emit rotationValuesChanged();
+}
+
+void CloudDataProvider::pollTimerExpired()
+{
+ if (!reply) {
+ httpRequestAborted = false;
+ dataFetched.clear();
+ reply = qnam.get(QNetworkRequest(QUrl(dataFetchUrl)));
+ connect(reply, &QNetworkReply::finished, this, &CloudDataProvider::httpFinished);
+ connect(reply, &QIODevice::readyRead, this, &CloudDataProvider::httpReadyRead);
+ } else {
+ qWarning() << "Attempt to fetch before previous http request was completed.";
+ }
+}
+
+void CloudDataProvider::httpFinished()
+{
+ if (httpRequestAborted) {
+ qCDebug(boot2QtDemos) << "http request aborted.";
+ return;
+ }
+ if (reply->error()) {
+ qWarning() << "Failed to fetch data," << reply->errorString();
+ return;
+ }
+
+ parseReceivedText();
+ reply->deleteLater();
+ reply = nullptr;
+}
+
+void CloudDataProvider::httpReadyRead()
+{
+ // this slot gets called every time the QNetworkReply has new data.
+ // We read all of its new data and write it into the file.
+ // That way we use less RAM than when reading it at the finished()
+ // signal of the QNetworkReply
+ dataFetched += reply->readAll();
+}
+
+#ifndef QT_NO_SSL
+void CloudDataProvider::sslErrors(QNetworkReply *, const QList &errors)
+{
+ QString errorString;
+ for (const QSslError &error : errors) {
+ if (!errorString.isEmpty())
+ errorString += '\n';
+ errorString += error.errorString();
+ }
+
+ qWarning() << "Ignoring SSL Error(s):" << errorString;
+ reply->ignoreSslErrors();
+}
+#endif
+
+void CloudDataProvider::slotAuthenticationRequired(QNetworkReply *, QAuthenticator *authenticator)
+{
+ Q_UNUSED(authenticator);
+}
+
+QString CloudDataProvider::sensorType() const
+{
+ return QString("cloud data");
+}
+
+QString CloudDataProvider::versionString() const
+{
+ return QString::number(MAJOR_VERSION_NUMBER) + "." + QString::number(MINOR_VERSION_NUMBER);
+}
diff --git a/tradeshow/iot-sensortag/clouddataprovider.h b/tradeshow/iot-sensortag/clouddataprovider.h
new file mode 100644
index 0000000..ccfbeed
--- /dev/null
+++ b/tradeshow/iot-sensortag/clouddataprovider.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qt for Device Creation.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef CLOUDDATAPROVIDER_H
+#define CLOUDDATAPROVIDER_H
+
+#include "sensortagdataprovider.h"
+#include
+#include
+#include
+#include
+
+class QTimer;
+
+class CloudDataProvider : public SensorTagDataProvider
+{
+ Q_OBJECT
+public:
+ explicit CloudDataProvider(QString id, QObject *parent = 0);
+
+ bool startDataFetching();
+ void endDataFetching();
+ QString sensorType() const;
+ QString versionString() const;
+public slots:
+ void pollTimerExpired();
+
+private slots:
+ void httpFinished();
+ void httpReadyRead();
+ void slotAuthenticationRequired(QNetworkReply *, QAuthenticator *);
+#ifndef QT_NO_SSL
+ void sslErrors(QNetworkReply *, const QList &errors);
+#endif
+protected:
+ void reset() {}
+private:
+ void parseReceivedText();
+
+ QTimer *pollTimer;
+ QNetworkAccessManager qnam;
+ QNetworkReply *reply;
+ bool httpRequestAborted;
+ QByteArray dataFetched;
+};
+#endif // CLOUDDATAPROVIDER_H
diff --git a/tradeshow/iot-sensortag/clouddataproviderpool.cpp b/tradeshow/iot-sensortag/clouddataproviderpool.cpp
new file mode 100644
index 0000000..5b69803
--- /dev/null
+++ b/tradeshow/iot-sensortag/clouddataproviderpool.cpp
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qt for Device Creation.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "clouddataproviderpool.h"
+#include "clouddataprovider.h"
+
+CloudDataProviderPool::CloudDataProviderPool(QObject *parent)
+ : DataProviderPool(parent)
+{
+ m_poolName = "Cloud";
+}
+
+void CloudDataProviderPool::startScanning()
+{
+ qDeleteAll(m_dataProviders);
+ m_dataProviders.clear();
+ m_dataProviders.push_back(new CloudDataProvider("CLOUD_PROVIDER", this));
+
+ emit providerConnected("MS_AZURE_CLOUD");
+ emit providersUpdated();
+ emit dataProvidersChanged();
+ emit scanFinished();
+}
diff --git a/tradeshow/iot-sensortag/clouddataproviderpool.h b/tradeshow/iot-sensortag/clouddataproviderpool.h
new file mode 100644
index 0000000..3a13a19
--- /dev/null
+++ b/tradeshow/iot-sensortag/clouddataproviderpool.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qt for Device Creation.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef CLOUDDATAPROVIDERPOOL_H
+#define CLOUDDATAPROVIDERPOOL_H
+
+#include "dataproviderpool.h"
+
+class CloudDataProvider;
+
+class CloudDataProviderPool : public DataProviderPool
+{
+public:
+ explicit CloudDataProviderPool(QObject *parent = 0);
+
+ void startScanning() override;
+};
+
+#endif // CLOUDDATAPROVIDERPOOL_H
diff --git a/tradeshow/iot-sensortag/cloudservice.h b/tradeshow/iot-sensortag/cloudservice.h
new file mode 100644
index 0000000..35a9f8e
--- /dev/null
+++ b/tradeshow/iot-sensortag/cloudservice.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qt for Device Creation.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef CLOUDSERVICE_H
+#define CLOUDSERVICE_H
+
+#define AZURE_ACCOUNT_NAME "ottoryynanenqt"
+#define AZURE_ACCOUNT_KEY "XCZNDmLR7uLrBaO5p7sPGems8AMwNEmEM9AuDQE2cpMYgu3VikoJC0yGwh1KztU0vCCwDv17bIpDO8IpzPDBtw=="
+#define CLOUD_BLOB_NAME "btsensortagreadings"
+#define CLOUD_FILE_NAME "sensorTagReadings.txt"
+
+#endif // CLOUDSERVICE_H
diff --git a/tradeshow/iot-sensortag/cloudupdate.cpp b/tradeshow/iot-sensortag/cloudupdate.cpp
new file mode 100644
index 0000000..b43c097
--- /dev/null
+++ b/tradeshow/iot-sensortag/cloudupdate.cpp
@@ -0,0 +1,185 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qt for Device Creation.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "cloudupdate.h"
+#include "cloudservice.h"
+#include "dataproviderpool.h"
+#include "sensortagdataprovider.h"
+#include "demodataproviderpool.h"
+
+#include "was/storage_account.h"
+#include "was/blob.h"
+
+#define ROUNDING_DECIMALS 2
+#define UPDATE_INTERVAL 1000
+
+CloudUpdate::CloudUpdate(QObject *parent)
+ : QObject(parent)
+ , m_providerPool(0)
+ , m_provider(0)
+ , m_timerId(0)
+ , m_updateInterval(UPDATE_INTERVAL)
+{
+}
+
+void CloudUpdate::setDataProviderPool(DataProviderPool *provider)
+{
+ m_providerPool = provider;
+ connect(m_providerPool, &DataProviderPool::currentProviderChanged, this, [=]() {
+ m_provider = m_providerPool->currentProvider();
+ if (!m_provider)
+ stop();
+ });
+}
+
+int CloudUpdate::updateInterval() const
+{
+ return m_updateInterval;
+}
+
+void CloudUpdate::setUpdateInterval(int interval)
+{
+ m_updateInterval = interval;
+}
+
+void CloudUpdate::restart()
+{
+ killTimer(m_timerId);
+ m_timerId = startTimer(m_updateInterval);
+}
+
+void CloudUpdate::stop()
+{
+ killTimer(m_timerId);
+}
+
+void CloudUpdate::timerEvent(QTimerEvent *event)
+{
+ Q_UNUSED(event);
+
+ if (!m_provider)
+ return;
+
+ writeToCloud();
+}
+
+void CloudUpdate::writeToCloud()
+{
+ if (!m_provider) {
+ qWarning("CloudUpdate: sensor data provider not set. Data not updated");
+ return;
+ }
+
+ // Define the connection-string with your values.
+ QByteArray accStr = QByteArrayLiteral("DefaultEndpointsProtocol=https;AccountName=");
+ accStr += AZURE_ACCOUNT_NAME;
+ accStr += QByteArrayLiteral(";AccountKey=");
+ accStr += AZURE_ACCOUNT_KEY;
+#ifndef Q_OS_WIN
+ const utility::string_t storage_connection_string(U(accStr.data()));
+#else
+ const utility::string_t storage_connection_string(reinterpret_cast(QString(accStr).utf16()));
+#endif
+ azure::storage::cloud_blob_container container;
+
+ try {
+ azure::storage::cloud_storage_account storage_account = azure::storage::cloud_storage_account::parse(storage_connection_string);
+
+ // Create the blob client.
+ azure::storage::cloud_blob_client blob_client = storage_account.create_cloud_blob_client();
+
+ // Retrieve a reference to a container.
+ container = blob_client.get_container_reference(U(CLOUD_BLOB_NAME));
+
+ // Create the container if it doesn't already exist.
+ container.create_if_not_exists();
+ }
+ catch (const std::exception& e)
+ {
+ std::wcout << U("Error: ") << e.what() << std::endl;
+ }
+
+ // Retrieve reference to a blob
+ azure::storage::cloud_block_blob blob = container.get_block_blob_reference(U(CLOUD_FILE_NAME));
+
+ QString sensorData = buildString();
+#ifndef Q_OS_WIN
+ blob.upload_text(U(sensorData.toLocal8Bit().data()));
+#else
+ blob.upload_text(reinterpret_cast(sensorData.utf16()));
+#endif
+}
+
+QString CloudUpdate::buildString() const
+{
+ QString exportString;
+ exportString += QString("Type:\n%1\n").arg(m_provider->sensorType());
+ exportString += QString("Version:\n%1\n").arg(m_provider->versionString());
+ exportString += QString("Humid:\n%1\n").arg(m_provider->getRelativeHumidity(), 0, 'f', ROUNDING_DECIMALS);
+ exportString += QString("Temp(Ambient):\n%1\n").arg(m_provider->getInfraredAmbientTemperature(), 0, 'f', ROUNDING_DECIMALS);
+ exportString += QString("Temp(Object):\n%1\n").arg(m_provider->getInfraredObjectTemperature(), 0, 'f', ROUNDING_DECIMALS);
+ exportString += QString("Light:\n%1\n").arg(m_provider->getLightIntensityLux(), 0, 'f', ROUNDING_DECIMALS);
+ exportString += QString("Temp(Baro):\n%1\n").arg(m_provider->getBarometerCelsiusTemperature(), 0, 'f', ROUNDING_DECIMALS);
+ exportString += QString("hPa:\n%1\n").arg(m_provider->getBarometer_hPa(), 0, 'f', ROUNDING_DECIMALS);
+ exportString += QString("gyroX:\n%1\n").arg(m_provider->getGyroscopeX_degPerSec(), 0, 'f', ROUNDING_DECIMALS);
+ exportString += QString("gyroY:\n%1\n").arg(m_provider->getGyroscopeY_degPerSec(), 0, 'f', ROUNDING_DECIMALS);
+ exportString += QString("gyroZ:\n%1\n").arg(m_provider->getGyroscopeZ_degPerSec(), 0, 'f', ROUNDING_DECIMALS);
+ exportString += QString("AccX:\n%1\n").arg(m_provider->getAccelometer_xAxis(), 0, 'f', ROUNDING_DECIMALS);
+ exportString += QString("AccY:\n%1\n").arg(m_provider->getAccelometer_yAxis(), 0, 'f', ROUNDING_DECIMALS);
+ exportString += QString("AccZ:\n%1\n").arg(m_provider->getAccelometer_zAxis(), 0, 'f', ROUNDING_DECIMALS);
+ exportString += QString("MagnX:\n%1\n").arg(m_provider->getMagnetometerMicroT_xAxis(), 0, 'f', ROUNDING_DECIMALS);
+ exportString += QString("MagnY:\n%1\n").arg(m_provider->getMagnetometerMicroT_yAxis(), 0, 'f', ROUNDING_DECIMALS);
+ exportString += QString("MagnZ:\n%1\n").arg(m_provider->getMagnetometerMicroT_zAxis(), 0, 'f', ROUNDING_DECIMALS);
+ exportString += QString("RotX:\n%1\n").arg(m_provider->getRotationX(), 0, 'f', ROUNDING_DECIMALS);
+ exportString += QString("RotY:\n%1\n").arg(m_provider->getRotationY(), 0, 'f', ROUNDING_DECIMALS);
+ exportString += QString("RotZ:\n%1").arg(m_provider->getRotationZ(), 0, 'f', ROUNDING_DECIMALS);
+
+ return exportString;
+}
diff --git a/tradeshow/iot-sensortag/cloudupdate.h b/tradeshow/iot-sensortag/cloudupdate.h
new file mode 100644
index 0000000..f6026ce
--- /dev/null
+++ b/tradeshow/iot-sensortag/cloudupdate.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qt for Device Creation.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef CLOUDUPDATE_H
+#define CLOUDUPDATE_H
+
+#include
+
+class DataProviderPool;
+class SensorTagDataProvider;
+
+class CloudUpdate : public QObject
+{
+public:
+ explicit CloudUpdate(QObject *parent = 0);
+
+ void setDataProviderPool(DataProviderPool *provider);
+
+ int updateInterval() const;
+ void setUpdateInterval(int interval);
+ void restart();
+ void stop();
+
+protected:
+ void timerEvent(QTimerEvent *event);
+
+ virtual void writeToCloud();
+
+private:
+ QString buildString() const;
+
+protected:
+ DataProviderPool *m_providerPool;
+
+private:
+ SensorTagDataProvider *m_provider;
+ int m_timerId;
+ int m_updateInterval;
+};
+
+#endif // CLOUDUPDATE_H
diff --git a/tradeshow/iot-sensortag/dataproviderpool.cpp b/tradeshow/iot-sensortag/dataproviderpool.cpp
new file mode 100644
index 0000000..66d9480
--- /dev/null
+++ b/tradeshow/iot-sensortag/dataproviderpool.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qt for Device Creation.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "dataproviderpool.h"
+
+DataProviderPool::DataProviderPool(QObject *parent)
+ : QObject(parent)
+ , m_currentProvider(nullptr)
+ , m_currentProviderIndex(-1)
+{
+}
+
+DataProviderPool::DataProviderPool(QString poolName, QObject *parent)
+ : QObject(parent)
+ , m_poolName(poolName)
+ , m_currentProvider(nullptr)
+ , m_currentProviderIndex(-1)
+{
+
+}
+
+void DataProviderPool::startScanning()
+{
+}
+
+void DataProviderPool::stopScanning()
+{
+ emit scanFinished();
+}
+
+void DataProviderPool::disconnectProvider(const QString &id)
+{
+ Q_UNUSED(id)
+}
+
+QQmlListProperty DataProviderPool::dataProviders()
+{
+ return QQmlListProperty(this, m_dataProviders);
+}
+
+SensorTagDataProvider *DataProviderPool::providerForCloud() const
+{
+ return 0;
+}
+
+SensorTagDataProvider *DataProviderPool::currentProvider() const
+{
+ return m_currentProvider;
+}
+
+int DataProviderPool::currentProviderIndex() const
+{
+ return m_currentProviderIndex;
+}
+
+void DataProviderPool::setCurrentProviderIndex(int currentProviderIndex)
+{
+ if (m_currentProviderIndex == currentProviderIndex)
+ return;
+
+ m_currentProviderIndex = currentProviderIndex;
+ m_currentProvider = m_dataProviders.at(m_currentProviderIndex);
+ emit currentProviderIndexChanged(m_currentProviderIndex);
+ emit currentProviderChanged(m_currentProvider);
+}
diff --git a/tradeshow/iot-sensortag/dataproviderpool.h b/tradeshow/iot-sensortag/dataproviderpool.h
new file mode 100644
index 0000000..e060758
--- /dev/null
+++ b/tradeshow/iot-sensortag/dataproviderpool.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qt for Device Creation.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef DATAPROVIDERPOOL_H
+#define DATAPROVIDERPOOL_H
+
+#include
+#include
+
+#include "sensortagdataprovider.h"
+
+class DataProviderPool : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQmlListProperty dataProviders READ dataProviders NOTIFY dataProvidersChanged)
+ Q_PROPERTY(SensorTagDataProvider* currentProvider READ currentProvider NOTIFY currentProviderChanged)
+ Q_PROPERTY(int currentProviderIndex READ currentProviderIndex WRITE setCurrentProviderIndex NOTIFY currentProviderIndexChanged)
+ Q_PROPERTY(QString name MEMBER m_poolName CONSTANT)
+
+public:
+ Q_INVOKABLE virtual void startScanning();
+ Q_INVOKABLE virtual void stopScanning();
+ Q_INVOKABLE virtual void disconnectProvider(const QString &id);
+ Q_INVOKABLE virtual SensorTagDataProvider *currentProvider() const;
+ Q_INVOKABLE virtual int currentProviderIndex() const;
+
+ QQmlListProperty dataProviders();
+
+ virtual SensorTagDataProvider *providerForCloud() const;
+
+
+public slots:
+ void setCurrentProviderIndex(int currentProviderIndex);
+
+signals:
+ void providerConnected(QString id);
+ void providerDisconnected(QString id);
+ void providerInError(QString id);
+ void providersUpdated();
+ void scanStarted();
+ void scanFinished();
+ void providerForCloudChanged();
+ void dataProvidersChanged();
+ void currentProviderChanged(SensorTagDataProvider* currentProvider);
+ void currentProviderIndexChanged(int currentProviderIndex);
+
+protected:
+ explicit DataProviderPool(QObject *parent = 0);
+ DataProviderPool(QString poolName, QObject *parent = 0);
+
+protected:
+ QList m_dataProviders;
+ QString m_poolName;
+ SensorTagDataProvider *m_currentProvider;
+ int m_currentProviderIndex;
+};
+
+#endif // DATAPROVIDERPOOL_H
diff --git a/tradeshow/iot-sensortag/demodataproviderpool.cpp b/tradeshow/iot-sensortag/demodataproviderpool.cpp
new file mode 100644
index 0000000..4689a1c
--- /dev/null
+++ b/tradeshow/iot-sensortag/demodataproviderpool.cpp
@@ -0,0 +1,309 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qt for Device Creation.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "demodataproviderpool.h"
+#include "mockdataprovider.h"
+#include "bluetoothdataprovider.h"
+
+#include
+
+Q_DECLARE_LOGGING_CATEGORY(boot2QtDemos)
+
+DemoCloudProvider::DemoCloudProvider(QObject *parent)
+ : SensorTagDataProvider(parent)
+{
+}
+
+void DemoCloudProvider::setDataProviders(const QList &dataProviders)
+{
+ m_dataProviders = dataProviders;
+}
+
+QString DemoCloudProvider::sensorType() const
+{
+ if (m_dataProviders.length())
+ return m_dataProviders.at(0)->sensorType();
+ else
+ return QString();
+}
+
+QString DemoCloudProvider::versionString() const
+{
+ if (m_dataProviders.length())
+ return m_dataProviders.at(0)->versionString();
+ else
+ return QString();
+}
+
+double DemoCloudProvider::getRelativeHumidity() const
+{
+ for (SensorTagDataProvider *p: qAsConst(m_dataProviders)) {
+ if (p->tagType() & SensorTagDataProvider::Humidity)
+ return p->getRelativeHumidity();
+ }
+ return 0;
+}
+
+double DemoCloudProvider::getInfraredAmbientTemperature() const
+{
+ for (SensorTagDataProvider *p: qAsConst(m_dataProviders)) {
+ if (p->tagType() & SensorTagDataProvider::AmbientTemperature)
+ return p->getInfraredAmbientTemperature();
+ }
+ return 0;
+}
+
+double DemoCloudProvider::getInfraredObjectTemperature() const
+{
+ for (SensorTagDataProvider *p: qAsConst(m_dataProviders)) {
+ if (p->tagType() & SensorTagDataProvider::ObjectTemperature)
+ return p->getInfraredObjectTemperature();
+ }
+ return 0;
+}
+
+double DemoCloudProvider::getLightIntensityLux() const
+{
+ for (SensorTagDataProvider *p: qAsConst(m_dataProviders)) {
+ if (p->tagType() & SensorTagDataProvider::Light)
+ return p->getLightIntensityLux();
+ }
+ return 0;
+}
+
+double DemoCloudProvider::getBarometerCelsiusTemperature() const
+{
+ for (SensorTagDataProvider *p: qAsConst(m_dataProviders)) {
+ if (p->tagType() & SensorTagDataProvider::AirPressure)
+ return p->getBarometerCelsiusTemperature();
+ }
+ return 0;
+}
+
+double DemoCloudProvider::getBarometerTemperatureAverage() const
+{
+ for (SensorTagDataProvider *p: qAsConst(m_dataProviders)) {
+ if (p->tagType() & SensorTagDataProvider::AirPressure)
+ return p->getBarometerTemperatureAverage();
+ }
+ return 0;
+}
+
+double DemoCloudProvider::getBarometer_hPa() const
+{
+ for (SensorTagDataProvider *p: qAsConst(m_dataProviders)) {
+ if (p->tagType() & SensorTagDataProvider::AirPressure)
+ return p->getBarometer_hPa();
+ }
+ return 0;
+}
+
+float DemoCloudProvider::getGyroscopeX_degPerSec() const
+{
+ for (SensorTagDataProvider *p: qAsConst(m_dataProviders)) {
+ if (p->tagType() & SensorTagDataProvider::Magnetometer)
+ return p->getGyroscopeX_degPerSec();
+ }
+ return 0;
+}
+
+float DemoCloudProvider::getGyroscopeY_degPerSec() const
+{
+ for (SensorTagDataProvider *p: qAsConst(m_dataProviders)) {
+ if (p->tagType() & SensorTagDataProvider::Magnetometer)
+ return p->getGyroscopeY_degPerSec();
+ }
+ return 0;
+}
+
+float DemoCloudProvider::getGyroscopeZ_degPerSec() const
+{
+ for (SensorTagDataProvider *p: qAsConst(m_dataProviders)) {
+ if (p->tagType() & SensorTagDataProvider::Magnetometer)
+ return p->getGyroscopeZ_degPerSec();
+ }
+ return 0;
+}
+
+float DemoCloudProvider::getAccelometer_xAxis() const
+{
+ for (SensorTagDataProvider *p: qAsConst(m_dataProviders)) {
+ if (p->tagType() & SensorTagDataProvider::Accelometer)
+ return p->getAccelometer_xAxis();
+ }
+ return 0;
+}
+
+float DemoCloudProvider::getAccelometer_yAxis() const
+{
+ for (SensorTagDataProvider *p: qAsConst(m_dataProviders)) {
+ if (p->tagType() & SensorTagDataProvider::Accelometer)
+ return p->getAccelometer_yAxis();
+ }
+ return 0;
+}
+
+float DemoCloudProvider::getAccelometer_zAxis() const
+{
+ for (SensorTagDataProvider *p: qAsConst(m_dataProviders)) {
+ if (p->tagType() & SensorTagDataProvider::Accelometer)
+ return p->getAccelometer_zAxis();
+ }
+ return 0;
+}
+
+float DemoCloudProvider::getMagnetometerMicroT_xAxis() const
+{
+ for (SensorTagDataProvider *p: qAsConst(m_dataProviders)) {
+ if (p->tagType() & SensorTagDataProvider::Magnetometer)
+ return p->getMagnetometerMicroT_xAxis();
+ }
+ return 0;
+}
+
+float DemoCloudProvider::getMagnetometerMicroT_yAxis() const
+{
+ for (SensorTagDataProvider *p: qAsConst(m_dataProviders)) {
+ if (p->tagType() & SensorTagDataProvider::Magnetometer)
+ return p->getMagnetometerMicroT_yAxis();
+ }
+ return 0;
+}
+
+float DemoCloudProvider::getMagnetometerMicroT_zAxis() const
+{
+ for (SensorTagDataProvider *p: qAsConst(m_dataProviders)) {
+ if (p->tagType() & SensorTagDataProvider::Magnetometer)
+ return p->getMagnetometerMicroT_zAxis();
+ }
+ return 0;
+}
+
+float DemoCloudProvider::getRotationX() const
+{
+ for (SensorTagDataProvider *p: qAsConst(m_dataProviders)) {
+ if (p->tagType() & SensorTagDataProvider::Rotation)
+ return p->getRotationX();
+ }
+ return 0;
+}
+
+float DemoCloudProvider::getRotationY() const
+{
+ for (SensorTagDataProvider *p: qAsConst(m_dataProviders)) {
+ if (p->tagType() & SensorTagDataProvider::Rotation)
+ return p->getRotationY();
+ }
+ return 0;
+}
+
+float DemoCloudProvider::getRotationZ() const
+{
+ for (SensorTagDataProvider *p: qAsConst(m_dataProviders)) {
+ if (p->tagType() & SensorTagDataProvider::Rotation)
+ return p->getRotationZ();
+ }
+ return 0;
+}
+
+float DemoCloudProvider::getAltitude() const
+{
+ for (SensorTagDataProvider *p: qAsConst(m_dataProviders)) {
+ if (p->tagType() & SensorTagDataProvider::Altitude)
+ return p->getAltitude();
+ }
+ return 0;
+}
+
+
+DemoDataProviderPool::DemoDataProviderPool(QObject *parent)
+ : SensorTagDataProviderPool("Demo", parent)
+ , m_mockData(false)
+ , m_cloudProvider(0)
+ , m_initialized(false)
+{
+}
+
+void DemoDataProviderPool::startScanning()
+{
+ qDeleteAll(m_dataProviders);
+ m_dataProviders.clear();
+
+ MockDataProvider* p = new MockDataProvider("MOCK_PROVIDER_1", this);
+ p->setTagType(SensorTagDataProvider::ObjectTemperature | SensorTagDataProvider::AmbientTemperature | SensorTagDataProvider::Rotation);
+ m_dataProviders.push_back(p);
+ p = new MockDataProvider("MOCK_PROVIDER_2", this);
+ p->setTagType(SensorTagDataProvider::Humidity | SensorTagDataProvider::Light | SensorTagDataProvider::Accelometer);
+ m_dataProviders.push_back(p);
+ p = new MockDataProvider("MOCK_PROVIDER_3", this);
+ p->setTagType(SensorTagDataProvider::Magnetometer | SensorTagDataProvider::AirPressure);
+ m_dataProviders.push_back(p);
+ for (int i=0; i < m_dataProviders.length(); i++)
+ emit providerConnected(p->id());
+ // Stop scanning as we already have a provider
+ finishScanning();
+
+ SensorTagDataProviderPool::startScanning();
+}
+
+void DemoDataProviderPool::finishScanning()
+{
+ emit dataProvidersChanged();
+ emit scanFinished();
+}
+
+void DemoDataProviderPool::setMockDataMode(bool mode)
+{
+ m_mockData = mode;
+}
+
+SensorTagDataProvider *DemoDataProviderPool::providerForCloud() const
+{
+ return m_cloudProvider;
+}
diff --git a/tradeshow/iot-sensortag/demodataproviderpool.h b/tradeshow/iot-sensortag/demodataproviderpool.h
new file mode 100644
index 0000000..b6b6b53
--- /dev/null
+++ b/tradeshow/iot-sensortag/demodataproviderpool.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qt for Device Creation.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef DEMODATAPROVIDERPOOL_H
+#define DEMODATAPROVIDERPOOL_H
+
+#include "sensortagdataproviderpool.h"
+
+class CloudUpdate;
+
+class DemoDataProviderPool : public SensorTagDataProviderPool
+{
+ Q_OBJECT
+public:
+ explicit DemoDataProviderPool(QObject *parent = 0);
+
+ void startScanning() override;
+
+ SensorTagDataProvider *providerForCloud() const override;
+ void setMockDataMode(bool mode);
+
+protected:
+ void finishScanning() override;
+
+private:
+ bool m_mockData;
+ SensorTagDataProvider *m_cloudProvider;
+ bool m_initialized;
+};
+
+// Internal class to provide sensor data for cloud update from demo setup
+class DemoCloudProvider : public SensorTagDataProvider
+{
+ Q_OBJECT
+public:
+ explicit DemoCloudProvider(QObject *parent);
+
+ void setDataProviders(const QList &dataProviders);
+
+ QString sensorType() const override;
+ QString versionString() const override;
+
+ double getRelativeHumidity() const override;
+ double getInfraredAmbientTemperature() const override;
+ double getInfraredObjectTemperature() const override;
+ double getLightIntensityLux() const override;
+ double getBarometerCelsiusTemperature() const override;
+ double getBarometerTemperatureAverage() const override;
+ double getBarometer_hPa() const override;
+ float getGyroscopeX_degPerSec() const override;
+ float getGyroscopeY_degPerSec() const override;
+ float getGyroscopeZ_degPerSec() const override;
+ float getAccelometer_xAxis() const override;
+ float getAccelometer_yAxis() const override;
+ float getAccelometer_zAxis() const override;
+ float getMagnetometerMicroT_xAxis() const override;
+ float getMagnetometerMicroT_yAxis() const override;
+ float getMagnetometerMicroT_zAxis() const override;
+ float getRotationX() const override;
+ float getRotationY() const override;
+ float getRotationZ() const override;
+ float getAltitude() const override;
+
+ QList m_dataProviders;
+};
+
+#endif // DEMODATAPROVIDERPOOL_H
diff --git a/tradeshow/iot-sensortag/main.cpp b/tradeshow/iot-sensortag/main.cpp
new file mode 100644
index 0000000..34cdcfc
--- /dev/null
+++ b/tradeshow/iot-sensortag/main.cpp
@@ -0,0 +1,213 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qt for Device Creation.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#if defined(RUNS_AS_HOST)
+#include "bluetoothdataprovider.h"
+#include "sensortagdataprovider.h"
+#include "sensortagdataproviderpool.h"
+#include "demodataproviderpool.h"
+#endif
+#include "clouddataprovider.h"
+#include "clouddataproviderpool.h"
+#include "mockdataprovider.h"
+#include "mockdataproviderpool.h"
+#ifdef AZURE_UPLOAD
+#include "cloudupdate.h"
+#elif defined (MQTT_UPLOAD)
+#include "mqttupdate.h"
+#include "mqttdataprovider.h"
+#include "mqttdataproviderpool.h"
+#endif
+#include "seriesstorage.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+Q_DECLARE_LOGGING_CATEGORY(boot2QtDemos)
+Q_LOGGING_CATEGORY(boot2QtDemos, "boot2qt.demos.iot")
+
+QString loggingOutput;
+QQuickWindow *loggingItem{nullptr};
+void handleMessageOutput(QtMsgType, const QMessageLogContext &, const QString &text)
+{
+ loggingOutput.prepend("\n");
+ loggingOutput.prepend(text);
+
+ loggingOutput.chop(loggingOutput.size() - 1024);
+ if (loggingItem)
+ loggingItem->setProperty("loggingOutput", loggingOutput);
+}
+
+int main(int argc, char *argv[])
+{
+ auto oldHandler = qInstallMessageHandler(handleMessageOutput);
+
+ // QtChars mandate using QApplication as it uses the graphics view fw
+ QApplication app(argc, argv);
+
+ QFontDatabase::addApplicationFont(QString::fromLatin1(":/resources/base/fonts/titilliumweb/TitilliumWeb-Regular.ttf"));
+ app.setFont(QFont("Titillium Web", 13));
+
+ DataProviderPool *remoteProviderPool = nullptr;
+ DataProviderPool *localProviderPool = nullptr;
+ SeriesStorage seriesStorage;
+
+ QCommandLineParser parser;
+ parser.addOptions({{"fullscreen", "Fullscreen mode", "true | false"}});
+ parser.addHelpOption();
+ parser.process(app);
+
+#if defined(MQTT_UPLOAD)
+ remoteProviderPool = new MqttDataProviderPool;
+#endif
+#if defined(RUNS_AS_HOST)
+// localProviderPool = new MockDataProviderPool;
+ localProviderPool = new DemoDataProviderPool;
+#endif
+ seriesStorage.setDataProviderPool(remoteProviderPool);
+
+ qmlRegisterType("SensorTag.DataProvider", 1, 0, "SensorTagData");
+ qmlRegisterType("SensorTag.DataProvider", 1, 0, "DataProviderPool");
+ qmlRegisterType("SensorTag.SeriesStorage", 1, 0, "SeriesStorage");
+
+#if defined(RUNS_AS_HOST) && (defined(AZURE_UPLOAD) || defined(MQTT_UPLOAD))
+#if AZURE_UPLOAD
+ CloudUpdate update;
+# else
+ MqttUpdate update;
+# endif
+
+ update.setDataProviderPool(localProviderPool);
+ update.restart();
+#endif
+
+#ifdef DEPLOY_TO_FS
+ QString namingScheme = QStringLiteral("file://") + qApp->applicationDirPath();
+ qCDebug(boot2QtDemos) << "Loading resources from the directory" << namingScheme;
+#else
+ QString namingScheme = QStringLiteral("qrc://");
+ qCDebug(boot2QtDemos) << "Loading resources from a resource file";
+#endif
+
+ QString mainFile;
+ QUrl styleFile;
+ QString uiVariant = QStringLiteral("small");
+ bool fullScreen =
+#ifdef Q_OS_ANDROID
+ true;
+#else
+ false;
+#endif
+ int appWidth = 1920;
+ int appHeight = 1080;
+
+ QScreen* scr = qApp->screens().at(0);
+
+ QByteArray sf = qgetenv("QT_SCREEN_SCALE_FACTORS");
+ qCDebug(boot2QtDemos) << "screen dimensions" << scr->geometry().size();
+ qCDebug(boot2QtDemos) << "Scale factor:" << sf.data();
+
+ QString addressString;
+ for (auto address : QNetworkInterface::allAddresses()) {
+ if (address.protocol() == QAbstractSocket::IPv4Protocol && address != QHostAddress(QHostAddress::LocalHost)
+ && !address.toString().startsWith(QLatin1String("169"))) {
+ addressString.append(address.toString());
+ addressString.append(QLatin1Char('/'));
+ }
+ }
+#ifdef UI_WATCH
+ mainFile = namingScheme + QStringLiteral("/resources/watch/MainWatch.qml");
+ styleFile = namingScheme + QStringLiteral("/resources/watch/StyleWatch.qml");
+#else
+ mainFile = namingScheme + QStringLiteral("/resources/small/MainSmall.qml");
+ styleFile = namingScheme + QStringLiteral("/resources/small/StyleSmall.qml");
+#endif
+ qmlRegisterSingletonType(styleFile, "Style", 1,0, "Style");
+
+ if (qEnvironmentVariableIsSet("QT_IOS_DEMO_NO_FULLSCREEN")) {
+ qCDebug(boot2QtDemos) << "Application forced not to obey fullscreen setting";
+ fullScreen = false;
+ }
+
+ QQmlApplicationEngine engine;
+ engine.rootContext()->setContextProperty("pathPrefix", namingScheme + +"/resources/" + uiVariant + "/images/");
+#ifdef DEPLOY_TO_FS
+ engine.load(QUrl::fromLocalFile(qApp->applicationDirPath() + QStringLiteral("/resources/base/main.qml")));
+#else
+ engine.load(QUrl(QStringLiteral("qrc:///resources/base/main.qml")));
+#endif
+
+ QQuickWindow *item = qobject_cast