From ecda5103c84feff9fb0edbf95967fe15e527f9e0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Martin=20T=C5=AFma?= Date: Wed, 31 May 2023 01:01:42 +0200 Subject: [PATCH] Properly handle Mapsforge style menus --- src/map/mapsforge/style.cpp | 88 +++++++++++++++++++++++++++++++++++++++------ src/map/mapsforge/style.h | 46 ++++++++++++++++++++++-- 2 files changed, 120 insertions(+), 14 deletions(-) diff --git a/src/map/mapsforge/style.cpp b/src/map/mapsforge/style.cpp index 49df83c3..807fc740 100644 --- a/src/map/mapsforge/style.cpp +++ b/src/map/mapsforge/style.cpp @@ -69,6 +69,42 @@ static QList valList(const QList &in) return out; } +const Style::Menu::Layer *Style::Menu::findLayer(const QString &id) const +{ + for (int i = 0; i < _layers.size(); i++) + if (_layers.at(i).id() == id) + return &_layers.at(i); + + qWarning("%s: layer not found", qPrintable(id)); + + return 0; +} + +void Style::Menu::addCats(const Layer *layer, QSet &cats) const +{ + if (!layer) + return; + + if (!layer->parent().isNull()) + addCats(findLayer(layer->parent()), cats); + + for (int i = 0; i < layer->cats().size(); i++) + cats.insert(layer->cats().at(i)); + + for (int i = 0; i < layer->overlays().size(); i++) { + const Layer *overlay = findLayer(layer->overlays().at(i)); + if (overlay && overlay->enabled()) + addCats(overlay, cats); + } +} + +QSet Style::Menu::cats() const +{ + QSet c; + addCats(findLayer(_defaultvalue), c); + return c; +} + Style::Rule::Filter::Filter(const MapData &data, const QList &keys, const QList &vals) : _neg(false) { @@ -499,36 +535,65 @@ void Style::rule(QXmlStreamReader &reader, const QString &dir, } } -void Style::cat(QXmlStreamReader &reader, QSet &cats) +QString Style::cat(QXmlStreamReader &reader) { const QXmlStreamAttributes &attr = reader.attributes(); - cats.insert(attr.value("id").toString()); + if (!attr.hasAttribute("id")) { + reader.raiseError("Missing id attribute"); + return QString(); + } + QString id(attr.value("id").toString()); reader.skipCurrentElement(); + + return id; } -void Style::layer(QXmlStreamReader &reader, QSet &cats) +Style::Menu::Layer Style::layer(QXmlStreamReader &reader) { const QXmlStreamAttributes &attr = reader.attributes(); - bool enabled = (attr.value("enabled").toString() == "true"); + if (!attr.hasAttribute("id")) { + reader.raiseError("Missing id attribute"); + return Menu::Layer(); + } + + Menu::Layer l(attr.value("id").toString(), + attr.value("enabled").toString() == "true"); + + if (attr.hasAttribute("parent")) + l.setParent(attr.value("parent").toString()); while (reader.readNextStartElement()) { - if (enabled && reader.name() == QLatin1String("cat")) - cat(reader, cats); + if (reader.name() == QLatin1String("cat")) + l.addCat(cat(reader)); + else if (reader.name() == QLatin1String("overlay")) + l.addOverlay(cat(reader)); else reader.skipCurrentElement(); } + + return l; } -void Style::stylemenu(QXmlStreamReader &reader, QSet &cats) +Style::Menu Style::stylemenu(QXmlStreamReader &reader) { + const QXmlStreamAttributes &attr = reader.attributes(); + if (!attr.hasAttribute("defaultvalue")) { + reader.raiseError("Missing defaultvalue attribute"); + return Menu(); + } + + Style::Menu menu(attr.value("defaultvalue").toString()); + while (reader.readNextStartElement()) { if (reader.name() == QLatin1String("layer")) - layer(reader, cats); + menu.addLayer(layer(reader)); else reader.skipCurrentElement(); } + + return menu; } void Style::rendertheme(QXmlStreamReader &reader, const QString &dir, @@ -540,9 +605,10 @@ void Style::rendertheme(QXmlStreamReader &reader, const QString &dir, while (reader.readNextStartElement()) { if (reader.name() == QLatin1String("rule")) rule(reader, dir, data, ratio, cats, r); - else if (reader.name() == QLatin1String("stylemenu")) - stylemenu(reader, cats); - else + else if (reader.name() == QLatin1String("stylemenu")) { + Menu menu(stylemenu(reader)); + cats = menu.cats(); + } else reader.skipCurrentElement(); } } diff --git a/src/map/mapsforge/style.h b/src/map/mapsforge/style.h index bff58dde..e2507e94 100644 --- a/src/map/mapsforge/style.h +++ b/src/map/mapsforge/style.h @@ -238,6 +238,46 @@ public: QList areaSymbols(int zoom) const; private: + class Menu { + public: + class Layer { + public: + Layer() : _enabled(false) {} + Layer(const QString &id, bool enabled) + : _id(id), _enabled(enabled) {} + + const QStringList &cats() const {return _cats;} + const QStringList &overlays() const {return _overlays;} + const QString &id() const {return _id;} + const QString &parent() const {return _parent;} + bool enabled() const {return _enabled;} + + void setParent(const QString &parent) {_parent = parent;} + void addCat(const QString &cat) {_cats.append(cat);} + void addOverlay(const QString &overlay) {_overlays.append(overlay);} + + private: + QStringList _cats; + QStringList _overlays; + QString _id; + QString _parent; + bool _enabled; + }; + + Menu() {} + Menu(const QString &defaultValue) : _defaultvalue(defaultValue) {} + + void addLayer(const Layer &layer) {_layers.append(layer);} + QSet cats() const; + + private: + const Layer *findLayer(const QString &id) const; + void addCats(const Layer *layer, QSet &cats) const; + + QString _defaultvalue; + QList _layers; + }; + QList _paths; QList _circles; QList _pathLabels, _pointLabels, _areaLabels; @@ -246,9 +286,9 @@ private: bool loadXml(const QString &path, const MapData &data, qreal ratio); void rendertheme(QXmlStreamReader &reader, const QString &dir, const MapData &data, qreal ratio); - void layer(QXmlStreamReader &reader, QSet &cats); - void stylemenu(QXmlStreamReader &reader, QSet &cats); - void cat(QXmlStreamReader &reader, QSet &cats); + Menu::Layer layer(QXmlStreamReader &reader); + Menu stylemenu(QXmlStreamReader &reader); + QString cat(QXmlStreamReader &reader); void rule(QXmlStreamReader &reader, const QString &dir, const MapData &data, qreal ratio, const QSet &cats, const Rule &parent); void area(QXmlStreamReader &reader, const QString &dir, qreal ratio, -- 2.11.4.GIT