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 }