diff --git a/src/apps/marble-maps/MainScreen.qml b/src/apps/marble-maps/MainScreen.qml index e5359095a..a8f5590e2 100644 --- a/src/apps/marble-maps/MainScreen.qml +++ b/src/apps/marble-maps/MainScreen.qml @@ -1,360 +1,360 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2015 Gábor Péterffy // Copyright 2015 Dennis Nienhüser // Copyright 2015 Mikhail Ivchenko // import QtQuick 2.3 import QtQuick.Controls 1.3 import QtQuick.Window 2.2 import org.kde.marble 0.20 ApplicationWindow { id: root title: qsTr("Marble Maps") visible: true width: 600 height: 400 color: palette.window SystemPalette{ id: palette colorGroup: SystemPalette.Active } Item { id: mapItem anchors { top: parent.top left: parent.left right: parent.right bottom: dialogContainer.top } PinchArea { anchors.fill: parent enabled: true onPinchStarted: marbleMaps.handlePinchStarted(pinch.center) onPinchFinished: marbleMaps.handlePinchFinished(pinch.center) onPinchUpdated: marbleMaps.handlePinchUpdated(pinch.center, pinch.scale); MarbleMaps { id: marbleMaps property string currentPositionProvider: "QtPositioning" property bool wlanOnly: false anchors.fill: parent visible: true // Theme settings. projection: MarbleItem.Mercator mapThemeId: "earth/vectorosm/vectorosm.dgml" // Visibility of layers/plugins. showFrameRate: false showAtmosphere: false showCompass: false showClouds: false showCrosshairs: false showGrid: false showOverviewMap: false showOtherPlaces: false showScaleBar: false showBackground: false positionProvider: suspended ? "" : currentPositionProvider keepScreenOn: !suspended && navigationManager.visible showPositionMarker: false placemarkDelegate: Image { property int xPos: 0 property int yPos: 0 property var placemark: null x: xPos - 0.5 * width y: yPos - height width: Screen.pixelDensity*6 height: width source: "qrc:///ic_place.png" onPlacemarkChanged: { placemarkDialog.placemark = placemark } } onPositionAvailableChanged: { updateIndicator(); } onPositionVisibleChanged: { updateIndicator(); } onVisibleLatLonAltBoxChanged: { updateIndicator(); } onCurrentPositionChanged: { updateIndicator(); } Component.onCompleted: marbleMaps.loadSettings() Component.onDestruction: marbleMaps.writeSettings() function updateIndicator() { if ( !positionVisible && positionAvailable ) { zoomToPositionButton.updateIndicator(); } } RoutingManager { id: routing anchors.fill: parent marbleItem: marbleMaps routingProfile: routeEditor.routingProfile - visible: routeEditor.visible +// visible: hasRoute // TODO: make this work } PositionMarker { id: positionMarker posX: navigationManager.snappedPositionMarkerScreenPosition.x posY: navigationManager.snappedPositionMarkerScreenPosition.y angle: marbleMaps.angle visible: marbleMaps.positionAvailable && marbleMaps.positionVisible radius: navigationManager.screenAccuracy color: navigationManager.deviated ? "#40ff0000" : "transparent" border.color: navigationManager.deviated ? "red" : "transparent" } MouseArea { anchors.fill: parent propagateComposedEvents: true onPressed: { marbleMaps.focus = true; mouse.accepted = false; } } Search { id: search anchors.fill: parent marbleQuickItem: marbleMaps routingManager: routing visible: !navigationManager.visible } } NavigationManager { id: navigationManager width: parent.width height: parent.height visible: false marbleItem: marbleMaps } } BoxedText { id: distanceIndicator text: qsTr("%1 km").arg(zoomToPositionButton.distance < 10 ? zoomToPositionButton.distance.toFixed(1) : zoomToPositionButton.distance.toFixed(0)) anchors { bottom: zoomToPositionButton.top horizontalCenter: zoomToPositionButton.horizontalCenter } visible: marbleMaps.positionAvailable && !marbleMaps.positionVisible } PositionButton { id: zoomToPositionButton anchors { right: parent.right rightMargin: Screen.pixelDensity * 1 bottom: routeEditorButton.top bottomMargin: 10 } iconSource: marbleMaps.positionAvailable ? "qrc:///gps_fixed.png" : "qrc:///gps_not_fixed.png" onClicked: marbleMaps.centerOnCurrentPosition() property real distance: 0 function updateIndicator() { var point = marbleMaps.mapFromItem(zoomToPositionButton, diameter * 0.5, diameter * 0.5); distance = 0.001 * marbleMaps.distanceFromPointToCurrentLocation(point); angle = marbleMaps.angleFromPointToCurrentLocation(point); } showDirection: marbleMaps.positionAvailable && !marbleMaps.positionVisible } CircularButton { id: routeEditorButton anchors { bottom: parent.bottom horizontalCenter: zoomToPositionButton.horizontalCenter bottomMargin: Screen.pixelDensity * 4 } onClicked: { if (dialogContainer.currentIndex === dialogContainer.routing) { dialogContainer.currentIndex = dialogContainer.none navigationManager.visible = true } else if (dialogContainer.currentIndex === dialogContainer.place) { dialogContainer.currentIndex = dialogContainer.routing placemarkDialog.addToRoute() } else { dialogContainer.currentIndex = dialogContainer.routing navigationManager.visible = false } } iconSource: "qrc:///material/directions.svg"; states: [ State { name: "" PropertyChanges { target: routeEditorButton; iconSource: "qrc:///material/directions.svg"; } }, State { name: "routingAction" when: dialogContainer.currentIndex === dialogContainer.routing PropertyChanges { target: routeEditorButton; iconSource: "qrc:///material/navigation.svg"; } }, State { name: "placeAction" when: dialogContainer.currentIndex === dialogContainer.place PropertyChanges { target: routeEditorButton; iconSource: placemarkDialog.actionIconSource } } ] } } Item { id: dialogContainer anchors { left: parent.left right: parent.right bottom: parent.bottom } visible: currentIndex >= 0 property var contentItem: routeEditor height: visible ? contentItem.height : 0 readonly property int none: -1 readonly property int routing: 0 readonly property int place: 1 readonly property int about: 2 readonly property int settings: 3 readonly property int developer: 4 property int currentIndex: none onCurrentIndexChanged: { switch (currentIndex) { case none: case routing: contentItem = routeEditor; break; case place: contentItem = placemarkDialog; break; case about: contentItem = aboutDialog; break; case settings: contentItem = settingsDialog; break; case developer: contentItem = developerDialog; break; } } RouteEditor { id: routeEditor visible: dialogContainer.currentIndex === dialogContainer.routing anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom } PlacemarkDialog { id: placemarkDialog visible: dialogContainer.currentIndex === dialogContainer.place anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom map: marbleMaps } AboutDialog { id: aboutDialog visible: dialogContainer.currentIndex === dialogContainer.about anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom } SettingsDialog { id: settingsDialog visible: dialogContainer.currentIndex === dialogContainer.settings anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom } DeveloperDialog { id: developerDialog visible: dialogContainer.currentIndex === dialogContainer.developer anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom } } BorderImage { visible: dialogContainer.visible anchors.fill: dialogContainer anchors.margins: -14 border { top: 14; left: 14; right: 14; bottom: 14 } source: "qrc:///border_shadow.png" } BoxedText { id: quitHelper visible: false text: qsTr("Press again to close.") anchors.bottom: parent.bottom anchors.bottomMargin: Screen.pixelDensity * 5 anchors.horizontalCenter: parent.horizontalCenter onVisibleChanged: { if (visible) { quitTimer.restart() } } Timer { id: quitTimer interval: 3000; running: false; repeat: false onTriggered: { root.aboutToQuit = false quitHelper.visible = false } } } property bool aboutToQuit: false onClosing: { if (root.aboutToQuit === true) { close.accepted = true // we will quit return } else if (navigationManager.visible) { navigationManager.visible = false } else if (dialogContainer.visible) { dialogContainer.currentIndex = dialogContainer.none } else { root.aboutToQuit = true quitHelper.visible = true } close.accepted = false } } diff --git a/src/lib/marble/declarative/Routing.cpp b/src/lib/marble/declarative/Routing.cpp index 0b5bb88e7..12fc7d0bc 100644 --- a/src/lib/marble/declarative/Routing.cpp +++ b/src/lib/marble/declarative/Routing.cpp @@ -1,474 +1,505 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2011 Dennis Nienhüser // #include "Routing.h" #include #include #include "MarbleDirs.h" #include "routing/AlternativeRoutesModel.h" #include "routing/RoutingManager.h" #include "routing/RouteRequest.h" #include "routing/RoutingProfilesModel.h" #include #include #include #include #include #include #include -#include #include +#include +#include +#include namespace Marble { class RoutingPrivate { public: explicit RoutingPrivate(QObject * parent = nullptr); MarbleMap* m_marbleMap; QMap m_profiles; QString m_routingProfile; QQmlComponent * m_waypointDelegate; QMap m_waypointItems; RouteRequestModel* m_routeRequestModel; QObject * m_parent; QVector m_searchResultPlacemarks; QMap m_searchResultItems; + QVector m_cachedPolygons; }; RoutingPrivate::RoutingPrivate(QObject *parent) : m_marbleMap( nullptr ), m_waypointDelegate( nullptr ), m_routeRequestModel( new RouteRequestModel(parent) ), m_parent( parent ) { // nothing to do } Routing::Routing( QQuickItem *parent) : - QQuickPaintedItem( parent ), d( new RoutingPrivate(this) ) + QQuickItem( parent ), d( new RoutingPrivate(this) ) { - setRenderTarget(QQuickPaintedItem::FramebufferObject); + setFlag(ItemHasContents, true); d->m_routeRequestModel->setRouting(this); connect(d->m_routeRequestModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(updateWaypointItems())); connect(d->m_routeRequestModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), this, SLOT(updateWaypointItems())); connect(d->m_routeRequestModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(updateWaypointItems())); emit routeRequestModelChanged(d->m_routeRequestModel); + update(); } Routing::~Routing() { delete d; } -void Routing::paint(QPainter *painter) -{ +QSGNode * Routing::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) { if (!d->m_marbleMap) { - return; + return 0; } - QPaintDevice *paintDevice = painter->device(); - painter->end(); - { - Marble::GeoPainter geoPainter(paintDevice, d->m_marbleMap->viewport(), d->m_marbleMap->mapQuality()); - - RoutingManager const * const routingManager = d->m_marbleMap->model()->routingManager(); - GeoDataLineString const waypoints = routingManager->routingModel()->route().path(); - - int const dpi = qMax(paintDevice->logicalDpiX(), paintDevice->logicalDpiY()); - QPen standardRoutePen( routingManager->routeColorStandard().darker( 200 ) ); - qreal const width = 2.5 * MM2M * M2IN * dpi; - standardRoutePen.setWidthF( width ); - geoPainter.setPen( standardRoutePen ); - geoPainter.drawPolyline( waypoints ); - - standardRoutePen.setColor( routingManager->routeColorStandard() ); - standardRoutePen.setWidthF( width - 4.0 ); - if ( routingManager->state() == RoutingManager::Downloading ) { - standardRoutePen.setStyle( Qt::DotLine ); + QOpenGLPaintDevice paintDevice(QSize(width(), height())); + Marble::GeoPainter geoPainter(&paintDevice, d->m_marbleMap->viewport(), d->m_marbleMap->mapQuality()); + + RoutingManager const * const routingManager = d->m_marbleMap->model()->routingManager(); + GeoDataLineString const waypoints = routingManager->routingModel()->route().path(); + + if (waypoints.isEmpty()) { + return 0; + } + + int const dpi = qMax(paintDevice.logicalDpiX(), paintDevice.logicalDpiY()); + qreal const width = 2.5 * MM2M * M2IN * dpi - 4; + + QColor standardRouteColor = routingManager->state() == RoutingManager::Downloading ? + routingManager->routeColorStandard() : + routingManager->routeColorStandard().darker( 200 ); + + geoPainter.polygonsFromLineString( waypoints, d->m_cachedPolygons); + + if (!d->m_cachedPolygons.isEmpty()) { + delete oldNode; + oldNode = new QSGNode; + QSGFlatColorMaterial *material = new QSGFlatColorMaterial; + material->setColor(standardRouteColor); + + foreach(const QPolygonF* itPolygon, d->m_cachedPolygons) { + + int segmentCount = itPolygon->size() - 1; + + QSGGeometryNode * lineNode = new QSGGeometryNode; + + QSGGeometry * lineNodeGeo = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 2*segmentCount); + lineNodeGeo->setLineWidth(width); + lineNodeGeo->setDrawingMode(GL_LINE_STRIP); + lineNodeGeo->allocate(2*segmentCount); + + lineNode->setGeometry(lineNodeGeo); + lineNode->setFlag(QSGNode::OwnsGeometry); + lineNode->setMaterial(material); + lineNode->setFlag(QSGNode::OwnsMaterial); + + for(int i = 0; i < segmentCount; ++i) { + lineNodeGeo->vertexDataAsPoint2D()[2*i].set(itPolygon->at(i).x(), itPolygon->at(i).y()); + lineNodeGeo->vertexDataAsPoint2D()[2*i+1].set(itPolygon->at(i+1).x(), itPolygon->at(i+1).y()); + } + oldNode->appendChildNode(lineNode); } - geoPainter.setPen( standardRoutePen ); - geoPainter.drawPolyline( waypoints ); } - painter->begin(paintDevice); + qDeleteAll(d->m_cachedPolygons); + d->m_cachedPolygons.clear(); + + return oldNode; } QObject* Routing::waypointModel() { return d->m_marbleMap ? d->m_marbleMap->model()->routingManager()->routingModel() : 0; } void Routing::setWaypointDelegate(QQmlComponent *waypointDelegate) { if (d->m_waypointDelegate == waypointDelegate) { return; } d->m_waypointDelegate = waypointDelegate; emit waypointDelegateChanged(waypointDelegate); } void Routing::updateWaypointItems() { if ( d->m_marbleMap && d->m_routeRequestModel ) { for (int i = d->m_waypointItems.keys().size(); i < d->m_routeRequestModel->rowCount(); i++ ) { QQmlContext * context = new QQmlContext( qmlContext( d->m_waypointDelegate ) ); QObject * component = d->m_waypointDelegate->create(context); QQuickItem* item = qobject_cast( component ); if ( item ) { item->setParentItem( this ); item->setProperty("index", i); d->m_waypointItems[i] = item; } else { delete component; } } for (int i = d->m_waypointItems.keys().size()-1; i >= d->m_routeRequestModel->rowCount(); i--) { QQuickItem* item = d->m_waypointItems[i]; item->setProperty("visible", QVariant(false) ); d->m_waypointItems.erase(d->m_waypointItems.find(i)); item->deleteLater(); } QMap::iterator iter = d->m_waypointItems.begin(); while ( iter != d->m_waypointItems.end() ) { qreal x = 0; qreal y = 0; const qreal lon = d->m_routeRequestModel->data(d->m_routeRequestModel->index( iter.key() ), RouteRequestModel::LongitudeRole).toFloat(); const qreal lat = d->m_routeRequestModel->data(d->m_routeRequestModel->index( iter.key() ), RouteRequestModel::LatitudeRole).toFloat(); const bool visible = d->m_marbleMap->viewport()->screenCoordinates(lon * DEG2RAD, lat * DEG2RAD, x, y); QQuickItem * item = iter.value(); if ( item ) { item->setVisible( visible ); if ( visible ) { item->setProperty("xPos", QVariant(x)); item->setProperty("yPos", QVariant(y)); if (iter.key() == 0 && waypointCount() == 1) { item->setProperty("type", QVariant(QStringLiteral("departure"))); } else if (iter.key() == d->m_waypointItems.keys().size()-1) { item->setProperty("type", QVariant(QStringLiteral("destination"))); } else if (iter.key() > 0) { item->setProperty("type", QVariant(QStringLiteral("waypoint"))); } else { item->setProperty("type", QVariant(QStringLiteral("departure"))); } } } ++iter; } } } int Routing::addSearchResultPlacemark(Placemark *placemark) { if ( d->m_marbleMap ) { for (int i = 0; i < d->m_searchResultItems.size(); i++) { if (d->m_searchResultPlacemarks[i]->placemark().coordinate() == placemark->placemark().coordinate()) { return i; } } Placemark * newPlacemark = new Placemark(this); newPlacemark->setGeoDataPlacemark(placemark->placemark()); d->m_searchResultPlacemarks.push_back(newPlacemark); } updateSearchResultPlacemarks(); return d->m_searchResultPlacemarks.size()-1; } void Routing::clearSearchResultPlacemarks() { foreach(Placemark* placemark, d->m_searchResultPlacemarks) { placemark->deleteLater(); } d->m_searchResultPlacemarks.clear(); foreach(QQuickItem* item, d->m_searchResultItems) { item->deleteLater(); } d->m_searchResultItems.clear(); } void Routing::updateSearchResultPlacemarks() { for (int i = d->m_searchResultItems.keys().size(); i < d->m_searchResultPlacemarks.size(); i++ ) { QQmlContext * context = new QQmlContext( qmlContext( d->m_waypointDelegate ) ); QObject * component = d->m_waypointDelegate->create(context); QQuickItem* item = qobject_cast( component ); if ( item ) { item->setParentItem( this ); item->setProperty("index", i); item->setProperty("type", QVariant(QStringLiteral("searchResult"))); item->setProperty("placemark", QVariant::fromValue(d->m_searchResultPlacemarks[i])); d->m_searchResultItems[i] = item; } else { delete component; } } for (int i = d->m_searchResultItems.keys().size()-1; i >= d->m_searchResultPlacemarks.size(); i--) { QQuickItem* item = d->m_searchResultItems[i]; item->setProperty("visible", QVariant(false) ); d->m_searchResultItems.erase(d->m_searchResultItems.find(i)); item->deleteLater(); } for (int i = 0; i < d->m_searchResultItems.keys().size() && i < d->m_searchResultPlacemarks.size(); i++) { qreal x = 0; qreal y = 0; const qreal lon = d->m_searchResultPlacemarks[i]->placemark().coordinate().longitude(); const qreal lat = d->m_searchResultPlacemarks[i]->placemark().coordinate().latitude(); const bool visible = d->m_marbleMap->viewport()->screenCoordinates(lon, lat, x, y); QQuickItem * item = d->m_searchResultItems[i]; if ( item ) { item->setVisible( visible ); if ( visible ) { item->setProperty("xPos", QVariant(x)); item->setProperty("yPos", QVariant(y)); } } } } void Routing::setMarbleMap( MarbleMap* marbleMap ) { d->m_marbleMap = marbleMap; if ( d->m_marbleMap ) { connect(d->m_marbleMap, SIGNAL(repaintNeeded(QRegion)), this, SLOT(update())); RoutingManager* routingManager = d->m_marbleMap->model()->routingManager(); if (routingManager->profilesModel()->rowCount() == 0) { routingManager->profilesModel()->loadDefaultProfiles(); routingManager->readSettings(); } connect( routingManager, SIGNAL(stateChanged(RoutingManager::State)), this, SLOT(update())); connect( routingManager, SIGNAL(routeRetrieved(GeoDataDocument*)), this, SLOT(update())); connect( routingManager, SIGNAL(stateChanged(RoutingManager::State)), this, SIGNAL(hasRouteChanged()) ); connect( routingModel(), SIGNAL(currentRouteChanged()), this, SIGNAL(hasRouteChanged()) ); connect( routingModel(), SIGNAL(currentRouteChanged()), this, SLOT(update()) ); connect( d->m_marbleMap, SIGNAL(visibleLatLonAltBoxChanged(GeoDataLatLonAltBox)), this, SLOT(updateWaypointItems()) ); connect( d->m_marbleMap, SIGNAL(visibleLatLonAltBoxChanged(GeoDataLatLonAltBox)), this, SLOT(updateSearchResultPlacemarks()) ); emit routingModelChanged(); QList profiles = routingManager->profilesModel()->profiles(); if ( profiles.size() == 4 ) { /** @todo FIXME: Restrictive assumptions on available plugins and certain profile loading implementation */ d->m_profiles[QStringLiteral("Motorcar")] = profiles.at( 0 ); d->m_profiles[QStringLiteral("Bicycle")] = profiles.at( 2 ); d->m_profiles[QStringLiteral("Pedestrian")] = profiles.at( 3 ); } else { qDebug() << "Unexpected size of default routing profiles: " << profiles.size(); } } emit marbleMapChanged(); emit routingProfileChanged(); emit hasRouteChanged(); } MarbleMap *Routing::marbleMap() { return d->m_marbleMap; } QString Routing::routingProfile() const { return d->m_routingProfile; } void Routing::setRoutingProfile( const QString & profile ) { if ( d->m_routingProfile != profile ) { d->m_routingProfile = profile; if ( d->m_marbleMap ) { d->m_marbleMap->model()->routingManager()->routeRequest()->setRoutingProfile( d->m_profiles[profile] ); } emit routingProfileChanged(); } } bool Routing::hasRoute() const { return d->m_marbleMap && d->m_marbleMap->model()->routingManager()->routingModel()->rowCount() > 0; } RoutingModel *Routing::routingModel() { return d->m_marbleMap == 0 ? 0 : d->m_marbleMap->model()->routingManager()->routingModel(); } QQmlComponent *Routing::waypointDelegate() const { return d->m_waypointDelegate; } int Routing::waypointCount() const { return d->m_routeRequestModel ? d->m_routeRequestModel->rowCount() : 0; } RouteRequestModel *Routing::routeRequestModel() { return d->m_routeRequestModel; } void Routing::addVia( qreal lon, qreal lat ) { if ( d->m_marbleMap ) { Marble::RouteRequest* request = d->m_marbleMap->model()->routingManager()->routeRequest(); request->addVia( Marble::GeoDataCoordinates( lon, lat, 0.0, Marble::GeoDataCoordinates::Degree ) ); updateRoute(); } } void Routing::addViaAtIndex(int index, qreal lon, qreal lat) { if ( d->m_marbleMap ) { Marble::RouteRequest * request = d->m_marbleMap->model()->routingManager()->routeRequest(); request->insert(index, Marble::GeoDataCoordinates( lon, lat, 0.0, Marble::GeoDataCoordinates::Degree) ); updateRoute(); } } void Routing::addViaByPlacemark(Placemark *placemark) { if (d->m_marbleMap && placemark) { Marble::RouteRequest * request = d->m_marbleMap->model()->routingManager()->routeRequest(); request->addVia(placemark->placemark()); updateRoute(); } } void Routing::addViaByPlacemarkAtIndex(int index, Placemark *placemark) { if (d->m_marbleMap && placemark) { Marble::RouteRequest * request = d->m_marbleMap->model()->routingManager()->routeRequest(); request->insert(index, placemark->placemark()); updateRoute(); } } void Routing::setVia( int index, qreal lon, qreal lat ) { if ( index < 0 || index > 200 || !d->m_marbleMap ) { return; } Marble::RouteRequest* request = d->m_marbleMap->model()->routingManager()->routeRequest(); Q_ASSERT( request ); if ( index < request->size() ) { request->setPosition( index, Marble::GeoDataCoordinates( lon, lat, 0.0, Marble::GeoDataCoordinates::Degree ) ); } else { for ( int i=request->size(); iappend( Marble::GeoDataCoordinates( 0.0, 0.0 ) ); } request->append( Marble::GeoDataCoordinates( lon, lat, 0.0, Marble::GeoDataCoordinates::Degree ) ); } updateRoute(); } void Routing::removeVia( int index ) { if ( index < 0 || !d->m_marbleMap ) { return; } Marble::RouteRequest* request = d->m_marbleMap->model()->routingManager()->routeRequest(); if ( index < request->size() ) { d->m_marbleMap->model()->routingManager()->routeRequest()->remove( index ); } updateRoute(); } void Routing::swapVias(int index1, int index2) { if ( !d->m_marbleMap || !d->m_routeRequestModel ) { return; } Marble::RouteRequest* request = d->m_marbleMap->model()->routingManager()->routeRequest(); request->swap(index1, index2); updateRoute(); updateWaypointItems(); } void Routing::reverseRoute() { if ( d->m_marbleMap ) { d->m_marbleMap->model()->routingManager()->reverseRoute(); } } void Routing::clearRoute() { if ( d->m_marbleMap ) { d->m_marbleMap->model()->routingManager()->clearRoute(); } } void Routing::updateRoute() { if ( d->m_marbleMap ) { d->m_marbleMap->model()->routingManager()->retrieveRoute(); } } void Routing::openRoute( const QString &fileName ) { if ( d->m_marbleMap ) { Marble::RoutingManager * const routingManager = d->m_marbleMap->model()->routingManager(); /** @todo FIXME: replace the file:// prefix on QML side */ routingManager->clearRoute(); QString target = fileName.startsWith( QLatin1String( "file://" ) ) ? fileName.mid( 7 ) : fileName; routingManager->loadRoute( target ); Marble::GeoDataDocument* route = routingManager->alternativeRoutesModel()->currentRoute(); if ( route ) { const Marble::GeoDataLineString* waypoints = Marble::AlternativeRoutesModel::waypoints( route ); if ( waypoints ) { GeoDataCoordinates const center = waypoints->latLonAltBox().center(); GeoDataCoordinates::Unit const inDegree = GeoDataCoordinates::Degree; d->m_marbleMap->centerOn( center.longitude(inDegree), center.latitude(inDegree) ); } } } } void Routing::saveRoute( const QString &fileName ) { if ( d->m_marbleMap ) { /** @todo FIXME: replace the file:// prefix on QML side */ QString target = fileName.startsWith( QLatin1String( "file://" ) ) ? fileName.mid( 7 ) : fileName; d->m_marbleMap->model()->routingManager()->saveRoute( target ); } } } #include "moc_Routing.cpp" diff --git a/src/lib/marble/declarative/Routing.h b/src/lib/marble/declarative/Routing.h index 24f55004e..1e18ee284 100644 --- a/src/lib/marble/declarative/Routing.h +++ b/src/lib/marble/declarative/Routing.h @@ -1,122 +1,121 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2011 Dennis Nienhüser // #ifndef MARBLE_DECLARATIVE_ROUTING_H #define MARBLE_DECLARATIVE_ROUTING_H -#include +#include #include #include #include namespace Marble { class MarbleMap; class RoutingPrivate; -class Routing : public QQuickPaintedItem +class Routing : public QQuickItem { Q_OBJECT Q_PROPERTY( MarbleMap* marbleMap READ marbleMap WRITE setMarbleMap NOTIFY marbleMapChanged) Q_PROPERTY( QString routingProfile READ routingProfile WRITE setRoutingProfile NOTIFY routingProfileChanged ) Q_PROPERTY( bool hasRoute READ hasRoute NOTIFY hasRouteChanged ) Q_PROPERTY( RoutingModel* routingModel READ routingModel NOTIFY routingModelChanged) Q_PROPERTY( QQmlComponent* waypointDelegate READ waypointDelegate WRITE setWaypointDelegate NOTIFY waypointDelegateChanged) Q_PROPERTY( RouteRequestModel* routeRequestModel READ routeRequestModel NOTIFY routeRequestModelChanged) public: enum RoutingProfile { Motorcar, Bicycle, Pedestrian }; explicit Routing( QQuickItem* parent = 0 ); ~Routing(); - // Implements QQuickPaintedItem interface - void paint(QPainter * painter); - -public: void setMarbleMap( MarbleMap* marbleMap ); MarbleMap *marbleMap(); QString routingProfile() const; void setRoutingProfile( const QString & profile ); bool hasRoute() const; RoutingModel *routingModel(); QQmlComponent * waypointDelegate() const; Q_INVOKABLE int waypointCount() const; RouteRequestModel* routeRequestModel(); public Q_SLOTS: void addVia( qreal lon, qreal lat ); void addViaAtIndex( int index, qreal lon, qreal lat ); void addViaByPlacemark( Placemark * placemark ); void addViaByPlacemarkAtIndex( int index, Placemark * placemark ); void setVia( int index, qreal lon, qreal lat ); void removeVia( int index ); void swapVias( int index1, int index2 ); void reverseRoute(); void clearRoute(); void updateRoute(); void openRoute( const QString &filename ); void saveRoute( const QString &filename ); QObject* waypointModel(); void setWaypointDelegate(QQmlComponent * waypointDelegate); int addSearchResultPlacemark( Placemark * placemark ); void clearSearchResultPlacemarks(); Q_SIGNALS: void marbleMapChanged(); void routingProfileChanged(); void hasRouteChanged(); void routingModelChanged(); void waypointDelegateChanged(QQmlComponent * waypointDelegate); void routeRequestModelChanged(RouteRequestModel* routeRequestModel); +protected: + // Implements QQuickItem interface + QSGNode * updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *); private Q_SLOTS: void updateWaypointItems(); void updateSearchResultPlacemarks(); private: RoutingPrivate* const d; }; } #endif