KOSMIndoorMap

indoormap.qml
1/*
2 SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7import QtCore
8import QtQuick
9import QtQuick.Layouts
10import QtQuick.Controls as QQC2
11import QtQuick.Dialogs as Dialogs
12import org.kde.kirigami as Kirigami
13import org.kde.kpublictransport as PublicTransport
14import org.kde.kosmindoormap
15import org.kde.kosmindoormap.kpublictransport
16import org.kde.osm.editorcontroller
17import org.kde.kirigamiaddons.formcard as FormCard
18
19Kirigami.ApplicationWindow {
20 globalDrawer: Kirigami.GlobalDrawer {
21 title: "Indoor Map"
22 titleIcon: "map-symbolic"
23 isMenu: true
24 actions: [
25 Kirigami.Action {
26 text: "Open O5M File"
27 icon.name: "document-open-symbolic"
28 onTriggered: fileDialog.open()
29 },
30 Kirigami.Action {
31 text: "Open MapCSS Stylesheet"
32 icon.name: "document-open-symbolic"
33 onTriggered: mapcssDialog.open()
34 },
35 Kirigami.Action {
36 text: "Reload Stylesheet"
37 icon.name: "view-refresh-symbolic"
38 shortcut: "F5"
39 onTriggered: {
40 var s = page.map.styleSheet;
41 page.map.styleSheet = "";
42 page.map.styleSheet = s;
43 }
44 },
45 Kirigami.Action { separator: true },
46 Kirigami.Action {
47 text: "Data Sources"
48 icon.name: "help-about-symbolic"
49 onTriggered: function() { applicationWindow().pageStack.push(attributionPage); }
50 },
51 Kirigami.Action {
52 id: aboutAction
53 text: "About"
54 icon.name: "help-about-symbolic"
55 onTriggered: function() { applicationWindow().pageStack.push(aboutPage); }
56 }
57 ]
58 }
59 contextDrawer: Kirigami.ContextDrawer {
60 id: contextDrawer
61 }
62
63 Dialogs.FileDialog {
64 id: fileDialog
65 title: "Open OSM File"
66 fileMode: Dialogs.FileDialog.OpenFile
67 nameFilters: ["o5m file (*.o5m)", "OSM XML file (*.osm *.xml)", "PBF file (*.osm.pbf)"]
68 onAccepted: page.map.mapLoader.loadFromFile(fileDialog.selectedFile);
69 }
70 Dialogs.FileDialog {
71 id: mapcssDialog
72 title: "Open MapCSS Stylesheet"
73 fileMode: Dialogs.FileDialog.OpenFile
74 nameFilters: ["MapCSS stylesheet (*.mapcss)"]
75 onAccepted: page.map.styleSheet = mapcssDialog.selectedFile
76 }
77 PublicTransport.Manager { id: ptMgr }
78 Settings {
79 id: settings
80 property alias debugMode: debugAction.checked
81 property alias stylesheet: page.map.styleSheet
82 property alias hoverMode: page.mapHoverEnabled
83 }
84
85 pageStack.initialPage: IndoorMapPage {
86 id: page
87 debug: debugAction.checked
88
89 actions: [
90 Kirigami.Action {
91 text: "Select Location"
92 icon.name: "search"
93 onTriggered: locationSheet.open()
94 },
95 Kirigami.Action {
96 text: "Light Style"
97 onTriggered: page.map.styleSheet = "breeze-light"
98 },
99 Kirigami.Action {
100 text: "Dark Style"
101 onTriggered: page.map.styleSheet = "breeze-dark"
102 },
103 Kirigami.Action {
104 text: "Diagnostic View"
105 onTriggered: page.map.styleSheet = "diagnostic"
106 },
107 Kirigami.Action {
108 id: debugAction
109 text: "Debug Info Model"
110 checkable: true
111 checked: false
112 },
113 Kirigami.Action {
114 id: platformAction
115 text: "Find Platform"
116 onTriggered: platformSheet.open()
117 visible: !platformModel.isEmpty
118 },
119 Kirigami.Action {
120 id: gateAction
121 text: "Find Gate"
122 onTriggered: gateSheet.open()
123 visible: !gateModel.isEmpty
124 },
125 Kirigami.Action {
126 id: amenityAction
127 text: "Find Amenity"
128 onTriggered: amenitySheet.open()
129 },
130 Kirigami.Action {
131 id: equipmentAction
132 text: "Show Elevator Status"
133 checkable: true
134 enabled: !page.map.mapLoader.isLoading
135 onTriggered: page.queryLiveLocationData();
136 },
137 Kirigami.Action {
138 id: rentalVehicleAction
139 text: i18n("Show Rental Vehicles")
140 checkable: true
141 enabled: !page.map.mapLoader.isLoading
142 onTriggered: page.queryLiveLocationData();
143 },
145 text: i18n("Edit with iD")
146 icon.name: "document-edit"
147 onTriggered: EditorController.editBoundingBox(page.map.view.mapSceneToGeo(page.map.view.viewport), Editor.ID)
148 },
150 text: i18n("Edit with JOSM")
151 icon.name: "org.openstreetmap.josm"
152 visible: EditorController.hasEditor(Editor.JOSM)
153 onTriggered: EditorController.editBoundingBox(page.map.view.mapSceneToGeo(page.map.view.viewport), Editor.JOSM)
154 },
156 text: i18n("Edit with Vespucci")
157 icon.name: "document-edit"
158 visible: EditorController.hasEditor(Editor.Vespucci)
159 onTriggered: EditorController.editBoundingBox(page.map.view.mapSceneToGeo(page.map.view.viewport), Editor.Vespucci)
160 },
162 text: i18n("Enable hover selection")
163 icon.name: "followmouse"
164 checkable: true
165 checked: page.mapHoverEnabled
166 onToggled: page.mapHoverEnabled = !page.mapHoverEnabled
167 }
168 ]
169
170 function queryLiveLocationData() {
171 if (rentalVehicleAction.checked || equipmentAction.checked) {
172 locationQuery.request.latitude = map.mapData.center.y;
173 locationQuery.request.longitude = map.mapData.center.x;
174 locationQuery.request.maximumDistance = map.mapData.radius;
175 locationQuery.request.types =
176 (rentalVehicleAction.checked ? (PublicTransport.Location.RentedVehicleStation | PublicTransport.Location.RentedVehicle) : 0)
177 | (equipmentAction.checked ? PublicTransport.Location.Equipment : 0);
178 } else {
179 locationQuery.clear();
180 }
181 }
182
183 PlatformModel {
184 id: platformModel
185 mapData: page.map.mapData
186 }
187
188 Component {
189 id: platformDelegate
190 QQC2.ItemDelegate {
191 property var platform: model
192 width: ListView.view.width
193 contentItem: Row {
194 QQC2.Label { text: platform.lines.length == 0 ? platform.display : (platform.display + " - "); }
195 Repeater {
196 model: platform.lines
197 delegate: Row {
198 Kirigami.Icon {
199 id: icon
200 height: Kirigami.Units.iconSizes.small
201 width: implicitWidth
202 visible: source != ""
203 source: {
204 switch (platform.mode) {
205 case Platform.Rail:
206 return PublicTransport.LineMetaData.lookup(modelData, platform.coordinate.y, platform.coordinate.x, PublicTransport.Line.Train, true).logo;
207 case Platform.Tram:
208 return PublicTransport.LineMetaData.lookup(modelData, platform.coordinate.y, platform.coordinate.x, PublicTransport.Line.Tramway, true).logo;
209 case Platform.Subway:
210 return PublicTransport.LineMetaData.lookup(modelData, platform.coordinate.y, platform.coordinate.x, PublicTransport.Line.Metro, true).logo;
211 }
212 return "";
213 }
214 }
215 QQC2.Label {
216 text: modelData + " "
217 visible: icon.source == ""
218 }
219 }
220 }
221 }
222 highlighted: false
223 onClicked: {
224 page.map.view.floorLevel = model.level
225 page.map.view.centerOnGeoCoordinate(model.coordinate);
226 page.map.view.setZoomLevel(19, Qt.point(page.map.width / 2.0, page.map.height/ 2.0));
227 platformSheet.close()
228 }
229 }
230 }
231
232 Kirigami.OverlaySheet {
233 id: platformSheet
234
235 header: Kirigami.Heading {
236 text: "Find Platform"
237 }
238
239 ListView {
240 model: platformModel
241 clip: true
242 Layout.preferredWidth: Kirigami.Units.gridUnit * 25
243
244 section.property: "mode"
245 section.delegate: Kirigami.ListSectionHeader {
246 label: switch(parseInt(section)) {
247 case Platform.Rail: return "Railway";
248 case Platform.Subway: return "Subway";
249 case Platform.Tram: return "Tramway";
250 case Platform.Bus: return "Bus";
251 default: console.log(section, Platform.Rail); return section;
252 }
253 width: ListView.view.width
254 }
255 section.criteria: ViewSection.FullString
256
257 delegate: platformDelegate
258 }
259 }
260
261 GateModel {
262 id: gateModel
263 mapData: page.map.mapData
264 }
265
266 Kirigami.OverlaySheet {
267 id: gateSheet
268
269 header: Kirigami.Heading {
270 text: "Find Gate"
271 }
272
273 ListView {
274 model: gateModel
275 Layout.preferredWidth: Kirigami.Units.gridUnit * 10
276 delegate: QQC2.ItemDelegate {
277 highlighted: false
278 width: ListView.view.width
279 contentItem: Kirigami.TitleSubtitle {
280 title: model.display
281 }
282 onClicked: {
283 page.map.view.floorLevel = model.level
284 page.map.view.centerOnGeoCoordinate(model.coordinate);
285 page.map.view.setZoomLevel(18, Qt.point(page.map.width / 2.0, page.map.height/ 2.0));
286 gateSheet.close();
287 }
288 }
289 }
290 }
291
292 AmenityModel {
293 id: amenityModel
294 mapData: page.map.mapData
295 }
296
297 Kirigami.OverlaySheet {
298 id: amenitySheet
299 header: Kirigami.Heading {
300 text: "Find Amenity"
301 }
302
303 ListView {
304 clip: true
305 Layout.preferredWidth: Kirigami.Units.gridUnit * 25
306 model: AmenitySortFilterProxyModel {
307 sourceModel: amenitySheet.visible ? amenityModel : null
308 filterCaseSensitivity: Qt.CaseInsensitive
309 filterString: amenitySearchField.text
310 }
311
312 delegate: IndoorMapAmenityDelegate {
313 id: item
314 mapData: page.map.mapData
315 required property QtObject model
316 onClicked: {
317 page.map.view.floorLevel = item.model.level
318 page.map.view.centerOnGeoCoordinate(item.model.coordinate);
319 page.map.view.setZoomLevel(21, Qt.point(page.map.width / 2.0, page.map.height/ 2.0));
320 console.log(item.model.element.url);
321 amenitySheet.close();
322 }
323 }
324
325 section.property: "groupName"
326 section.delegate: Kirigami.ListSectionHeader {
327 label: section
328 width: ListView.view.width
329 }
330 }
331
332 footer: Kirigami.SearchField {
333 id: amenitySearchField
334 focus: true
335 }
336 onOpened: amenitySearchField.clear()
337 }
338
339 LocationQueryOverlayProxyModel {
340 id: locationModel
341 sourceModel: PublicTransport.LocationQueryModel {
342 id: locationQuery
343 manager: ptMgr
344 }
345 mapData: page.map.mapData
346 }
347
348 RealtimeEquipmentModel {
349 id: equipmentModel
350 mapData: page.map.mapData
351 realtimeModel: locationModel.sourceModel
352 }
353
354 SelectLocationSheet {
355 id: locationSheet
356 publicTransportManager: ptMgr
357 onCoordinateSelected: function() {
358 page.map.mapLoader.loadForCoordinate(locationSheet.coordinate.y, locationSheet.coordinate.x);
359 page.map.view.beginTime = new Date();
360 page.map.view.endTime = new Date(page.map.view.beginTime.getTime() + 3600000);
361 // TODO timezone
362
363 settings.setValue("latitude", locationSheet.coordinate.y);
364 settings.setValue("longitude", locationSheet.coordinate.x);
365 }
366 }
367
368 map.overlaySources: [ gateModel, platformModel, locationModel, equipmentModel ]
369 map.timeZone: "Europe/Berlin"
370
371 header: RowLayout {
372 QQC2.Label { text: "Floor Level:" }
373 QQC2.ComboBox {
374 id: floorLevelCombo
375 model: page.map.floorLevels
376 textRole: "display"
377 currentIndex: page.map.floorLevels.rowForLevel(page.map.view.floorLevel);
378 onCurrentIndexChanged: if (currentIndex >= 0) { page.map.view.floorLevel = page.map.floorLevels.levelForRow(currentIndex); }
379 Layout.fillWidth: true
380 }
381 Connections {
382 target: page.map.view
383 function onFloorLevelChanged() { floorLevelCombo.currentIndex = page.map.floorLevels.rowForLevel(page.map.view.floorLevel); }
384 }
385
386 QQC2.Slider {
387 id: zoomSlider
388 from: 14.0
389 to: 21.0
390 live: true
391 Layout.fillWidth: true
392
393 onValueChanged: {
394 page.map.view.setZoomLevel(value, Qt.point(page.map.width / 2.0, page.map.height/ 2.0));
395 }
396 }
397 Connections {
398 target: page.map.view
399 function onZoomLevelChanged() { zoomSlider.value = page.map.view.zoomLevel; }
400 }
401 }
402
403 coordinate: Qt.point(settings.value("longitude", 11.08196), settings.value("latitude", 49.44572))
404 }
405
406 Connections {
407 target: page.map
408 function onMapDataChanged() {
409 page.queryLiveLocationData();
410 }
411 }
412
413 Component {
414 id: attributionPage
415 AttributionPage {
416 publicTransportManager: ptMgr
417 }
418 }
419
420 Component {
421 id: aboutPage
422 FormCard.AboutPage {
423 aboutData: {
424 "displayName": "KDE OSM Indoor Map",
425 "productName": "org.kde.kosmindoormap",
426 "componentName": "org.kde.kosmindoormap",
427 "shortDescription": "OSM Indoor Map Demo",
428 "homepage": "https://kde.org/",
429 "bugAddress": "submit@bugs.kde.org",
430 "version": Application.version,
431 "licenses": [
432 {
433 "name": "LGPL 2.0 or later",
434 "spdx": "LGPL-2.0-or-later"
435 }
436 ],
437 "copyrightStatement": "© 2020-2024 The KDE Community",
438 "desktopFileName": "org.kde.kosmindoormap",
439 "otherText": ""
440 }
441 }
442 }
443}
QString i18n(const char *text, const TYPE &arg...)
const QList< QKeySequence > & shortcut(StandardShortcut id)
QFuture< void > map(Iterator begin, Iterator end, MapFunctor &&function)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:20:03 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.