Commit 73ab8063 authored by Volker Krause's avatar Volker Krause

Generalize JSON de/serialization code

We'll need that for the other data types too.
parent eef6d7e1
......@@ -17,6 +17,7 @@ set(kpublictransport_srcs
datatypes/departure.cpp
datatypes/journey.cpp
datatypes/json.cpp
datatypes/line.cpp
datatypes/location.cpp
......
/*
Copyright (C) 2018 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "json.h"
#include <QMetaObject>
#include <QMetaProperty>
#include <QVariant>
using namespace KPublicTransport;
static QJsonValue variantToJson(const QVariant &v)
{
switch (v.userType()) {
case QMetaType::QString:
return v.toString();
case QMetaType::Double:
case QMetaType::Float:
return v.toDouble();
case QMetaType::Int:
return v.toInt();
}
return {};
}
QJsonObject Json::toJson(const QMetaObject *mo, const void *elem)
{
QJsonObject obj;
for (int i = 0; i < mo->propertyCount(); ++i) {
const auto prop = mo->property(i);
if (!prop.isStored()) {
continue;
}
const auto v = variantToJson(prop.readOnGadget(elem));
if (!v.isNull()) {
obj.insert(QString::fromUtf8(prop.name()), v);
}
}
return obj;
}
static QVariant variantFromJson(const QJsonValue &v, int mt)
{
switch (mt) {
case QMetaType::QString:
return v.toString();
case QMetaType::Double:
case QMetaType::Float:
return v.toDouble();
case QMetaType::Int:
return v.toInt();
}
return {};
}
void Json::fromJson(const QMetaObject *mo, const QJsonObject &obj, void *elem)
{
for (auto it = obj.begin(); it != obj.end(); ++it) {
const auto idx = mo->indexOfProperty(it.key().toUtf8());
if (idx < 0) {
continue;
}
const auto prop = mo->property(idx);
if (!prop.isStored()) {
continue;
}
const auto v = variantFromJson(it.value(), prop.userType());
prop.writeOnGadget(elem, v);
}
}
/*
Copyright (C) 2018 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef KPUBLICTRANSPORT_JSON_H
#define KPUBLICTRANSPORT_JSON_H
#include <QJsonObject>
class QMetaObject;
namespace KPublicTransport {
/** De/serialization helper methods. */
namespace Json
{
QJsonObject toJson(const QMetaObject *mo, const void *elem);
/** Serialize from QMetaObject. */
template <typename T> inline QJsonObject toJson(const T &elem)
{
return toJson(&T::staticMetaObject, &elem);
}
void fromJson(const QMetaObject *mo, const QJsonObject &obj, void *elem);
/** Deserialize via QMetaObject. */
template <typename T> inline T fromJson(const QJsonObject &obj)
{
T elem;
fromJson(&T::staticMetaObject, obj, &elem);
return elem;
}
}
}
#endif // KPUBLICTRANSPORT_JSON_H
......@@ -18,6 +18,7 @@
#include "location.h"
#include "datatypes_p.h"
#include "json.h"
#include <QHash>
#include <QJsonArray>
......@@ -60,11 +61,23 @@ float Location::latitude() const
return d->latitude;
}
void Location::setLatitude(float latitude)
{
d.detach();
d->latitude = latitude;
}
float Location::longitude() const
{
return d->longitude;
}
void Location::setLongitude(float longitude)
{
d.detach();
d->longitude = longitude;
}
void Location::setCoordinate(float latitude, float longitude)
{
d.detach();
......@@ -155,10 +168,7 @@ int Location::distance(float lat1, float lon1, float lat2, float lon2)
QJsonObject Location::toJson(const Location &loc)
{
QJsonObject obj;
obj.insert(QLatin1String("name"), loc.name());
obj.insert(QLatin1String("latitude"), loc.latitude());
obj.insert(QLatin1String("longitude"), loc.longitude());
auto obj = Json::toJson(loc);
if (loc.timeZone().isValid()) {
obj.insert(QLatin1String("timezone"), QString::fromUtf8(loc.timeZone().id()));
}
......@@ -182,9 +192,7 @@ QJsonArray Location::toJson(const std::vector<Location> &locs)
static Location fromJsonObject(const QJsonObject &obj)
{
Location loc;
loc.setName(obj.value(QLatin1String("name")).toString());
loc.setCoordinate(obj.value(QLatin1String("latitude")).toDouble(), obj.value(QLatin1String("longitude")).toDouble());
auto loc = Json::fromJson<Location>(obj);
const auto tz = obj.value(QLatin1String("timezone")).toString();
if (!tz.isEmpty()) {
loc.setTimeZone(QTimeZone(tz.toUtf8()));
......
......@@ -37,8 +37,8 @@ class Location
/** Human-readable name of the location. */
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(float latitude READ latitude)
Q_PROPERTY(float longitude READ longitude)
Q_PROPERTY(float latitude READ latitude WRITE setLatitude)
Q_PROPERTY(float longitude READ longitude WRITE setLongitude)
// TODO: type, id, address
......@@ -47,7 +47,9 @@ public:
void setName(const QString &name);
float latitude() const;
void setLatitude(float latitude);
float longitude() const;
void setLongitude(float longitude);
void setCoordinate(float latitude, float longitude);
bool hasCoordinate() const;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment