diff options
Diffstat (limited to 'basicsuite/ebike-ui/datamodelplugin')
20 files changed, 2067 insertions, 33 deletions
diff --git a/basicsuite/ebike-ui/datamodelplugin/brightnesscontroller.cpp b/basicsuite/ebike-ui/datamodelplugin/brightnesscontroller.cpp new file mode 100644 index 0000000..a6e2e30 --- /dev/null +++ b/basicsuite/ebike-ui/datamodelplugin/brightnesscontroller.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the E-Bike demo project. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QFile> + +#include "brightnesscontroller.h" + +static const char brightnessSource[] = "/sys/class/backlight/backlight/brightness"; +static const int brightnessMax = 6; +static const int brightnessMin = 1; + +BrightnessController::BrightnessController(QObject *parent) + : QObject(parent) + , m_automatic(false) +{ + QFile brightnessfile(brightnessSource); + if (brightnessfile.exists() && brightnessfile.open(QIODevice::ReadOnly)) { + char data[1]; + if (brightnessfile.read(data, 1)) { + m_brightness = static_cast<int>(data[0] - '0'); + } + } else { + // By default set to half + m_brightness = (brightnessMax + brightnessMin) / 2; + } +} + +void BrightnessController::setBrightness(int brightness) +{ + if (m_brightness == brightness) + return; + + // Valid values are between 1-6 + if (brightness < brightnessMin || brightness > brightnessMax) + return; + + QFile brightnessfile(brightnessSource); + if (brightnessfile.exists() && brightnessfile.open(QIODevice::WriteOnly)) { + char data[1] = {static_cast<char>('0' + brightness)}; + if (brightnessfile.write(data, 1) == 1) { + m_brightness = brightness; + emit brightnessChanged(m_brightness); + } + } else { + // File does not exists, simulate changes + m_brightness = brightness; + emit brightnessChanged(m_brightness); + } +} + +void BrightnessController::setAutomatic(bool automatic) +{ + if (m_automatic == automatic) + return; + + m_automatic = automatic; + emit automaticChanged(m_automatic); +} diff --git a/basicsuite/ebike-ui/datamodelplugin/brightnesscontroller.h b/basicsuite/ebike-ui/datamodelplugin/brightnesscontroller.h new file mode 100644 index 0000000..7b85f58 --- /dev/null +++ b/basicsuite/ebike-ui/datamodelplugin/brightnesscontroller.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the E-Bike demo project. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BRIGHTNESSCONTROLLER_H +#define BRIGHTNESSCONTROLLER_H + +#include <QObject> + +class BrightnessController : public QObject +{ + Q_OBJECT + Q_PROPERTY(int brightness READ brightness WRITE setBrightness NOTIFY brightnessChanged) + Q_PROPERTY(bool automatic READ automatic WRITE setAutomatic NOTIFY automaticChanged) + +public: + explicit BrightnessController(QObject *parent = nullptr); + +public: + int brightness() const { return m_brightness; } + bool automatic() const { return m_automatic; } + + void setBrightness(int brightness); + void setAutomatic(bool automatic); + +signals: + void brightnessChanged(int brightness); + void automaticChanged(bool automatic); + +public slots: + +private: + int m_brightness; + bool m_automatic; +}; + +#endif // BRIGHTNESSCONTROLLER_H diff --git a/basicsuite/ebike-ui/datamodelplugin/datamodelplugin.pro b/basicsuite/ebike-ui/datamodelplugin/datamodelplugin.pro index ce22eec..98515ef 100644 --- a/basicsuite/ebike-ui/datamodelplugin/datamodelplugin.pro +++ b/basicsuite/ebike-ui/datamodelplugin/datamodelplugin.pro @@ -1,39 +1,31 @@ TEMPLATE = lib CONFIG += plugin -QT += qml quick positioning charts +QT += quick positioning TARGET = ebikedatamodelplugin +QML_MODULENAME = DataStore SOURCES += plugin.cpp \ - $$PWD/../socketclient.cpp \ - $$PWD/../datastore.cpp \ - $$PWD/../navigation.cpp \ - $$PWD/../mapboxsuggestions.cpp \ - $$PWD/../suggestionsmodel.cpp \ - $$PWD/../mapbox.cpp \ - $$PWD/../brightnesscontroller.cpp \ - $$PWD/../fpscounter.cpp \ - $$PWD/../tripdatamodel.cpp + socketclient.cpp \ + datastore.cpp \ + navigation.cpp \ + mapboxsuggestions.cpp \ + suggestionsmodel.cpp \ + mapbox.cpp \ + brightnesscontroller.cpp \ + fpscounter.cpp \ + tripdatamodel.cpp HEADERS += \ - $$PWD/../socketclient.h \ - $$PWD/../datastore.h \ - $$PWD/../navigation.h \ - $$PWD/../mapboxsuggestions.h \ - $$PWD/../suggestionsmodel.h \ - $$PWD/../mapbox.h \ - $$PWD/../brightnesscontroller.h \ - $$PWD/../fpscounter.h \ - $$PWD/../tripdatamodel.h - -INCLUDEPATH += $$PWD/../ - -pluginfiles.files += \ - qmldir \ - -B2QT_DEPLOYPATH = /data/user/qt/qmlplugins/DataStore -target.path += $$B2QT_DEPLOYPATH -pluginfiles.path += $$B2QT_DEPLOYPATH - -INSTALLS += target pluginfiles - + socketclient.h \ + datastore.h \ + navigation.h \ + mapboxsuggestions.h \ + suggestionsmodel.h \ + mapbox.h \ + brightnesscontroller.h \ + fpscounter.h \ + tripdatamodel.h + +top_builddir=$$shadowed($$PWD/../) +include(../../shared/shared_plugin.pri) diff --git a/basicsuite/ebike-ui/datamodelplugin/datastore.cpp b/basicsuite/ebike-ui/datamodelplugin/datastore.cpp new file mode 100644 index 0000000..73567ac --- /dev/null +++ b/basicsuite/ebike-ui/datamodelplugin/datastore.cpp @@ -0,0 +1,300 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the E-Bike demo project. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QJsonArray> +#include <QMetaObject> +#include <QMetaMethod> + +#include "socketclient.h" +#include "datastore.h" +#include "tripdatamodel.h" + +// Speed conversions from m/s to km/h and mph +static const double msToKmh = 3.6; +static const double msToMph = 2.2369418519393043; +// Distance conversions to and from m to km and mi +static const double mToKm = 0.001; +static const double mToMi = 0.000621371; +static const double kmToM = 1000.0; +static const double miToM = 1609.344; +static const double mToYd = 1760.0 / 1609.344; + +DataStore::DataStore(QObject *parent) + : QObject(parent) + , m_client(new SocketClient(this)) + , m_unit(Mph) + , m_trips(new TripDataModel(this, this)) +{ + connect(m_client, &SocketClient::connected, this, &DataStore::requestStatus); + connect(m_client, &SocketClient::newMessage, this, &DataStore::parseMessage); +} + +void DataStore::connectToServer(const QString &servername) +{ + m_client->connectToServer(servername); +} + +void DataStore::getTrips() +{ + m_client->sendToServer(QJsonObject{{"method", "gettrips"}}); +} + +void DataStore::endTrip() +{ + m_client->sendToServer(QJsonObject{{"method", "endtrip"}}); +} + +void DataStore::toggleMode() +{ + setMode(mode() == Cruise ? Sport : Cruise); +} + +void DataStore::resetDemo() +{ + m_client->sendToServer(QJsonObject{{"method", "reset"}}); +} + +double DataStore::speed() const +{ + return convertSpeed(m_properties.value("speed").toDouble()); +} + +double DataStore::topSpeed() const +{ + return convertSpeed(m_properties.value("topspeed").toDouble()); +} + +double DataStore::averageSpeed() const +{ + return convertSpeed(m_current.value("distance").toDouble() / m_current.value("duration").toDouble()); +} + +double DataStore::odometer() const +{ + return convertDistance(m_properties.value("odometer").toDouble()); +} + +double DataStore::trip() const +{ + return convertDistance(m_current.value("distance").toDouble()); +} + +double DataStore::calories() const +{ + return m_current.value("calories").toDouble(); +} + +double DataStore::assistDistance() const +{ + return convertDistance(m_properties.value("assistdistance").toDouble()); +} + +double DataStore::assistPower() const +{ + return m_properties.value("assistpower").toDouble(); +} + +double DataStore::batteryLevel() const +{ + return m_properties.value("batterylevel").toDouble(); +} + +bool DataStore::lights() const +{ + return m_properties.value("lights").toBool(); +} + +DataStore::Mode DataStore::mode() const +{ + return static_cast<Mode>(m_properties.value("mode").toInt()); +} + +DataStore::Unit DataStore::unit() const +{ + return m_unit; +} + +int DataStore::arrow() const +{ + return m_properties.value("arrow").toInt(); +} + +double DataStore::legDistance() const +{ + return m_properties.value("legdistance").toDouble(); +} + +double DataStore::tripRemaining() const +{ + return m_properties.value("tripremaining").toDouble(); +} + +QString DataStore::smallUnit() const +{ + return m_unit == Kmh ? "m" : "yd"; +} + +void DataStore::setLights(bool lights) +{ + if (m_properties.value("lights").toBool() == lights) + return; + + m_properties.insert("lights", lights); + m_client->sendToServer(QJsonObject{{"method", "set"}, {"key", "lights"}, {"value", lights}}); + emit lightsChanged(); +} + +void DataStore::setMode(Mode mode) +{ + if (DataStore::mode() == mode) + return; + + m_properties.insert("mode", mode); + m_client->sendToServer(QJsonObject{{"method", "set"}, {"key", "mode"}, {"value", static_cast<int>(mode)}}); + emit modeChanged(); +} + +void DataStore::setUnit(DataStore::Unit unit) +{ + if (m_unit == unit) + return; + + m_unit = unit; + emit unitChanged(); + // Also emit all the other signals that are affected by mode change + emit speedChanged(); + emit averagespeedChanged(); + emit odometerChanged(); + emit tripChanged(); + emit assistdistanceChanged(); + emit smallUnitChanged(smallUnit()); +} + +double DataStore::convertSpeed(double speed) const +{ + return speed * (m_unit == Kmh ? msToKmh : msToMph); +} + +double DataStore::convertDistance(double distance) const +{ + return distance * (m_unit == Kmh ? mToKm : mToMi); +} + +double DataStore::convertSmallDistance(double distance) const +{ + return distance * (m_unit == Kmh ? 1.0 : mToYd); +} + +QString DataStore::getSmallUnit() const +{ + return m_unit == Kmh ? "m" : "yd"; +} + +QJsonObject DataStore::splitDistance(double distance, bool round) const +{ + if (m_unit == Kmh) { + if (distance >= kmToM) + return QJsonObject{{"value", distance * mToKm}, {"unit", "km"}, {"decimal", true}}; + else { + if (round) + distance = qRound(distance / 10) * 10; + return QJsonObject{{"value", distance}, {"unit", "m"}, {"decimal", false}}; + } + } else { + if (distance >= miToM) + return QJsonObject{{"value", distance * mToMi}, {"unit", "mi."}, {"decimal", true}}; + else { + distance *= mToYd; + if (round) + distance = qRound(distance / 10) * 10; + return QJsonObject{{"value", distance}, {"unit", "yd"}, {"decimal", false}}; + } + } +} + +QJsonObject DataStore::splitDuration(double duration) const +{ + if (duration >= 60.0) + return QJsonObject{{"value", duration / 60.0}, {"unit", "min"}}; + else + return QJsonObject{{"value", duration}, {"unit", "s"}}; +} + +void DataStore::requestStatus() +{ + m_client->sendToServer(QJsonObject{{"method", "getall"}}); +} + +void DataStore::emitByName(const QString &valuename) +{ + // Use QMetaObject information to find a proper signal + const QMetaObject *meta = metaObject(); + + // Find the notifier signal + QString signalName = QString("%1Changed()").arg(valuename); + int methodIndex = meta->indexOfSignal(signalName.toLatin1().constData()); + meta->method(methodIndex).invoke(this, Qt::AutoConnection); +} + +void DataStore::parseMessage(const QJsonObject &message) +{ + QString method = message.value("method").toString(); + + // If we are updating just one, simply insert new value and emit + if (method == "updateone") { + QString key = message.value("key").toString(); + m_properties.insert(key, message.value("value")); + emitByName(key); + // If we are updating many, then iterate over the list and update each value + } else if (method == "updatemany") { + foreach (const QJsonValue &value, message.value("values").toArray()) { + QJsonObject obj = value.toObject(); + QString key = obj.value("key").toString(); + m_properties.insert(key, obj.value("value")); + emitByName(key); + } + } else if (method == "trips") { + m_trips->setTrips(message.value("trips").toArray()); + } else if (method == "trip") { + m_trips->addTrip(message.value("trip").toObject()); + } else if (method == "currenttrip") { + m_current = message.value("currenttrip").toObject(); + m_trips->setCurrentTrip(m_current); + emit currentTripChanged(); + } else if (method == "reset") { + emit demoReset(); + } +} diff --git a/basicsuite/ebike-ui/datamodelplugin/datastore.h b/basicsuite/ebike-ui/datamodelplugin/datastore.h new file mode 100644 index 0000000..20fa388 --- /dev/null +++ b/basicsuite/ebike-ui/datamodelplugin/datastore.h @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the E-Bike demo project. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DATASTORE_H +#define DATASTORE_H + +#include <QObject> +#include <QJsonObject> + +class SocketClient; +class TripDataModel; + +class DataStore: public QObject +{ + Q_OBJECT + + // Different measured properties + Q_PROPERTY(double speed READ speed NOTIFY speedChanged) + Q_PROPERTY(double topspeed READ topSpeed NOTIFY topspeedChanged) + Q_PROPERTY(double averagespeed READ averageSpeed NOTIFY currentTripChanged) + Q_PROPERTY(double odometer READ odometer NOTIFY odometerChanged) + Q_PROPERTY(double trip READ trip NOTIFY currentTripChanged) + Q_PROPERTY(double calories READ calories NOTIFY currentTripChanged) + Q_PROPERTY(double assistdistance READ assistDistance NOTIFY assistdistanceChanged) + Q_PROPERTY(double assistpower READ assistPower NOTIFY assistpowerChanged) + Q_PROPERTY(double batterylevel READ batteryLevel NOTIFY batterylevelChanged) + + // Toggles for lights and mode + Q_PROPERTY(bool lights READ lights WRITE setLights NOTIFY lightsChanged) + Q_PROPERTY(Mode mode READ mode WRITE setMode NOTIFY modeChanged) + + // Current units + Q_PROPERTY(Unit unit READ unit WRITE setUnit NOTIFY unitChanged) + Q_PROPERTY(QString smallUnit READ smallUnit NOTIFY smallUnitChanged) + + // Navigation + Q_PROPERTY(int arrow READ arrow NOTIFY arrowChanged) + Q_PROPERTY(double legdistance READ legDistance NOTIFY legdistanceChanged) + Q_PROPERTY(double tripremaining READ tripRemaining NOTIFY tripremainingChanged) + +public: + explicit DataStore(QObject *parent = nullptr); + + enum Mode { Cruise, Sport }; + Q_ENUM(Mode) + + enum Unit { Kmh, Mph }; + Q_ENUM(Unit) + +public: + // Getters + double speed() const; + double topSpeed() const; + double averageSpeed() const; + double odometer() const; + double trip() const; + double calories() const; + double assistDistance() const; + double assistPower() const; + double batteryLevel() const; + bool lights() const; + Mode mode() const; + Unit unit() const; + int arrow() const; + double legDistance() const; + double tripRemaining() const; + QString smallUnit() const; + + // Setters + void setLights(bool lights); + void setMode(Mode mode); + void setUnit(Unit unit); + + // Get trip data model + TripDataModel *tripDataModel() const { return m_trips; } + + // Convert speed and distance to proper units + Q_INVOKABLE double convertSpeed(double speed) const; + Q_INVOKABLE double convertDistance(double distance) const; + Q_INVOKABLE double convertSmallDistance(double distance) const; + Q_INVOKABLE QString getSmallUnit() const; + + // Split and convert distance and duration to value and unit + Q_INVOKABLE QJsonObject splitDistance(double distance, bool round=false) const; + Q_INVOKABLE QJsonObject splitDuration(double duration) const; + +private: + void emitByName(const QString &valuename); + +signals: + void speedChanged(); + void topspeedChanged(); + void averagespeedChanged(); + void odometerChanged(); + void tripChanged(); + void caloriesChanged(); + void assistdistanceChanged(); + void assistpowerChanged(); + void batterylevelChanged(); + void lightsChanged(); + void modeChanged(); + void unitChanged(); + void arrowChanged(); + void legdistanceChanged(); + void tripremainingChanged(); + void currentTripChanged(); + void smallUnitChanged(QString smallUnit); + void demoReset(); + +public slots: + void connectToServer(const QString &servername); + void getTrips(); + void endTrip(); + void toggleMode(); + void resetDemo(); + +private slots: + void requestStatus(); + void parseMessage(const QJsonObject &message); + +private: + SocketClient *m_client; + QJsonObject m_properties; + QJsonObject m_current; + Unit m_unit; + TripDataModel *m_trips; + int m_smallUnit; +}; + +#endif // DATASTORE_H diff --git a/basicsuite/ebike-ui/datamodelplugin/fpscounter.cpp b/basicsuite/ebike-ui/datamodelplugin/fpscounter.cpp new file mode 100644 index 0000000..137dcb4 --- /dev/null +++ b/basicsuite/ebike-ui/datamodelplugin/fpscounter.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the E-Bike demo project. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QQuickWindow> + +#include "fpscounter.h" + +FpsCounter::FpsCounter(QObject *parent) + : QObject(parent) + , m_frameCounter(0) + , m_fps(0.0) + , m_visible(false) +{ +} + +void FpsCounter::setVisible(bool visible) +{ + if (m_visible == visible) + return; + + m_visible = visible; + emit visibleChanged(m_visible); +} + +void FpsCounter::setWindow(QQuickWindow *window) +{ + connect(window, &QQuickWindow::frameSwapped, this, &FpsCounter::frameUpdated); + startTimer(1000); + m_timer.start(); +} + +void FpsCounter::timerEvent(QTimerEvent *) +{ + // Calculate new FPS + qreal newfps = qRound(m_frameCounter * 1000.0 / m_timer.elapsed()); + m_frameCounter = 0; + m_timer.start(); + + // If there is no change, do nothing + if (qFuzzyCompare(m_fps, newfps)) + return; + + // Otherwise emit new fps + m_fps = newfps; + emit fpsChanged(m_fps); +} diff --git a/basicsuite/ebike-ui/datamodelplugin/fpscounter.h b/basicsuite/ebike-ui/datamodelplugin/fpscounter.h new file mode 100644 index 0000000..7828844 --- /dev/null +++ b/basicsuite/ebike-ui/datamodelplugin/fpscounter.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the E-Bike demo project. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FPSCOUNTER_H +#define FPSCOUNTER_H + +#include <QObject> +#include <QElapsedTimer> + +class QQuickWindow; + +class FpsCounter : public QObject +{ + Q_OBJECT + Q_PROPERTY(qreal fps READ fps NOTIFY fpsChanged) + Q_PROPERTY(bool visible READ visible WRITE setVisible NOTIFY visibleChanged) + +public: + explicit FpsCounter(QObject *parent = nullptr); + +public: + qreal fps() const { return m_fps; } + bool visible() const { return m_visible; } + void setVisible(bool visible); + void setWindow(QQuickWindow *window); + +protected: + void timerEvent(QTimerEvent *); + +signals: + void fpsChanged(qreal fps); + void visibleChanged(bool visible); + +private slots: + void frameUpdated() { m_frameCounter++; } + +private: + QElapsedTimer m_timer; + int m_frameCounter; + qreal m_fps; + bool m_visible; +}; + +#endif // FPSCOUNTER_H diff --git a/basicsuite/ebike-ui/datamodelplugin/mapbox.cpp b/basicsuite/ebike-ui/datamodelplugin/mapbox.cpp new file mode 100644 index 0000000..9d2303d --- /dev/null +++ b/basicsuite/ebike-ui/datamodelplugin/mapbox.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the E-Bike demo project. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QNetworkAccessManager> +#include <QUrlQuery> + +#include "mapbox.h" + +#define MAPBOX_URL "https://api.mapbox.com/" +#define MAPBOX_TOKEN "pk.eyJ1IjoibWFwYm94NHF0IiwiYSI6ImNpd3J3eDE0eDEzdm8ydHM3YzhzajlrN2oifQ.keEkjqm79SiFDFjnesTcgQ" + +MapBox::MapBox(QObject *parent) + : QObject(parent) + , m_nam(new QNetworkAccessManager(this)) +{ +} + +const QUrl MapBox::createUrl(const QString &path, QUrlQuery params) const +{ + // Create URL and set path + QUrl url(MAPBOX_URL); + url.setPath(path, QUrl::TolerantMode); + + // Add access token to query params + params.addQueryItem("access_token", MAPBOX_TOKEN); + url.setQuery(params); + + return url; +} + +QNetworkReply *MapBox::get(const QUrl &url) const +{ + return m_nam->get(QNetworkRequest(url)); +} + +QNetworkReply *MapBox::getGeocoding(const QString &query, const QGeoCoordinate &proximity) +{ + QUrlQuery params; + params.addQueryItem("autocomplete", "true"); + params.addQueryItem("limit", "3"); + if (proximity.isValid()) + params.addQueryItem("proximity", QString("%1,%2").arg(proximity.longitude()).arg(proximity.latitude())); + QUrl url = createUrl(QString("/geocoding/v5/mapbox.places/%1.json").arg(QString(QUrl::toPercentEncoding(query))), params); + + return get(url); +} + +QNetworkReply *MapBox::getDirections(const QGeoCoordinate &source, const QGeoCoordinate &destination, const QString &type) +{ + QString where = QString("%1,%2;%3,%4").arg(source.longitude()).arg(source.latitude()).arg(destination.longitude()).arg(destination.latitude()); + QUrlQuery params; + params.addQueryItem("steps", "true"); + params.addQueryItem("geometries", "geojson"); + QUrl url = createUrl(QString("/directions/v5/mapbox/%1/%2.json").arg(type).arg(QString(QUrl::toPercentEncoding(where))), params); + + return get(url); +} diff --git a/basicsuite/ebike-ui/datamodelplugin/mapbox.h b/basicsuite/ebike-ui/datamodelplugin/mapbox.h new file mode 100644 index 0000000..5bd295f --- /dev/null +++ b/basicsuite/ebike-ui/datamodelplugin/mapbox.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the E-Bike demo project. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MAPBOX_H +#define MAPBOX_H + +#include <QObject> +#include <QUrl> +#include <QGeoCoordinate> + +class QNetworkAccessManager; +class QNetworkReply; + +class MapBox : public QObject +{ + Q_OBJECT + +public: + explicit MapBox(QObject *parent = nullptr); + +public: + const QUrl createUrl(const QString &path, QUrlQuery params) const; + QNetworkReply *get(const QUrl &url) const; + QNetworkReply *getGeocoding(const QString &query, const QGeoCoordinate &proximity=QGeoCoordinate()); + QNetworkReply *getDirections(const QGeoCoordinate &source, const QGeoCoordinate &destination, const QString &type=QString("cycling")); + +signals: + +public slots: + +private: + QNetworkAccessManager *m_nam; +}; + +#endif // MAPBOX_H diff --git a/basicsuite/ebike-ui/datamodelplugin/mapboxsuggestions.cpp b/basicsuite/ebike-ui/datamodelplugin/mapboxsuggestions.cpp new file mode 100644 index 0000000..3f66766 --- /dev/null +++ b/basicsuite/ebike-ui/datamodelplugin/mapboxsuggestions.cpp @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the E-Bike demo project. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QTimer> +#include <QNetworkAccessManager> +#include <QNetworkReply> +#include <QUrl> +#include <QUrlQuery> +#include <QJsonDocument> +#include <QJsonParseError> +#include <QJsonObject> + +#include "mapboxsuggestions.h" +#include "mapbox.h" +#include "suggestionsmodel.h" + +MapBoxSuggestions::MapBoxSuggestions(MapBox *mapbox, QObject *parent) + : QObject(parent) + , m_mapbox(mapbox) + , m_timer(new QTimer(this)) + , m_suggestions(new SuggestionsModel(this)) +{ + // Setup timer to request 500ms after user stops typing + m_timer->setSingleShot(true); + m_timer->setInterval(500); + + // Connect timer signal + connect(m_timer, &QTimer::timeout, this, &MapBoxSuggestions::loadSuggestions); +} + +void MapBoxSuggestions::stopSuggest() +{ + m_timer->stop(); +} + +void MapBoxSuggestions::setSearch(const QString &search) +{ + if (m_search == search) + return; + + m_search = search; + m_timer->start(); + emit searchChanged(m_search); +} + +void MapBoxSuggestions::loadSuggestions() +{ + QNetworkReply *reply = m_mapbox->getGeocoding(m_search, m_center); + connect(reply, &QNetworkReply::finished, this, &MapBoxSuggestions::handleReply); + m_requests.append(reply); + emit loadingChanged(); +} + +void MapBoxSuggestions::handleReply() +{ + QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender()); + QJsonParseError error; + QJsonDocument doc = QJsonDocument::fromJson(reply->readAll(), &error); + if (error.error == QJsonParseError::NoError) { + QJsonObject obj = doc.object(); + m_suggestions->setSuggestions(obj.value("features").toArray()); + emit suggestionsChanged(); + } + + m_requests.removeOne(reply); + emit loadingChanged(); + reply->deleteLater(); +} + +void MapBoxSuggestions::setCenter(const QGeoCoordinate ¢er) +{ + if (m_center != center) { + m_center = center; + emit centerChanged(); + } +} diff --git a/basicsuite/ebike-ui/datamodelplugin/mapboxsuggestions.h b/basicsuite/ebike-ui/datamodelplugin/mapboxsuggestions.h new file mode 100644 index 0000000..8dc1506 --- /dev/null +++ b/basicsuite/ebike-ui/datamodelplugin/mapboxsuggestions.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the E-Bike demo project. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MAPBOXSUGGESTIONS_H +#define MAPBOXSUGGESTIONS_H + +#include <QObject> +#include <QGeoCoordinate> + +class MapBox; +class QNetworkReply; +class QTimer; +class SuggestionsModel; + +class MapBoxSuggestions : public QObject +{ + Q_OBJECT + Q_PROPERTY(SuggestionsModel suggestions READ suggestions NOTIFY suggestionsChanged) + Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged) + Q_PROPERTY(QGeoCoordinate center READ center WRITE setCenter NOTIFY centerChanged) + Q_PROPERTY(QString search READ search WRITE setSearch NOTIFY searchChanged) + +public: + explicit MapBoxSuggestions(MapBox *mapbox, QObject *parent = nullptr); + +public: + SuggestionsModel *suggestions() const { return m_suggestions; } + bool loading() const { return m_requests.size() > 0; } + const QGeoCoordinate center() { return m_center; } + void setCenter(const QGeoCoordinate ¢er); + const QString search() const { return m_search; } + void setSearch(const QString &search); + +signals: + void suggestionsChanged(); + void loadingChanged(); + void centerChanged(); + void searchChanged(QString search); + +public slots: + void stopSuggest(); + +private slots: + void loadSuggestions(); + void handleReply(); + +private: + MapBox *m_mapbox; + QTimer *m_timer; + QList<QNetworkReply *> m_requests; + SuggestionsModel *m_suggestions; + QGeoCoordinate m_center; + QString m_search; +}; + +#endif // MAPBOXSUGGESTIONS_H diff --git a/basicsuite/ebike-ui/datamodelplugin/navigation.cpp b/basicsuite/ebike-ui/datamodelplugin/navigation.cpp new file mode 100644 index 0000000..067636e --- /dev/null +++ b/basicsuite/ebike-ui/datamodelplugin/navigation.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the E-Bike demo project. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QJsonDocument> +#include <QJsonArray> +#include <QNetworkReply> + +#include "navigation.h" +#include "mapbox.h" + +Navigation::Navigation(MapBox *mapbox, QObject *parent) + : QObject(parent) + , m_mapbox(mapbox) + , m_position(QGeoCoordinate(36.131961, -115.153048), QDateTime::currentDateTime()) + , m_zoomlevel(18) + , m_active(false) + , m_routeDirection(0) + , m_routePosition(m_position.coordinate()) +{ + m_position.setAttribute(QGeoPositionInfo::Direction, 0); +} + +void Navigation::setPosition(const QGeoPositionInfo &position) +{ + if (m_position != position) { + m_position = position; + emit positionChanged(m_position); + } +} + +void Navigation::setCoordinate(const QGeoCoordinate &coordinate) +{ + if (m_position.coordinate() != coordinate) { + m_position.setCoordinate(coordinate); + emit coordinateChanged(m_position.coordinate()); + } +} + +void Navigation::setDirection(qreal direction) +{ + if (qFuzzyCompare(m_position.attribute(QGeoPositionInfo::Direction), direction)) + return; + + m_position.setAttribute(QGeoPositionInfo::Direction, direction); + emit directionChanged(direction); +} + +void Navigation::setZoomLevel(qreal zoomlevel) +{ + if (qFuzzyCompare(m_zoomlevel, zoomlevel)) + return; + + m_zoomlevel = zoomlevel; + emit zoomLevelChanged(m_zoomlevel); +} + +void Navigation::setActive(bool active) +{ + if (m_active == active) + return; + + m_active = active; + emit activeChanged(m_active); +} diff --git a/basicsuite/ebike-ui/datamodelplugin/navigation.h b/basicsuite/ebike-ui/datamodelplugin/navigation.h new file mode 100644 index 0000000..6c9533f --- /dev/null +++ b/basicsuite/ebike-ui/datamodelplugin/navigation.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the E-Bike demo project. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef NAVIGATION_H +#define NAVIGATION_H + +#include <QObject> +#include <QGeoPositionInfo> +#include <QJsonObject> +#include <QJSValue> +#include <QTimer> + +#include <QDebug> + +class MapBox; + +class Navigation : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QGeoPositionInfo position READ position WRITE setPosition NOTIFY positionChanged) + Q_PROPERTY(QGeoCoordinate coordinate READ coordinate WRITE setCoordinate NOTIFY coordinateChanged) + Q_PROPERTY(qreal direction READ direction WRITE setDirection NOTIFY directionChanged) + Q_PROPERTY(qreal zoomlevel READ zoomLevel WRITE setZoomLevel NOTIFY zoomLevelChanged) + Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) + Q_PROPERTY(qreal routeDirection READ routeDirection NOTIFY routeDirectionChanged) + Q_PROPERTY(QGeoCoordinate routePosition READ routePosition NOTIFY routePositionChanged) + +public: + explicit Navigation(MapBox *mapbox, QObject *parent = nullptr); + +public: + // Getters + const QGeoPositionInfo &position() const { return m_position; } + QGeoCoordinate coordinate() const { return m_position.coordinate(); } + qreal direction() const { return m_position.attribute(QGeoPositionInfo::Direction); } + qreal zoomLevel() const { return m_zoomlevel; } + bool active() const { return m_active; } + + qreal routeDirection() const { return m_routeDirection; } + QGeoCoordinate routePosition() const { return m_routePosition; } + + // Setters + void setPosition(const QGeoPositionInfo &position); + void setCoordinate(const QGeoCoordinate &coordinate); + void setDirection(qreal direction); + void setZoomLevel(qreal zoomlevel); + void setActive(bool active); + +signals: + void positionChanged(QGeoPositionInfo position); + void coordinateChanged(QGeoCoordinate coordinate); + void directionChanged(qreal direction); + void zoomLevelChanged(qreal zoomlevel); + void activeChanged(bool active); + + void routeDirectionChanged(qreal routeDirection); + void routePositionChanged(QGeoCoordinate routePosition); + +private: + MapBox *m_mapbox; + QGeoPositionInfo m_position; + qreal m_zoomlevel; + bool m_active; + + qreal m_routeDirection; + QGeoCoordinate m_routePosition; +}; + +#endif // NAVIGATION_H diff --git a/basicsuite/ebike-ui/datamodelplugin/plugin.cpp b/basicsuite/ebike-ui/datamodelplugin/plugin.cpp index 098a6a8..870d418 100644 --- a/basicsuite/ebike-ui/datamodelplugin/plugin.cpp +++ b/basicsuite/ebike-ui/datamodelplugin/plugin.cpp @@ -70,7 +70,7 @@ class QExampleQmlPlugin : public QQmlExtensionPlugin public: - void registerTypes(const char *uri) + void registerTypes(const char *uri) { Q_UNUSED(uri); qmlRegisterType<DataStore>("DataStore", 1, 0, "DataStore"); @@ -89,7 +89,7 @@ public: MapBoxSuggestions *suggest = new MapBoxSuggestions(mapbox, engine); // Setup navigation container - Navigation *navi = new Navigation(mapbox, engine); + Navigation *navi = new Navigation(nullptr, engine); // Brightness controller BrightnessController *brightness = new BrightnessController(engine); diff --git a/basicsuite/ebike-ui/datamodelplugin/socketclient.cpp b/basicsuite/ebike-ui/datamodelplugin/socketclient.cpp new file mode 100644 index 0000000..d40d268 --- /dev/null +++ b/basicsuite/ebike-ui/datamodelplugin/socketclient.cpp @@ -0,0 +1,152 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the E-Bike demo project. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QDataStream> +#include <QJsonDocument> + +#include "socketclient.h" + +SocketClient::SocketClient(QObject *parent) + : QObject(parent) + , m_socket(new QLocalSocket(this)) +{ + // Connect socket signals + connect(m_socket, &QLocalSocket::connected, this, &SocketClient::connected); + connect(m_socket, &QLocalSocket::disconnected, this, &SocketClient::disconnected); + connect(m_socket, &QLocalSocket::readyRead, this, &SocketClient::readyRead); + + // Setup timer to try to reconnect after disconnect + m_connectionTimer.setInterval(5000); + connect(&m_connectionTimer, &QTimer::timeout, this, &SocketClient::reconnect); + connect(m_socket, &QLocalSocket::connected, &m_connectionTimer, &QTimer::stop); + connect(m_socket, &QLocalSocket::disconnected, + &m_connectionTimer, static_cast<void (QTimer::*)()>(&QTimer::start)); + connect(m_socket, static_cast<void(QLocalSocket::*)(QLocalSocket::LocalSocketError)>(&QLocalSocket::error), + &m_connectionTimer, static_cast<void (QTimer::*)()>(&QTimer::start)); +} + +void SocketClient::connectToServer(const QString &servername) +{ + m_servername = servername; + reconnect(); +} + +void SocketClient::reconnect() +{ + qDebug("Connecting to server..."); + m_socket->connectToServer(m_servername); +} + +qint64 SocketClient::write(const QByteArray &data) +{ + return m_socket->write(data); +} + +/** + * @brief send a QByteArray to the server + * @param message + * + * Adds the length of the message as a header and sends the message to the server. + */ +void SocketClient::sendToServer(const QByteArray &message) +{ + // Prepend the message length + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + stream << static_cast<qint32>(message.size() + 4); + data.append(message); + + write(data); +} + +/** + * @brief send a Json object to the server + * @param message + * + * Sends a QJsonObject object to the server, encoded in Qt's internal binary format. + */ +void SocketClient::sendToServer(const QJsonObject &message) +{ + QJsonDocument doc(message); + sendToServer(doc.toBinaryData()); +} + +/** + * @brief reads incoming data from the server + * + * Parses only message headers and body as QByteArray, but does not care about + * the contents. All complete messages are processed at @see parseMessage. + */ +void SocketClient::readyRead() +{ + m_data += m_socket->readAll(); + + bool messagefound = true; + while (messagefound) { + messagefound = false; + // If we have at least some data + if (m_data.size() >= 4) { + // Extract message size + qint32 messagesize; + QDataStream stream(m_data.left(4)); + stream >> messagesize; + + // If we have enough data for at least one message + if (m_data.size() >= messagesize) { + // Extract actual message + QByteArray message = m_data.mid(4, messagesize - 4); + parseMessage(message); + // Drop necessary amount of bytes + m_data = m_data.mid(messagesize); + messagefound = true; // Try to parse another message + } + } + } +} + +/** + * @brief parse the contents of a QByteArray + * @param message + * + * Contents are parsed from QJsonDocument's binary data. This separation allows + * the format to be changed later on, if need be. + */ +void SocketClient::parseMessage(const QByteArray &message) +{ + // Parse message from raw format + QJsonDocument doc = QJsonDocument::fromBinaryData(message); + emit newMessage(doc.object()); +} diff --git a/basicsuite/ebike-ui/datamodelplugin/socketclient.h b/basicsuite/ebike-ui/datamodelplugin/socketclient.h new file mode 100644 index 0000000..dc100a2 --- /dev/null +++ b/basicsuite/ebike-ui/datamodelplugin/socketclient.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the E-Bike demo project. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SOCKETCLIENT_H +#define SOCKETCLIENT_H + +#include <QObject> +#include <QLocalSocket> +#include <QTimer> +#include <QJsonObject> + +/** + * @brief The SocketClient class + * + * Socket container and message parser for client communications. + */ +class SocketClient : public QObject +{ + Q_OBJECT + +public: + explicit SocketClient(QObject *parent = nullptr); + +public: + QLocalSocket* socket(void) const { return m_socket; } + qint64 write(const QByteArray &data); + void sendToServer(const QByteArray &message); + void sendToServer(const QJsonObject &message); + +private: + void parseMessage(const QByteArray &message); + +signals: + void connected(); + void disconnected(); + + void newMessage(const QJsonObject &message); + +public slots: + void connectToServer(const QString &servername); + +private slots: + void reconnect(); + void readyRead(); + +private: + QLocalSocket *m_socket; + QString m_servername; + QTimer m_connectionTimer; + QByteArray m_data; +}; + +#endif // SOCKETCLIENT_H diff --git a/basicsuite/ebike-ui/datamodelplugin/suggestionsmodel.cpp b/basicsuite/ebike-ui/datamodelplugin/suggestionsmodel.cpp new file mode 100644 index 0000000..fa028f0 --- /dev/null +++ b/basicsuite/ebike-ui/datamodelplugin/suggestionsmodel.cpp @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the E-Bike demo project. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QCoreApplication> +#include <QDir> +#include <QFile> +#include <QJsonDocument> + +#include "suggestionsmodel.h" + +#define EBIKE_DEMO_MODE + +static const char mostRecentFilename[] = "mostrecent.bson"; + +SuggestionsModel::SuggestionsModel(QObject *parent) + : QAbstractListModel(parent) +{ + loadMostRecent(); +} + +SuggestionsModel::SuggestionsModel(const QJsonArray &suggestions, QObject *parent) + : QAbstractListModel(parent) + , m_suggestions(suggestions) +{ + loadMostRecent(); +} + +QVariant SuggestionsModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + // Only horizontal header + if (orientation == Qt::Vertical) + return QVariant(); + + if (role == Qt::DisplayRole && section == 0) + return tr("Place"); + + return QAbstractListModel::headerData(section, orientation, role); +} + +int SuggestionsModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + return m_suggestions.isEmpty() ? m_mostrecent.size() : m_suggestions.size(); +} + +QVariant SuggestionsModel::data(const QModelIndex &index, int role) const +{ + QJsonObject obj = get(index.row()); + if (role == Qt::DisplayRole) { + return obj.value("place_name").toVariant(); + } else if (role == PlaceNameRole) { + return obj.value("place_name").toVariant(); + } + + return QVariant(); +} + +QHash<int, QByteArray> SuggestionsModel::roleNames() const +{ + QHash<int, QByteArray> roles = QAbstractListModel::roleNames(); + roles[PlaceNameRole] = "placename"; + return roles; +} + +const QJsonObject SuggestionsModel::get(int index) const +{ + return m_suggestions.isEmpty() ? + m_mostrecent[index].toObject() : + m_suggestions[index].toObject(); +} + +void SuggestionsModel::setSuggestions(const QJsonArray &suggestions) +{ + beginResetModel(); + m_suggestions = suggestions; + endResetModel(); + emit emptyChanged(); +} + +void SuggestionsModel::clear() +{ + beginResetModel(); + m_suggestions = QJsonArray(); + endResetModel(); + emit emptyChanged(); +} + +void SuggestionsModel::addToMostRecent(const QJsonObject &place) +{ + Q_UNUSED(place) + // For the demo, do not add new most recent places +#ifndef EBIKE_DEMO_MODE + if (!m_mostrecent.contains(place)) + m_mostrecent.prepend(place); + if (m_mostrecent.size() > 3) + m_mostrecent.pop_back(); + saveMostRecent(); +#endif +} + +void SuggestionsModel::loadMostRecent() +{ + QDir dir(QCoreApplication::applicationDirPath()); + + // Load most recent places + QString mostRecentFilepath = dir.absoluteFilePath(mostRecentFilename); + QFile mostRecentFile(mostRecentFilepath); + if (mostRecentFile.open(QIODevice::ReadOnly)) { + QJsonDocument doc = QJsonDocument::fromBinaryData(mostRecentFile.readAll()); + m_mostrecent = doc.array(); + } +} + +void SuggestionsModel::saveMostRecent() const +{ + QDir dir(QCoreApplication::applicationDirPath()); + + // Load most recent places + QString mostRecentFilepath = dir.absoluteFilePath(mostRecentFilename); + QFile mostRecentFile(mostRecentFilepath); + if (mostRecentFile.open(QIODevice::WriteOnly)) { + QJsonDocument doc(m_mostrecent); + mostRecentFile.write(doc.toBinaryData()); + } +} diff --git a/basicsuite/ebike-ui/datamodelplugin/suggestionsmodel.h b/basicsuite/ebike-ui/datamodelplugin/suggestionsmodel.h new file mode 100644 index 0000000..5bf22b5 --- /dev/null +++ b/basicsuite/ebike-ui/datamodelplugin/suggestionsmodel.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the E-Bike demo project. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SUGGESTIONSMODEL_H +#define SUGGESTIONSMODEL_H + +#include <QAbstractListModel> +#include <QJsonArray> +#include <QJsonObject> + +class SuggestionsModel : public QAbstractListModel +{ + Q_OBJECT + Q_PROPERTY(bool empty READ isEmpty RESET clear NOTIFY emptyChanged) + +public: + explicit SuggestionsModel(QObject *parent = nullptr); + explicit SuggestionsModel(const QJsonArray &suggestions, QObject *parent = nullptr); + enum SuggestionRoles { + PlaceNameRole = Qt::UserRole + 1 + }; + +public: + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + virtual int rowCount(const QModelIndex &parent) const; + virtual QVariant data(const QModelIndex &index, int role) const; + virtual QHash<int, QByteArray> roleNames() const; + + Q_INVOKABLE const QJsonObject get(int index) const; + bool isEmpty() const { return m_suggestions.size() == 0; } + + void setSuggestions(const QJsonArray &suggestions); + Q_INVOKABLE void clear(); + + Q_INVOKABLE void addToMostRecent(const QJsonObject &place); + +private: + void loadMostRecent(); + void saveMostRecent() const; + +signals: + void emptyChanged(); + +private: + QJsonArray m_mostrecent; + QJsonArray m_suggestions; +}; + +#endif // SUGGESTIONSMODEL_H diff --git a/basicsuite/ebike-ui/datamodelplugin/tripdatamodel.cpp b/basicsuite/ebike-ui/datamodelplugin/tripdatamodel.cpp new file mode 100644 index 0000000..b74605f --- /dev/null +++ b/basicsuite/ebike-ui/datamodelplugin/tripdatamodel.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the E-Bike demo project. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "datastore.h" +#include "tripdatamodel.h" + +#include <QDebug> + +TripDataModel::TripDataModel(DataStore *datastore, QObject *parent) + : QAbstractListModel(parent) + , m_datastore(datastore) + , m_refreshing(false) + , m_saving(false) +{ +} + +int TripDataModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + return m_trips.count() + 1; // +1 for current trip +} + +QVariant TripDataModel::data(const QModelIndex &index, int role) const +{ + QJsonObject obj = get(index.row()); + if (role == DurationRole) + return obj.value("duration").toDouble(); // Seconds + else if (role == DistanceRole) + return m_datastore->convertDistance(obj.value("distance").toDouble()); + else if (role == CaloriesRole) + return obj.value("calories").toDouble(); + else if (role == MaxspeedRole) + return m_datastore->convertSpeed(obj.value("maxspeed").toDouble()); + else if (role == AvgspeedRole) + return m_datastore->convertSpeed(obj.value("distance").toDouble() / obj.value("duration").toDouble()); + else if (role == AscentRole) + return obj.value("ascent").toDouble(); + else if (role == StartTimeRole) + return obj.value("starttime").toDouble(); + + return QVariant(); +} + +QHash<int, QByteArray> TripDataModel::roleNames() const +{ + QHash<int, QByteArray> roles = QAbstractListModel::roleNames(); + roles[DurationRole] = "duration"; + roles[DistanceRole] = "distance"; + roles[CaloriesRole] = "calories"; + roles[MaxspeedRole] = "maxspeed"; + roles[AvgspeedRole] = "avgspeed"; + roles[AscentRole] = "ascent"; + roles[StartTimeRole] = "starttime"; + + return roles; +} + +void TripDataModel::setTrips(const QJsonArray &trips) +{ + beginResetModel(); + m_trips = trips; + endResetModel(); + m_refreshing = false; + emit refreshingChanged(m_refreshing); + emit refreshed(); +} + +void TripDataModel::addTrip(const QJsonObject &trip) +{ + // Always append at the beginning of the list, easy to calculate + int newRow = 0; + beginInsertRows(QModelIndex(), newRow, newRow); + m_trips.append(trip); + endInsertRows(); + emit tripDataSaved(newRow); +} + +const QJsonObject TripDataModel::get(int index) const +{ + return index == 0 ? m_current : m_trips.at(m_trips.count() - index).toObject(); +} + +void TripDataModel::refresh() +{ + m_refreshing = true; + emit refreshingChanged(m_refreshing); + m_datastore->getTrips(); +} + +void TripDataModel::endTrip() +{ + m_saving = true; + emit savingChanged(m_saving); + m_datastore->endTrip(); +} + +void TripDataModel::setCurrentTrip(const QJsonObject ¤t) +{ + m_current = current; + QModelIndex currentIndex = index(0); + emit dataChanged(currentIndex, currentIndex); +} diff --git a/basicsuite/ebike-ui/datamodelplugin/tripdatamodel.h b/basicsuite/ebike-ui/datamodelplugin/tripdatamodel.h new file mode 100644 index 0000000..56be84e --- /dev/null +++ b/basicsuite/ebike-ui/datamodelplugin/tripdatamodel.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the E-Bike demo project. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TRIPDATAMODEL_H +#define TRIPDATAMODEL_H + +#include <QAbstractListModel> +#include <QJsonObject> +#include <QJsonArray> + +class DataStore; + +class TripDataModel : public QAbstractListModel +{ + Q_OBJECT + Q_PROPERTY(bool refreshing READ refreshing NOTIFY refreshingChanged) + Q_PROPERTY(bool saving READ saving NOTIFY savingChanged) + +public: + explicit TripDataModel(DataStore *datastore, QObject *parent = nullptr); + enum TripDataRoles { + DurationRole = Qt::UserRole + 1, + DistanceRole, + CaloriesRole, + MaxspeedRole, + AvgspeedRole, + AscentRole, + StartTimeRole + }; + +public: + virtual int rowCount(const QModelIndex &parent) const; + virtual QVariant data(const QModelIndex &index, int role) const; + virtual QHash<int, QByteArray> roleNames() const; + + Q_INVOKABLE const QJsonObject get(int index) const; + + void setTrips(const QJsonArray &trips); + void addTrip(const QJsonObject &trip); + + bool refreshing() const { return m_refreshing; } + bool saving() const { return m_saving; } + +signals: + void refreshed(); + void refreshingChanged(bool refreshing); + void savingChanged(bool saving); + void tripDataSaved(int index); + +public slots: + void refresh(); + void endTrip(); + void setCurrentTrip(const QJsonObject ¤t); + +private: + DataStore *m_datastore; + QJsonArray m_trips; + QJsonObject m_current; + bool m_refreshing; + bool m_saving; +}; + +#endif // TRIPDATAMODEL_H |