Warning, /libraries/kpublictransport/tests/journeyquery.qml is written in an unsupported language. File is not indexed.
0001 /*
0002 SPDX-FileCopyrightText: 2018 Volker Krause <vkrause@kde.org>
0003
0004 SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006
0007 import QtCore
0008 import QtQuick
0009 import QtQuick.Layouts
0010 import QtQuick.Controls as QQC2
0011 import QtQuick.Dialogs as Dialogs
0012 import org.kde.kirigami as Kirigami
0013 import org.kde.kpublictransport
0014 import org.kde.example
0015
0016 Kirigami.ApplicationWindow {
0017 title: "Journey Query"
0018 width: 640
0019 height: 800
0020
0021 pageStack.initialPage: journyQueryPage
0022
0023 Manager {
0024 id: ptMgr;
0025 }
0026 Settings {
0027 id: settings
0028 property alias allowInsecureBackends: ptMgr.allowInsecureBackends
0029 property alias enabledBackends: ptMgr.enabledBackends
0030 property alias disabledBackends: ptMgr.disabledBackends
0031 }
0032
0033 JourneyQueryModel {
0034 id: journeyModel
0035 manager: ptMgr
0036 }
0037
0038 JourneyTitleModel {
0039 id: titleModel
0040 sourceModel: journeyModel
0041 }
0042
0043 globalDrawer: Kirigami.GlobalDrawer {
0044 actions: [
0045 Kirigami.Action {
0046 text: "Save..."
0047 icon.name: "document-save"
0048 onTriggered: fileDialog.open();
0049 },
0050 Kirigami.Action {
0051 icon.name: "help-about-symbolic"
0052 text: "Current Data Sources"
0053 enabled: journeyModel.attributions.length > 0
0054 onTriggered: {
0055 aboutSheet.attributions = Qt.binding(function() { return journeyModel.attributions; });
0056 aboutSheet.open();
0057 }
0058 },
0059 Kirigami.Action {
0060 icon.name: "help-about-symbolic"
0061 text: "All Data Sources"
0062 onTriggered: {
0063 aboutSheet.attributions = Qt.binding(function() { return ptMgr.attributions; });
0064 aboutSheet.open();
0065 }
0066 },
0067 Kirigami.Action {
0068 icon.name: "settings-configure"
0069 text: "Backends"
0070 onTriggered: pageStack.push(backendPage)
0071 }
0072 ]
0073 }
0074
0075 Dialogs.FileDialog {
0076 id: fileDialog
0077 title: "Save Journey Data"
0078 fileMode: Dialogs.FileDialog.SaveFile
0079 nameFilters: ["JSON files (*.json)"]
0080 onAccepted: ExampleUtil.saveTo(journeyModel, fileDialog.selectedFile);
0081 }
0082
0083 TestLocationsModel { id: exampleModel }
0084 AttributionSheet { id: aboutSheet }
0085 LocationDetailsSheet { id:locationDetailsSheet }
0086
0087 function displayDuration(dur)
0088 {
0089 if (dur < 60)
0090 return "<1min";
0091 if (dur < 3600)
0092 return Math.floor(dur/60) + "min";
0093 return Math.floor(dur/3600) + ":" + Math.floor((dur % 3600)/60)
0094 }
0095
0096 function displayDistance(dist)
0097 {
0098 if (dist == 0)
0099 return "";
0100 if (dist < 1000)
0101 return dist + "m";
0102 return Math.floor(dist/1000) + "km";
0103 }
0104
0105 function locationName(loc)
0106 {
0107 switch(loc.type) {
0108 case Location.Stop: return "🚏 " + loc.name;
0109 case Location.RentedVehicleStation: return "🚏🚲 " + loc.name;
0110 case Location.RentedVehicle: return "🚲 " + loc.name;
0111 case Location.Place: return loc.name;
0112 }
0113 }
0114
0115 Component {
0116 id: vehicleLayoutPage
0117 VehicleLayoutPage {
0118 publicTransportManager: ptMgr
0119 }
0120 }
0121
0122 Component {
0123 id: indoorMapPage
0124 IndoorMapPage {}
0125 }
0126
0127 Component {
0128 id: journeyDelegate
0129 QQC2.ItemDelegate {
0130 enabled: modelData.disruptionEffect != Disruption.NoService
0131 highlighted: false
0132 width: ListView.view.width
0133 contentItem: RowLayout {
0134 id: topLayout
0135
0136 Kirigami.Icon {
0137 id: icon
0138 source: modelData.route.line.hasLogo ? modelData.route.line.logo : modelData.route.line.modeLogo
0139 width: height
0140 height: Kirigami.Units.iconSizes.large
0141 visible: source != ""
0142 }
0143
0144 Rectangle {
0145 id: colorBar
0146 width: Kirigami.Units.largeSpacing
0147 color: modelData.route.line.hasColor ? modelData.route.line.color : "transparent"
0148 Layout.fillHeight: true
0149 visible: icon.source == ""
0150 }
0151
0152 QQC2.Label {
0153 text: {
0154 switch (modelData.mode) {
0155 case JourneySection.PublicTransport:
0156 {
0157 switch (modelData.route.line.mode) {
0158 case Line.Air: return "✈️";
0159 case Line.Boat: return "🛥️";
0160 case Line.Bus: return "🚍";
0161 case Line.BusRapidTransit: return "🚌";
0162 case Line.Coach: return "🚌";
0163 case Line.Ferry: return "⛴️";
0164 case Line.Funicular: return "🚞";
0165 case Line.LocalTrain: return "🚆";
0166 case Line.LongDistanceTrain: return "🚄";
0167 case Line.Metro: return "🚇";
0168 case Line.RailShuttle: return "🚅";
0169 case Line.RapidTransit: return "🚊";
0170 case Line.Shuttle: return "🚐";
0171 case Line.Taxi: return "🚕";
0172 case Line.Train: return "🚆";
0173 case Line.Tramway: return "🚈";
0174 case Line.RideShare: return "🚗";
0175 default: return "?";
0176 }
0177 break;
0178 }
0179 case JourneySection.Walking: return "🚶";
0180 case JourneySection.Waiting: return "⌛";
0181 case JourneySection.Transfer: return "⇄";
0182 case JourneySection.RentedVehicle:
0183 {
0184 switch (modelData.rentalVehicle.type) {
0185 case RentalVehicle.Bicycle: return "🔑🚲";
0186 case RentalVehicle.Pedelec: return "🔑🔌🚲";
0187 case RentalVehicle.ElectricKickScooter: return "🔑🛴";
0188 case RentalVehicle.ElectricMoped: return "🔑🛵";
0189 case RentalVehicle.Car: return "🔑🚗";
0190 default: return "?";
0191 }
0192 }
0193 case JourneySection.IndividualTransport:
0194 {
0195 switch (modelData.individualTransport.mode) {
0196 case IndividualTransport.Walk: return "🚶";
0197 case IndividualTransport.Bike: return "🚲";
0198 case IndividualTransport.Car: return "🚗";
0199 }
0200 }
0201 default: return "?";
0202 }
0203 }
0204 font.pointSize: Kirigami.Theme.defaultFont.pointSize * 2
0205 visible: icon.source == ""
0206 }
0207
0208 ColumnLayout {
0209 Layout.fillWidth: true
0210 RowLayout {
0211 QQC2.Label {
0212 text: "From: <a href=\"#from\">" + locationName(modelData.from) + "</a> Platform: " + modelData.scheduledDeparturePlatform
0213 onLinkActivated: {
0214 locationDetailsSheet.location = modelData.from;
0215 locationDetailsSheet.open();
0216 }
0217 }
0218 QQC2.Label {
0219 text: modelData.expectedDeparturePlatform
0220 color: modelData.departurePlatformChanged ? Kirigami.Theme.negativeTextColor : Kirigami.Theme.positiveTextColor
0221 visible: modelData.hasExpectedDeparturePlatform
0222 }
0223 }
0224 RowLayout {
0225 QQC2.Label {
0226 text: "Departure: " + modelData.scheduledDepartureTime.toTimeString()
0227 }
0228 QQC2.Label {
0229 text: (modelData.departureDelay >= 0 ? "+" : "") + modelData.departureDelay
0230 color: modelData.departureDelay > 1 ? Kirigami.Theme.negativeTextColor : Kirigami.Theme.positiveTextColor
0231 visible: modelData.hasExpectedDepartureTime
0232 }
0233 QQC2.Label {
0234 text: "<a href=\"#layout\">vehicle</a>"
0235 visible: modelData.route.line.mode == Line.LongDistanceTrain || modelData.route.line.mode == Line.Train || modelData.route.name !== ""
0236 onLinkActivated: applicationWindow().pageStack.push(vehicleLayoutPage, {"departure": modelData.departure });
0237 Layout.fillWidth: true
0238 horizontalAlignment: Text.Right
0239 }
0240 }
0241 QQC2.Label {
0242 Layout.fillWidth: true
0243 text: {
0244 switch (modelData.mode) {
0245 case JourneySection.PublicTransport:
0246 {
0247 if (modelData.route.name !== "") {
0248 return modelData.route.line.modeString + " " + modelData.route.line.name + " (" + modelData.route.name
0249 + ") " + displayDuration(modelData.duration) + " / " + displayDistance(modelData.distance)
0250 }
0251 return modelData.route.line.modeString + " " + modelData.route.line.name + " " + displayDuration(modelData.duration) + " / " + displayDistance(modelData.distance)
0252 }
0253 case JourneySection.Walking:
0254 return "Walk " + displayDuration(modelData.duration) + " / " + displayDistance(modelData.distance)
0255 case JourneySection.Transfer:
0256 return "Transfer " + displayDuration(modelData.duration) + " / " + displayDistance(modelData.distance)
0257 case JourneySection.Waiting:
0258 return "Wait " + displayDuration(modelData.duration)
0259 case JourneySection.RentedVehicle:
0260 return "Drive (" + modelData.rentalVehicle.network.name + ") " + displayDuration(modelData.duration) + " / " + displayDistance(modelData.distance);
0261 case JourneySection.IndividualTransport:
0262 return "Drive " + displayDuration(modelData.duration) + " / " + displayDistance(modelData.distance)
0263 return "???";
0264 }}
0265 }
0266 RowLayout {
0267 QQC2.Label {
0268 text: "To: <a href=\"#to\">" + locationName(modelData.to) + "</a> Platform: " + modelData.scheduledArrivalPlatform
0269 onLinkActivated: {
0270 locationDetailsSheet.location = modelData.to;
0271 locationDetailsSheet.open();
0272 }
0273 }
0274 QQC2.Label {
0275 text: modelData.expectedArrivalPlatform
0276 color: modelData.arrivalPlatformChanged ? Kirigami.Theme.negativeTextColor : Kirigami.Theme.positiveTextColor
0277 visible: modelData.hasExpectedArrivalPlatform
0278 }
0279 }
0280 RowLayout {
0281 QQC2.Label {
0282 text: "Arrival: " + modelData.scheduledArrivalTime.toTimeString()
0283 }
0284 QQC2.Label {
0285 text: (modelData.arrivalDelay >= 0 ? "+" : "") + modelData.arrivalDelay
0286 color: modelData.arrivalDelay > 1 ? Kirigami.Theme.negativeTextColor : Kirigami.Theme.positiveTextColor
0287 visible: modelData.hasExpectedArrivalTime
0288 }
0289 QQC2.Label {
0290 text: "<a href=\"#layout\">vehicle</a>"
0291 visible: modelData.route.line.mode == Line.LongDistanceTrain
0292 onLinkActivated: applicationWindow().pageStack.push(vehicleLayoutPage, {"departure": modelData.arrival });
0293 Layout.fillWidth: true
0294 horizontalAlignment: Text.Right
0295 }
0296 }
0297 RowLayout {
0298 visible: modelData.loadInformation.length > 0
0299 QQC2.Label {
0300 text: "Load: ";
0301 }
0302 Repeater {
0303 model: modelData.loadInformation
0304 RowLayout {
0305 QQC2.Label {
0306 text: {
0307 switch (modelData.load) {
0308 case Load.Low: return "Low";
0309 case Load.Medium: return "Medium";
0310 case Load.High: return "High";
0311 case Load.Full: return "Full";
0312 default: return "?"
0313 }
0314 }
0315 color: {
0316 switch (modelData.load) {
0317 case Load.Low: return Kirigami.Theme.positiveTextColor;
0318 case Load.Medium: return Kirigami.Theme.neutralTextColor;
0319 case Load.High:
0320 case Load.Full:
0321 return Kirigami.Theme.negativeTextColor;
0322 default:
0323 return Kirigami.Theme.textColor;
0324 }
0325 }
0326 }
0327 QQC2.Label {
0328 text: "(class " + modelData.seatingClass + ")"
0329 visible: modelData.seatingClass != ""
0330 }
0331 }
0332 }
0333 }
0334 QQC2.Label {
0335 text: modelData.notes.join("<br/>")
0336 textFormat: Text.RichText
0337 visible: modelData.notes.length > 0
0338 font.italic: true
0339 }
0340 }
0341 }
0342 onClicked: {
0343 if (modelData.mode == JourneySection.PublicTransport) {
0344 applicationWindow().pageStack.push(journeySectionPage, {"journeySection": modelData});
0345 } else if (modelData.path.sectionCount > 1) {
0346 applicationWindow().pageStack.push(pathPage, {"path": modelData.path});
0347 }
0348 }
0349 }
0350 }
0351
0352 Component {
0353 id: backendPage
0354 BackendPage {
0355 publicTransportManager: ptMgr
0356 }
0357 }
0358
0359 Component {
0360 id: journeySectionPage
0361 JourneySectionPage {}
0362 }
0363
0364 Component {
0365 id: pathPage
0366 PathPage {}
0367 }
0368
0369 readonly property var individualTransportModes: [
0370 [{ mode: IndividualTransport.Walk }],
0371 [{ mode: IndividualTransport.Bike }],
0372 [{ mode: IndividualTransport.Bike, qualifier: IndividualTransport.Park }],
0373 [{ mode: IndividualTransport.Bike, qualifier: IndividualTransport.Rent }],
0374 [{ mode: IndividualTransport.Car, qualifier: IndividualTransport.Park }],
0375 [{ mode: IndividualTransport.Car, qualifier: IndividualTransport.Rent }],
0376 [{ mode: IndividualTransport.Car, qualifier: IndividualTransport.Pickup }],
0377 [{ mode: IndividualTransport.Car, qualifier: IndividualTransport.Dropoff }],
0378 ]
0379 ListModel {
0380 id: individualTransportModesModel
0381 ListElement { name: "Walk" }
0382 ListElement { name: "Take Bike" }
0383 ListElement { name: "Park Bike" }
0384 ListElement { name: "Rent Bike" }
0385 ListElement { name: "Park Car" }
0386 ListElement { name: "Rent Car" }
0387 ListElement { name: "Pickup by car" }
0388 ListElement { name: "Drop-off by car" }
0389 }
0390
0391 Component {
0392 id: journyQueryPage
0393 Kirigami.Page {
0394 Settings {
0395 id: settings
0396 property alias singleBackend: backendBox.checked
0397 property alias backend: backendSelector.currentIndex
0398 property alias maxResults: maxResults.text
0399 property alias includeIntermediateStops: intermediateStops.checked
0400 property alias includePaths: includePaths.checked
0401 property alias accessMode: accessMode.currentIndex
0402 property alias egressMode: egressMode.currentIndex
0403 }
0404
0405 ColumnLayout {
0406 anchors.fill: parent
0407 QQC2.CheckBox {
0408 id: searchDirection
0409 text: checked ? "Time is arrival" : "Time is departure"
0410 }
0411
0412 QQC2.CheckBox {
0413 text: "Allow insecure backends"
0414 checked: ptMgr.allowInsecureBackends
0415 onToggled: ptMgr.allowInsecureBackends = checked
0416 }
0417
0418 RowLayout {
0419 QQC2.CheckBox {
0420 id: backendBox
0421 text: "Select Backend:"
0422 }
0423 QQC2.ComboBox {
0424 id: backendSelector
0425 Layout.fillWidth: true
0426 textRole: "identifier"
0427 model: BackendModel {
0428 manager: ptMgr
0429 }
0430 enabled: backendBox.checked
0431 }
0432 }
0433
0434 RowLayout {
0435 QQC2.CheckBox {
0436 id: ptMode
0437 checked: true
0438 text: "Public Transport"
0439 }
0440 QQC2.CheckBox {
0441 id: rentalMode
0442 checked: true
0443 text: "Rental Vehicles"
0444 }
0445 }
0446 RowLayout {
0447 QQC2.Label { text: "Results:" }
0448 QQC2.TextField {
0449 id: maxResults
0450 text: "10"
0451 }
0452 QQC2.CheckBox {
0453 id: intermediateStops
0454 checked: true
0455 text: "Intermediate stops"
0456 }
0457 QQC2.CheckBox {
0458 id: includePaths
0459 text: "Paths"
0460 }
0461 }
0462
0463 QQC2.ComboBox {
0464 id: accessMode
0465 Layout.fillWidth: true
0466 model: individualTransportModesModel
0467 textRole: "name"
0468 }
0469 QQC2.ComboBox {
0470 id: fromSelector
0471 Layout.fillWidth: true
0472 model: exampleModel
0473 textRole: "label"
0474 onCurrentIndexChanged: {
0475 var obj = exampleModel.get(currentIndex);
0476 fromName.text = obj.name == "" ? obj.label : obj.name;
0477 fromLon.text = obj.lon;
0478 fromLat.text = obj.lat;
0479 if (toSelector.currentIndex == currentIndex) {
0480 toSelector.currentIndex = (currentIndex + 1) % count;
0481 }
0482 }
0483 }
0484 RowLayout {
0485 QQC2.TextField {
0486 id: fromName
0487 }
0488 QQC2.TextField {
0489 id: fromLon
0490 }
0491 QQC2.TextField {
0492 id: fromLat
0493 }
0494 }
0495
0496 QQC2.ComboBox {
0497 id: toSelector
0498 Layout.fillWidth: true
0499 model: exampleModel
0500 textRole: "label"
0501 onCurrentIndexChanged: {
0502 var obj = exampleModel.get(currentIndex);
0503 toName.text = obj.name == "" ? obj.label : obj.name;
0504 toLon.text = obj.lon;
0505 toLat.text = obj.lat;
0506 if (fromSelector.currentIndex == currentIndex) {
0507 fromSelector.currentIndex = (currentIndex - 1 + count) % count;
0508 }
0509 }
0510 }
0511 RowLayout {
0512 QQC2.TextField {
0513 id: toName
0514 }
0515 QQC2.TextField {
0516 id: toLon
0517 }
0518 QQC2.TextField {
0519 id: toLat
0520 }
0521 }
0522 QQC2.ComboBox {
0523 id: egressMode
0524 Layout.fillWidth: true
0525 model: individualTransportModesModel
0526 textRole: "name"
0527 }
0528 QQC2.ComboBox {
0529 id: lineModeSelector
0530 Layout.fillWidth: true
0531 model: [ "All", "Only long distance", "Local public transport", "Local trains only", "Rapit transit/metro/tram", "Bus" ]
0532 property var currentMode: {
0533 switch (currentIndex) {
0534 case 1: return [Line.LongDistanceTrain, Line.Train];
0535 case 2: return [Line.LocalTrain, Line.RapidTransit, Line.Metro, Line.Tramway, Line.Funicular, Line.Bus];
0536 case 3: return [Line.LocalTrain];
0537 case 4: return [Line.RapidTransit, Line.Metro, Line.Tramway, Line.Funicular];
0538 case 5: return [Line.Bus];
0539 }
0540 return [];
0541 }
0542 }
0543
0544 RowLayout {
0545 function setupRequestCommon()
0546 {
0547 journeyModel.request.dateTimeMode = searchDirection.checked ? JourneyRequest.Arrival : JourneyRequest.Departure;
0548 journeyModel.request.dateTime = new Date(new Date().getTime() + (searchDirection.checked ? 7200000 : 0));
0549 journeyModel.request.backends = backendBox.checked ? [ backendSelector.currentText ] : [];
0550 journeyModel.request.downloadAssets = true
0551 journeyModel.request.modes = (ptMode.checked ? JourneySection.PublicTransport : JourneySection.Invalid)
0552 | (rentalMode.checked ? JourneySection.RentedVehicle : JourneySection.Invalid);
0553 journeyModel.request.maximumResults = maxResults.text;
0554 journeyModel.request.includeIntermediateStops = intermediateStops.checked;
0555 journeyModel.request.includePaths = includePaths.checked;
0556 journeyModel.request.accessModes = individualTransportModes[accessMode.currentIndex];
0557 journeyModel.request.egressModes = individualTransportModes[egressMode.currentIndex];
0558 journeyModel.request.lineModes = lineModeSelector.currentMode;
0559 }
0560
0561 QQC2.Button {
0562 text: "Query"
0563 onClicked: {
0564 var from = journeyModel.request.from;
0565 from.name = fromName.text;
0566 from.latitude = fromLat.text;
0567 from.longitude = fromLon.text;
0568 journeyModel.request.from = from;
0569 var to = journeyModel.request.to;
0570 to.name = toName.text;
0571 to.latitude = toLat.text;
0572 to.longitude = toLon.text;
0573 journeyModel.request.to = to;
0574 parent.setupRequestCommon();
0575 }
0576 }
0577 QQC2.Button {
0578 text: "Query Name"
0579 onClicked: {
0580 var from = journeyModel.request.from;
0581 from.name = fromName.text;
0582 from.latitude = NaN;
0583 from.longitude = NaN;
0584 journeyModel.request.from = from;
0585 var to = journeyModel.request.to;
0586 to.name = toName.text;
0587 to.latitude = NaN;
0588 to.longitude = NaN;
0589 journeyModel.request.to = to;
0590 parent.setupRequestCommon();
0591 }
0592 }
0593 QQC2.Button {
0594 text: "Query Coord"
0595 onClicked: {
0596 var from = journeyModel.request.from;
0597 from.name = "";
0598 from.latitude = fromLat.text;
0599 from.longitude = fromLon.text;
0600 journeyModel.request.from = from;
0601 var to = journeyModel.request.to;
0602 to.name = "";
0603 to.latitude = toLat.text;
0604 to.longitude = toLon.text;
0605 journeyModel.request.to = to;
0606 parent.setupRequestCommon();
0607 }
0608 }
0609 QQC2.Button {
0610 text: "Clear"
0611 onClicked: {
0612 fromName.text = "";
0613 fromLon.text = "";
0614 fromLat.text = "";
0615 toName.text = "";
0616 toLon.text = "";
0617 toLat.text = "";
0618 }
0619 }
0620 }
0621
0622 RowLayout {
0623 QQC2.ToolButton {
0624 id: prevQueryButton
0625 icon.name: "go-previous"
0626 enabled: journeyModel.canQueryPrevious
0627 onClicked: journeyModel.queryPrevious()
0628 }
0629 QQC2.ComboBox {
0630 id: journeySelector
0631 Layout.fillWidth: true
0632 model: titleModel
0633 textRole: "display"
0634 }
0635 QQC2.ToolButton {
0636 id: nextQueryButton
0637 icon.name: "go-next"
0638 enabled: journeyModel.canQueryNext
0639 onClicked: journeyModel.queryNext()
0640 }
0641 }
0642
0643 ListView {
0644 Layout.fillHeight: true
0645 Layout.fillWidth: true
0646 model: journeyModel.data(journeyModel.index(journeySelector.currentIndex, 0), 256).sections
0647 clip: true
0648 delegate: journeyDelegate
0649
0650 QQC2.BusyIndicator {
0651 anchors.centerIn: parent
0652 running: journeyModel.loading
0653 }
0654
0655 QQC2.Label {
0656 anchors.centerIn: parent
0657 width: parent.width
0658 text: journeyModel.errorMessage
0659 color: Kirigami.Theme.negativeTextColor
0660 wrapMode: Text.Wrap
0661 }
0662 }
0663
0664 }
0665 }
0666 }
0667 }