KOSMIndoorMap

floorlevelchangemodel.cpp
1 /*
2  SPDX-FileCopyrightText: 2020 Volker Krause <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "floorlevelchangemodel.h"
8 
9 #include "loader/levelparser_p.h"
10 #include <KOSMIndoorMap/MapData>
11 
12 #include <QDebug>
13 
14 using namespace KOSMIndoorMap;
15 
16 FloorLevelChangeModel::FloorLevelChangeModel(QObject *parent)
17  : QAbstractListModel(parent)
18 {
19 }
20 
21 FloorLevelChangeModel::~FloorLevelChangeModel() = default;
22 
23 int FloorLevelChangeModel::rowCount(const QModelIndex &parent) const
24 {
25  if (parent.isValid()) {
26  return 0;
27  }
28  return m_levels.size();
29 }
30 
31 QVariant FloorLevelChangeModel::data(const QModelIndex &index, int role) const
32 {
33  if (!index.isValid()) {
34  return {};
35  }
36 
37  switch (role) {
38  case Qt::DisplayRole:
39  return m_levels[index.row()].name();
40  case FloorLevelRole:
41  return m_levels[index.row()].numericLevel();
42  case CurrentFloorRole:
43  return m_levels[index.row()].numericLevel() == m_currentFloorLevel;
44  }
45  return {};
46 }
47 
48 QHash<int, QByteArray> FloorLevelChangeModel::roleNames() const
49 {
51  n.insert(FloorLevelRole, "floorLevel");
52  n.insert(CurrentFloorRole, "isCurrentFloor");
53  return n;
54 }
55 
56 int FloorLevelChangeModel::currentFloorLevel() const
57 {
58  return m_currentFloorLevel;
59 }
60 
61 void FloorLevelChangeModel::setCurrentFloorLevel(int level)
62 {
63  if (m_currentFloorLevel == level) {
64  return;
65  }
66  m_currentFloorLevel = level;
67  if (!m_levels.empty()) {
68  Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, 0));
69  }
70  Q_EMIT contentChanged();
71 }
72 
73 FloorLevelModel* FloorLevelChangeModel::floorLevelModel() const
74 {
75  return m_floorLevelModel;
76 }
77 
78 void FloorLevelChangeModel::setFloorLevelModel(FloorLevelModel *floorLevelModel)
79 {
80  if (m_floorLevelModel == floorLevelModel) {
81  return;
82  }
83 
84  m_floorLevelModel = floorLevelModel;
85  Q_EMIT contentChanged();
86 }
87 
88 OSMElement FloorLevelChangeModel::element() const
89 {
90  return OSMElement(m_element);
91 }
92 
93 void FloorLevelChangeModel::setElement(const OSMElement &element)
94 {
95  if (m_element == element.element()) {
96  return;
97  }
98 
99  beginResetModel();
100  m_element = element.element();
101  m_levels.clear();
102 
103  if (isLevelChangeElement(m_element)) {
104 
105  // elevators are sometimes also tagged with building:level tags instead of level/repeat_on, so handle that as well
106  const auto buildingLevels = m_element.tagValue("building:levels").toUInt();
107  if (buildingLevels > 0) {
108  const auto buildingMinLevel = m_element.tagValue("building:min_level", "level").toUInt();
109  for (auto i = buildingMinLevel; i < buildingLevels; ++i) {
110  appendFullFloorLevel(i * 10);
111  }
112  }
113  const auto buildingUndergroundLevel = m_element.tagValue("building:levels:underground").toUInt();
114  for (auto i = buildingUndergroundLevel; i > 0; --i) {
115  appendFullFloorLevel(-i * 10);
116  }
117 
118  LevelParser::parse(m_element.tagValue("level", "repeat_on"), m_element, [this](int level, OSM::Element e) {
119  Q_UNUSED(e);
120  appendFloorLevel(level);
121 
122  });
123  std::sort(m_levels.begin(), m_levels.end());
124  m_levels.erase(std::unique(m_levels.begin(), m_levels.end()), m_levels.end());
125  }
126 
127  endResetModel();
128  Q_EMIT contentChanged();
129 }
130 
131 bool FloorLevelChangeModel::isLevelChangeElement(OSM::Element element) const
132 {
133  return !element.tagValue("highway").isEmpty()
134  || !element.tagValue("elevator").isEmpty()
135  || !element.tagValue("stairwell").isEmpty()
136  || element.tagValue("building:part") == "elevator"
137  || element.tagValue("building") == "elevator"
138  || element.tagValue("room") == "elevator"
139  || element.tagValue("levelpart") == "elevator_platform";
140 }
141 
142 void FloorLevelChangeModel::appendFloorLevel(int level)
143 {
144  MapLevel ml(level);
145  if (ml.isFullLevel()) {
146  appendFullFloorLevel(level);
147  } else {
148  appendFullFloorLevel(ml.fullLevelBelow());
149  appendFullFloorLevel(ml.fullLevelAbove());
150  }
151 }
152 
153 void FloorLevelChangeModel::appendFullFloorLevel(int level)
154 {
155  if (!m_floorLevelModel) {
156  m_levels.push_back(MapLevel(level));
157  } else {
158  const auto row = m_floorLevelModel->rowForLevel(level);
159  if (row >= 0) {
160  const auto idx = m_floorLevelModel->index(row, 0);
161  m_levels.push_back(m_floorLevelModel->data(idx, FloorLevelModel::MapLevelRole).value<MapLevel>());
162  }
163  }
164 }
165 
166 bool FloorLevelChangeModel::hasSingleLevelChange() const
167 {
168  if (m_levels.size() != 2) {
169  return false;
170  }
171  return m_levels[0].numericLevel() == m_currentFloorLevel || m_levels[1].numericLevel() == m_currentFloorLevel;
172 }
173 
174 int FloorLevelChangeModel::destinationLevel() const
175 {
176  if (m_levels.size() != 2) {
177  return 0;
178  }
179  return m_levels[0].numericLevel() == m_currentFloorLevel ? m_levels[1].numericLevel() : m_levels[0].numericLevel();
180 }
181 
182 QString FloorLevelChangeModel::destinationLevelName() const
183 {
184  if (m_levels.size() != 2) {
185  return {};
186  }
187  return m_levels[0].numericLevel() == m_currentFloorLevel ? m_levels[1].name() : m_levels[0].name();
188 }
189 
190 bool FloorLevelChangeModel::hasMultipleLevelChanges() const
191 {
192  return m_levels.size() > 1;
193 }
OSM-based multi-floor indoor maps for buildings.
QML wrapper around an OSM element.
Definition: osmelement.h:18
uint toUInt(bool *ok, int base) const const
virtual QHash< int, QByteArray > roleNames() const const
int size() const const
bool isEmpty() const const
A floor level.
Definition: mapdata.h:27
bool isValid() const const
A reference to any of OSM::Node/OSMWay/OSMRelation.
Definition: element.h:22
DisplayRole
int row() const const
QObject * parent() const const
Q_EMITQ_EMIT
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Sep 25 2021 23:05:04 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.