File indexing completed on 2024-05-05 03:49:17

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2014 Adam Dabrowski <adabrowski@piap.pl> <adamdbrw@gmail.com>
0004 //
0005 
0006 
0007 #include <MarbleQuickItem.h>
0008 #include <QQuickWindow>
0009 #include <QScreen>
0010 #include <QPainter>
0011 #include <QPaintDevice>
0012 #include <QtMath>
0013 #include <QQmlContext>
0014 #include <QSettings>
0015 
0016 #include <MarbleModel.h>
0017 #include <MarbleMap.h>
0018 #include <ViewportParams.h>
0019 #include <GeoPainter.h>
0020 #include <GeoDataLookAt.h>
0021 #include <Planet.h>
0022 #include <MarbleAbstractPresenter.h>
0023 #include <AbstractFloatItem.h>
0024 #include <MarbleInputHandler.h>
0025 #include <PositionTracking.h>
0026 #include <PositionProviderPlugin.h>
0027 #include <PluginManager.h>
0028 #include <RenderPlugin.h>
0029 #include <MarbleMath.h>
0030 #include <StyleBuilder.h>
0031 #include <GeoDataLatLonAltBox.h>
0032 #include <GeoDataCoordinates.h>
0033 #include <ReverseGeocodingRunnerManager.h>
0034 #include <routing/RoutingManager.h>
0035 #include <routing/RoutingModel.h>
0036 #include <routing/Route.h>
0037 #include <BookmarkManager.h>
0038 #include "GeoDataRelation.h"
0039 #include "osm/OsmPlacemarkData.h"
0040 #include "GeoDataDocument.h"
0041 #include <geodata/parser/GeoSceneTypes.h>
0042 #include <geodata/scene/GeoSceneDocument.h>
0043 #include <geodata/scene/GeoSceneMap.h>
0044 #include <geodata/scene/GeoSceneLayer.h>
0045 #include <geodata/scene/GeoSceneTextureTileDataset.h>
0046 
0047 namespace Marble
0048 {
0049     //TODO - move to separate files
0050     class QuickItemSelectionRubber : public AbstractSelectionRubber
0051     { //TODO: support rubber selection in MarbleQuickItem
0052     public:
0053         QuickItemSelectionRubber();
0054         void show() override { m_visible = true; }
0055         void hide() override { m_visible = false; }
0056         bool isVisible() const override { return m_visible; }
0057         const QRect &geometry() const override { return m_geometry; }
0058         void setGeometry(const QRect &/*geometry*/) override {}
0059     private:
0060         QRect m_geometry;
0061         bool m_visible;
0062     };
0063 
0064     //TODO - implement missing functionalities
0065     class MarbleQuickInputHandler : public MarbleDefaultInputHandler
0066     {
0067     public:
0068         MarbleQuickInputHandler(MarbleAbstractPresenter *marblePresenter, MarbleQuickItem *marbleQuick)
0069             : MarbleDefaultInputHandler(marblePresenter)
0070             ,m_marbleQuick(marbleQuick)
0071         {
0072             setInertialEarthRotationEnabled(false); //Disabled by default, it's buggy. TODO - fix
0073         }
0074 
0075         bool acceptMouse() override
0076         {
0077             return true;
0078         }
0079 
0080         void pinch(QPointF center, qreal scale, Qt::GestureState state)
0081         {   //TODO - this whole thing should be moved to MarbleAbstractPresenter
0082             (void)handlePinch(center, scale, state);
0083         }
0084 
0085         void handleMouseButtonPressAndHold(const QPoint &position) override
0086         {
0087             m_marbleQuick->reverseGeocoding(position);
0088         }
0089 
0090     private Q_SLOTS:
0091         void showLmbMenu(int x, int y) override
0092         {
0093             m_marbleQuick->selectPlacemarkAt(x, y);
0094             emit m_marbleQuick->lmbMenuRequested(QPoint(x,y));
0095         }
0096 
0097         void showRmbMenu(int x, int y) override {
0098             emit m_marbleQuick->rmbMenuRequested(QPoint(x,y));
0099         }
0100         void openItemToolTip() override {}
0101         void setCursor(const QCursor &cursor) override
0102         {
0103             m_marbleQuick->setCursor(cursor);
0104         }
0105 
0106     private Q_SLOTS:
0107         void installPluginEventFilter(RenderPlugin *) override {}
0108 
0109     private:
0110         bool layersEventFilter(QObject *o, QEvent *e) override
0111         {
0112             return m_marbleQuick->layersEventFilter(o, e);
0113         }
0114 
0115         //empty - don't check. It would be invalid with quick items
0116         void checkReleasedMove(QMouseEvent *) override {}
0117 
0118         bool handleTouch(QTouchEvent *event) override
0119         {
0120             if (event->touchPoints().count() > 1)
0121             {   //not handling multi-touch at all, let PinchArea or MultiPointTouchArea take care of it
0122                 return false;
0123             }
0124 
0125             if (event->touchPoints().count() == 1)
0126             {   //handle - but do not accept. I.e. pinchArea still needs to get this
0127                 QTouchEvent::TouchPoint p = event->touchPoints().at(0);
0128                 if (event->type() == QEvent::TouchBegin)
0129                 {
0130                     QMouseEvent press(QMouseEvent::MouseButtonPress, p.pos(),
0131                                       Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
0132                     handleMouseEvent(&press);
0133                 }
0134                 else if (event->type() == QEvent::TouchUpdate)
0135                 {
0136                     QMouseEvent move(QMouseEvent::MouseMove, p.pos(),
0137                                       Qt::NoButton, Qt::LeftButton, Qt::NoModifier);
0138                     handleMouseEvent(&move);
0139                 }
0140                 else if (event->type() == QEvent::TouchEnd)
0141                 {
0142                     QMouseEvent release(QMouseEvent::MouseButtonRelease, p.pos(),
0143                                       Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
0144                     handleMouseEvent(&release);
0145                 }
0146             }
0147             return false;
0148         }
0149 
0150         AbstractSelectionRubber *selectionRubber() override
0151         {
0152             return &m_selectionRubber;
0153         }
0154 
0155         MarbleQuickItem *m_marbleQuick;
0156         QuickItemSelectionRubber m_selectionRubber;
0157 //        bool m_usePinchArea;
0158     };
0159 
0160     class MarbleQuickItemPrivate
0161     {
0162     public:
0163         explicit MarbleQuickItemPrivate(MarbleQuickItem *marble) :
0164             m_marble(marble),
0165             m_model(),
0166             m_map(&m_model),
0167             m_presenter(&m_map),
0168             m_positionVisible(false),
0169             m_currentPosition(marble),
0170             m_inputHandler(&m_presenter, marble),
0171             m_placemarkDelegate(nullptr),
0172             m_placemarkItem(nullptr),
0173             m_placemark(nullptr),
0174             m_reverseGeocoding(&m_model),
0175             m_showScaleBar(false),
0176             m_enabledRelationTypes(GeoDataRelation::RouteFerry |
0177                             GeoDataRelation::RouteTrain |
0178                             GeoDataRelation::RouteSubway |
0179                             GeoDataRelation::RouteTram |
0180                             GeoDataRelation::RouteBus |
0181                             GeoDataRelation::RouteTrolleyBus |
0182                             GeoDataRelation::RouteHiking),
0183             m_showPublicTransport(false),
0184             m_showOutdoorActivities(false),
0185             m_heading(0.0),
0186             m_hoverEnabled(false),
0187             m_invertColorEnabled(false)
0188         {
0189             m_currentPosition.setName(QObject::tr("Current Location"));
0190             m_relationTypeConverter["road"] = GeoDataRelation::RouteRoad;
0191             m_relationTypeConverter["detour"] = GeoDataRelation::RouteDetour;
0192             m_relationTypeConverter["ferry"] = GeoDataRelation::RouteFerry;
0193             m_relationTypeConverter["train"] = GeoDataRelation::RouteTrain;
0194             m_relationTypeConverter["subway"] = GeoDataRelation::RouteSubway;
0195             m_relationTypeConverter["tram"] = GeoDataRelation::RouteTram;
0196             m_relationTypeConverter["bus"] = GeoDataRelation::RouteBus;
0197             m_relationTypeConverter["trolley-bus"] = GeoDataRelation::RouteTrolleyBus;
0198             m_relationTypeConverter["bicycle"] = GeoDataRelation::RouteBicycle;
0199             m_relationTypeConverter["mountainbike"] = GeoDataRelation::RouteMountainbike;
0200             m_relationTypeConverter["foot"] = GeoDataRelation::RouteFoot;
0201             m_relationTypeConverter["hiking"] = GeoDataRelation::RouteHiking;
0202             m_relationTypeConverter["horse"] = GeoDataRelation::RouteHorse;
0203             m_relationTypeConverter["inline-skates"] = GeoDataRelation::RouteInlineSkates;
0204             m_relationTypeConverter["downhill"] = GeoDataRelation::RouteSkiDownhill;
0205             m_relationTypeConverter["ski-nordic"] = GeoDataRelation::RouteSkiNordic;
0206             m_relationTypeConverter["skitour"] = GeoDataRelation::RouteSkitour;
0207             m_relationTypeConverter["sled"] = GeoDataRelation::RouteSled;
0208         }
0209 
0210         void updateVisibleRoutes();
0211         void changeBlending(bool enabled, const QString &blendingName);
0212         void changeStyleBuilder(bool invert);
0213 
0214     private:
0215         MarbleQuickItem *m_marble;
0216         friend class MarbleQuickItem;
0217         MarbleModel m_model;
0218         MarbleMap m_map;
0219         Marble::MapTheme m_mapTheme;
0220         MarbleAbstractPresenter m_presenter;
0221         bool m_positionVisible;
0222         Placemark m_currentPosition;
0223 
0224         MarbleQuickInputHandler m_inputHandler;
0225         QQmlComponent* m_placemarkDelegate;
0226         QQuickItem* m_placemarkItem;
0227         Placemark* m_placemark;
0228         ReverseGeocodingRunnerManager m_reverseGeocoding;
0229 
0230         bool m_showScaleBar;
0231         QMap<QString, GeoDataRelation::RelationType> m_relationTypeConverter;
0232         GeoDataRelation::RelationTypes m_enabledRelationTypes;
0233         bool m_showPublicTransport;
0234         bool m_showOutdoorActivities;
0235         qreal m_heading;
0236         bool m_hoverEnabled;
0237         bool m_invertColorEnabled;
0238     };
0239 
0240     MarbleQuickItem::MarbleQuickItem(QQuickItem *parent) : QQuickPaintedItem(parent)
0241       ,d(new MarbleQuickItemPrivate(this))
0242     {
0243         setRenderTarget(QQuickPaintedItem::FramebufferObject);
0244         setOpaquePainting(true);
0245         qRegisterMetaType<Placemark*>("Placemark*");
0246         d->m_map.setMapQualityForViewContext(NormalQuality, Animation);
0247 
0248         for (AbstractFloatItem *item: d->m_map.floatItems()) {
0249             if (item->nameId() == QLatin1String("license")) {
0250                 item->setPosition(QPointF(5.0, -10.0));
0251             } else {
0252                 item->hide();
0253             }
0254         }
0255 
0256         d->m_model.positionTracking()->setTrackVisible(false);
0257         d->m_mapTheme.setMap(this);
0258 
0259         connect(&d->m_map, SIGNAL(repaintNeeded(QRegion)), this, SLOT(update()));
0260         connect(this, &MarbleQuickItem::widthChanged, this, &MarbleQuickItem::resizeMap);
0261         connect(this, &MarbleQuickItem::heightChanged, this, &MarbleQuickItem::resizeMap);
0262         connect(&d->m_map, &MarbleMap::visibleLatLonAltBoxChanged, this, &MarbleQuickItem::updatePositionVisibility);
0263         connect(&d->m_map, &MarbleMap::radiusChanged, this, &MarbleQuickItem::radiusChanged);
0264         connect(&d->m_map, &MarbleMap::radiusChanged, this, &MarbleQuickItem::zoomChanged);
0265         connect(&d->m_reverseGeocoding, SIGNAL(reverseGeocodingFinished(GeoDataCoordinates,GeoDataPlacemark)),
0266                 this, SLOT(handleReverseGeocoding(GeoDataCoordinates,GeoDataPlacemark)));
0267         connect(&d->m_map, &MarbleMap::visibleLatLonAltBoxChanged, this, &MarbleQuickItem::handleVisibleLatLonAltBoxChanged);
0268         connect(d->m_map.model(), &MarbleModel::workOfflineChanged, this, &MarbleQuickItem::workOfflineChanged);
0269 
0270         setAcceptedMouseButtons(Qt::AllButtons);
0271         installEventFilter(&d->m_inputHandler);
0272     }
0273 
0274     void MarbleQuickItem::resizeMap()
0275     {
0276 
0277         d->m_map.setSize(qMax(100, int(width())), qMax(100, int(height())));
0278         update();
0279         updatePositionVisibility();
0280     }
0281 
0282     void MarbleQuickItem::positionDataStatusChanged(PositionProviderStatus status)
0283     {
0284         bool const positionAvailable = status == PositionProviderStatusAvailable;
0285         emit positionAvailableChanged(positionAvailable);
0286         updatePositionVisibility();
0287     }
0288 
0289     void MarbleQuickItem::positionChanged(const GeoDataCoordinates &, GeoDataAccuracy)
0290     {
0291        updatePositionVisibility();
0292     }
0293 
0294     void MarbleQuickItem::updatePositionVisibility()
0295     {
0296         updatePlacemarks();
0297         bool isVisible = false;
0298         if ( positionAvailable() ) {
0299             qreal x, y;
0300             bool globeHidesPoint;
0301             bool const valid = d->m_map.viewport()->screenCoordinates(d->m_model.positionTracking()->currentLocation(), x, y, globeHidesPoint);
0302             isVisible = valid && !globeHidesPoint;
0303         }
0304 
0305         if ( isVisible != d->m_positionVisible ) {
0306             d->m_positionVisible = isVisible;
0307             emit positionVisibleChanged( isVisible );
0308         }
0309     }
0310 
0311     void MarbleQuickItem::updateCurrentPosition(const GeoDataCoordinates &coordinates)
0312     {
0313         d->m_currentPosition.placemark().setCoordinate(coordinates);
0314         emit currentPositionChanged(&d->m_currentPosition);
0315     }
0316 
0317     void MarbleQuickItem::updatePlacemarks()
0318     {
0319         if (!d->m_placemarkDelegate || !d->m_placemark) {
0320             return;
0321         }
0322 
0323         if (!d->m_placemarkItem) {
0324             QQmlContext * context = new QQmlContext(qmlContext(d->m_placemarkDelegate));
0325             QObject * component = d->m_placemarkDelegate->create(context);
0326             d->m_placemarkItem = qobject_cast<QQuickItem*>( component );
0327             if (d->m_placemarkItem) {
0328                 d->m_placemarkItem->setParentItem( this );
0329                 d->m_placemarkItem->setProperty("placemark", QVariant::fromValue(d->m_placemark));
0330             } else {
0331                 delete component;
0332                 return;
0333             }
0334         }
0335 
0336         qreal x = 0;
0337         qreal y = 0;
0338         const bool visible = d->m_map.viewport()->screenCoordinates(d->m_placemark->placemark().coordinate(), x, y);
0339         d->m_placemarkItem->setVisible(visible);
0340         if (visible) {
0341             d->m_placemarkItem->setProperty("xPos", QVariant(x));
0342             d->m_placemarkItem->setProperty("yPos", QVariant(y));
0343         }
0344     }
0345 
0346     void MarbleQuickItem::handleReverseGeocoding(const GeoDataCoordinates &coordinates, const GeoDataPlacemark &placemark)
0347     {
0348         if (d->m_placemark && d->m_placemark->placemark().coordinate() == coordinates) {
0349             d->m_placemark->setGeoDataPlacemark(placemark);
0350             updatePlacemarks();
0351         }
0352     }
0353 
0354     void MarbleQuickItem::handleVisibleLatLonAltBoxChanged(const GeoDataLatLonAltBox &latLonAltBox)
0355     {
0356         Q_UNUSED(latLonAltBox)
0357 
0358         if (d->m_heading != d->m_map.heading()) {
0359             d->m_heading = d->m_map.heading();
0360             emit headingChanged(d->m_heading);
0361         }
0362         emit visibleLatLonAltBoxChanged();
0363         emit geoItemUpdateRequested();
0364     }
0365 
0366     void MarbleQuickItem::paint(QPainter *painter)
0367     {   //TODO - much to be done here still, i.e paint !enabled version
0368         QPaintDevice * paintDevice = painter->device();
0369         QRect rect = contentsBoundingRect().toRect();
0370 
0371         painter->end();
0372         {
0373             GeoPainter geoPainter(paintDevice, d->m_map.viewport(), d->m_map.mapQuality());
0374 
0375             double scale = 1.0;
0376             // For HighDPI displays take QT_SCALE_FACTOR into account:
0377             QQuickWindow * window = this->window();
0378             if (window) {
0379                 QScreen * screen = window->screen();
0380                 scale = screen != nullptr ? screen->devicePixelRatio() : 1.0;
0381                 if (scale != 1) {
0382                     geoPainter.scale(scale, scale);
0383                 }
0384             }
0385 
0386             d->m_map.paint(geoPainter, rect);
0387         }
0388         painter->begin(paintDevice);
0389     }
0390 
0391     void MarbleQuickItem::classBegin()
0392     {
0393     }
0394 
0395     void MarbleQuickItem::componentComplete()
0396     {
0397     }
0398 
0399     void Marble::MarbleQuickItem::MarbleQuickItem::hoverMoveEvent(QHoverEvent *event) {
0400         if (d->m_hoverEnabled) {
0401             emit hoverPositionChanged(event->pos());
0402         }
0403         QQuickItem::hoverMoveEvent(event);
0404     }
0405 
0406     int MarbleQuickItem::mapWidth() const
0407     {
0408         return d->m_map.width();
0409     }
0410 
0411     int MarbleQuickItem::mapHeight() const
0412     {
0413         return d->m_map.height();
0414     }
0415 
0416     bool MarbleQuickItem::showFrameRate() const
0417     {
0418         return d->m_map.showFrameRate();
0419     }
0420 
0421     MarbleQuickItem::Projection MarbleQuickItem::projection() const
0422     {
0423         return Projection(d->m_map.projection());
0424     }
0425 
0426     QString MarbleQuickItem::mapThemeId() const
0427     {
0428         return d->m_map.mapThemeId();
0429     }
0430 
0431     Marble::MapTheme *MarbleQuickItem::mapTheme() const
0432     {
0433         return &d->m_mapTheme;
0434     }
0435 
0436     bool MarbleQuickItem::showAtmosphere() const
0437     {
0438         return d->m_map.showAtmosphere();
0439     }
0440 
0441     bool MarbleQuickItem::showCompass() const
0442     {
0443         return d->m_map.showCompass();
0444     }
0445 
0446     bool MarbleQuickItem::showClouds() const
0447     {
0448         return d->m_map.showClouds();
0449     }
0450 
0451     bool MarbleQuickItem::showCrosshairs() const
0452     {
0453         return d->m_map.showCrosshairs();
0454     }
0455 
0456     bool MarbleQuickItem::showGrid() const
0457     {
0458         return d->m_map.showGrid();
0459     }
0460 
0461     bool MarbleQuickItem::showOverviewMap() const
0462     {
0463         return d->m_map.showOverviewMap();
0464     }
0465 
0466     bool MarbleQuickItem::showOtherPlaces() const
0467     {
0468         return d->m_map.showOtherPlaces();
0469     }
0470 
0471     bool MarbleQuickItem::showScaleBar() const
0472     {
0473         return d->m_showScaleBar;
0474     }
0475 
0476     bool MarbleQuickItem::showBackground() const
0477     {
0478         return d->m_map.showBackground();
0479     }
0480 
0481     bool MarbleQuickItem::showPositionMarker() const
0482     {
0483         QList<RenderPlugin *> plugins = d->m_map.renderPlugins();
0484         for (const RenderPlugin * plugin: plugins) {
0485             if (plugin->nameId() == QLatin1String("positionMarker")) {
0486                 return plugin->visible();
0487             }
0488         }
0489         return false;
0490     }
0491 
0492     bool MarbleQuickItem::showPublicTransport() const
0493     {
0494         return d->m_showPublicTransport;
0495     }
0496 
0497     bool MarbleQuickItem::showOutdoorActivities() const
0498     {
0499         return d->m_showOutdoorActivities;
0500     }
0501 
0502     QString MarbleQuickItem::positionProvider() const
0503     {
0504         if ( d->m_model.positionTracking()->positionProviderPlugin() ) {
0505             return d->m_model.positionTracking()->positionProviderPlugin()->nameId();
0506         }
0507 
0508         return QString();
0509     }
0510 
0511     MarbleModel* MarbleQuickItem::model()
0512     {
0513         return &d->m_model;
0514     }
0515 
0516     const MarbleModel* MarbleQuickItem::model() const
0517     {
0518         return &d->m_model;
0519     }
0520 
0521     MarbleMap* MarbleQuickItem::map()
0522     {
0523         return &d->m_map;
0524     }
0525 
0526     const MarbleMap* MarbleQuickItem::map() const
0527     {
0528         return &d->m_map;
0529     }
0530 
0531     bool MarbleQuickItem::inertialGlobeRotation() const
0532     {
0533         return d->m_inputHandler.inertialEarthRotationEnabled();
0534     }
0535 
0536     bool MarbleQuickItem::animationViewContext() const
0537     {
0538         return d->m_map.viewContext() == Animation;
0539     }
0540 
0541     bool MarbleQuickItem::animationsEnabled() const
0542     {
0543         return d->m_presenter.animationsEnabled();
0544     }
0545 
0546     QQmlComponent *MarbleQuickItem::placemarkDelegate() const
0547     {
0548         return d->m_placemarkDelegate;
0549     }
0550 
0551     void MarbleQuickItem::reverseGeocoding(const QPoint &point)
0552     {
0553         qreal lon, lat;
0554         d->m_map.viewport()->geoCoordinates(point.x(), point.y(), lon, lat);
0555         auto const coordinates = GeoDataCoordinates(lon, lat, 0.0, GeoDataCoordinates::Degree);
0556         delete d->m_placemarkItem;
0557         d->m_placemarkItem = nullptr;
0558         delete d->m_placemark;
0559         d->m_placemark = new Placemark(this);
0560         d->m_placemark->placemark().setCoordinate(coordinates);
0561         d->m_reverseGeocoding.reverseGeocoding(coordinates);
0562     }
0563 
0564     bool MarbleQuickItem::hoverEnabled() const
0565     {
0566         return d->m_hoverEnabled;
0567     }
0568 
0569     void MarbleQuickItem::moveUp()
0570     {
0571         d->m_presenter.moveByStep( 0, -1, Marble::Linear );
0572     }
0573 
0574     void MarbleQuickItem::moveDown()
0575     {
0576         d->m_presenter.moveByStep( 0, 1, Marble::Linear );
0577     }
0578 
0579     void MarbleQuickItem::moveLeft()
0580     {
0581         d->m_presenter.moveByStep( -1, 0, Marble::Linear );
0582     }
0583 
0584     void MarbleQuickItem::moveRight()
0585     {
0586         d->m_presenter.moveByStep( 1, 0, Marble::Linear );
0587     }
0588 
0589     qreal MarbleQuickItem::speed() const
0590     {
0591         return d->m_model.positionTracking()->speed();
0592     }
0593 
0594     qreal MarbleQuickItem::angle() const
0595     {
0596         bool routeExists = d->m_model.routingManager()->routingModel()->route().distance() != 0.0;
0597         bool onRoute = !d->m_model.routingManager()->routingModel()->deviatedFromRoute();
0598         if ( routeExists && onRoute) {
0599             GeoDataCoordinates curPoint = d->m_model.positionTracking()->positionProviderPlugin()->position();
0600             return d->m_model.routingManager()->routingModel()->route().currentSegment().projectedDirection(curPoint);
0601         } else {
0602             return d->m_model.positionTracking()->direction();
0603         }
0604     }
0605 
0606     bool MarbleQuickItem::positionAvailable() const
0607     {
0608         return d->m_model.positionTracking()->status() == PositionProviderStatusAvailable;
0609     }
0610 
0611     bool MarbleQuickItem::positionVisible() const
0612     {
0613         return d->m_positionVisible;
0614     }
0615 
0616     qreal MarbleQuickItem::distanceFromPointToCurrentLocation(const QPoint & position) const
0617     {
0618         if ( positionAvailable() ) {
0619             qreal lon1;
0620             qreal lat1;
0621             d->m_map.viewport()->geoCoordinates(position.x(), position.y(), lon1, lat1, GeoDataCoordinates::Radian );
0622 
0623             GeoDataCoordinates currentCoordinates = d->m_model.positionTracking()->currentLocation();
0624             qreal lon2 = currentCoordinates.longitude();
0625             qreal lat2 = currentCoordinates.latitude();
0626 
0627             return distanceSphere(lon1, lat1, lon2, lat2) * d->m_model.planetRadius();
0628         }
0629         return 0;
0630     }
0631 
0632     qreal MarbleQuickItem::angleFromPointToCurrentLocation( const QPoint & position ) const
0633     {
0634         if ( positionAvailable() ) {
0635             qreal x, y;
0636             PositionTracking const * positionTracking = d->m_model.positionTracking();
0637             map()->viewport()->screenCoordinates( positionTracking->currentLocation(), x, y );
0638             return atan2( y-position.y(), x-position.x() ) * RAD2DEG;
0639         }
0640         return 0;
0641     }
0642 
0643     Placemark * MarbleQuickItem::currentPosition() const
0644     {
0645         return &d->m_currentPosition;
0646     }
0647 
0648     QPointF MarbleQuickItem::screenCoordinatesFromCoordinate(Coordinate * coordinate) const
0649     {
0650         qreal x, y;
0651         bool globeHidesPoint;
0652         bool const valid = d->m_map.viewport()->screenCoordinates(coordinate->coordinates(), x, y, globeHidesPoint);
0653         bool isVisible = valid && !globeHidesPoint;
0654         return isVisible ? QPointF(x, y) : QPointF();
0655     }
0656 
0657     QPointF MarbleQuickItem::screenCoordinatesFromGeoDataCoordinates(const GeoDataCoordinates & coordinates) const
0658     {
0659         qreal x, y;
0660         bool globeHidesPoint;
0661         d->m_map.viewport()->screenCoordinates(coordinates, x, y, globeHidesPoint);
0662         return !globeHidesPoint ? QPointF(x, y) : QPointF();
0663     }
0664 
0665     bool MarbleQuickItem::screenCoordinatesFromGeoDataLineString(const GeoDataLineString &lineString, QVector<QPolygonF *> &polygons) const
0666     {
0667         return d->m_map.viewport()->screenCoordinates(lineString, polygons);
0668     }
0669 
0670     bool MarbleQuickItem::screenCoordinatesToCoordinate(const QPoint & point, Coordinate * coordinate)
0671     {
0672         GeoDataCoordinates geoDataCoordinates;
0673         bool success = screenCoordinatesToGeoDataCoordinates(point, geoDataCoordinates);
0674         if (!qobject_cast<Coordinate*>(coordinate)){
0675             Coordinate * tmp(coordinate);
0676             coordinate = new Coordinate(geoDataCoordinates.longitude(), geoDataCoordinates.latitude(), 0, nullptr);
0677             QQmlEngine::setObjectOwnership(coordinate, QQmlEngine::JavaScriptOwnership);
0678             delete tmp;
0679         }
0680         else {
0681             coordinate->setLongitude(geoDataCoordinates.longitude());
0682             coordinate->setLatitude(geoDataCoordinates.latitude());
0683         }
0684 
0685         return success;
0686     }
0687 
0688     bool MarbleQuickItem::screenCoordinatesToGeoDataCoordinates(const QPoint & point, GeoDataCoordinates & coordinates)
0689     {
0690         qreal lon = 0.0 , lat = 0.0;
0691         bool const valid = d->m_map.viewport()->geoCoordinates(point.x(), point.y(), lon, lat);
0692         coordinates.setLongitude(lon);
0693         coordinates.setLatitude(lat);
0694         return valid;
0695     }
0696 
0697     void MarbleQuickItem::setRadius(int radius)
0698     {
0699         d->m_map.setRadius(radius);
0700     }
0701 
0702     void MarbleQuickItem::setHeading(qreal heading)
0703     {
0704         if (qFuzzyCompare(d->m_heading, heading))
0705             return;
0706 
0707         d->m_map.setHeading(heading);
0708         d->m_heading = heading;
0709 
0710         emit headingChanged(d->m_heading);
0711     }
0712 
0713     void MarbleQuickItem::setHoverEnabled(bool hoverEnabled)
0714     {
0715         if (d->m_hoverEnabled == hoverEnabled)
0716             return;
0717 
0718         d->m_hoverEnabled = hoverEnabled;
0719 
0720         setAcceptHoverEvents(hoverEnabled);
0721         setFlag(ItemAcceptsInputMethod, hoverEnabled);
0722 
0723         emit hoverEnabledChanged(d->m_hoverEnabled);
0724     }
0725 
0726     void MarbleQuickItem::setZoom(int newZoom, FlyToMode mode)
0727     {
0728         d->m_presenter.setZoom(newZoom, mode);
0729     }
0730 
0731     void MarbleQuickItem::setZoomToMaximumLevel()
0732     {
0733         d->m_presenter.setZoom(d->m_map.maximumZoom());
0734     }
0735 
0736     void MarbleQuickItem::centerOn(const GeoDataPlacemark& placemark, bool animated)
0737     {
0738         d->m_presenter.centerOn(placemark, animated);
0739     }
0740 
0741     void MarbleQuickItem::centerOn(const GeoDataLatLonBox& box, bool animated)
0742     {
0743         d->m_presenter.centerOn(box, animated);
0744     }
0745 
0746     void MarbleQuickItem::centerOn(const GeoDataCoordinates &coordinate)
0747     {
0748         GeoDataLookAt target = d->m_presenter.lookAt();
0749         target.setCoordinates(coordinate);
0750         d->m_presenter.flyTo(target, Automatic);
0751     }
0752 
0753     void MarbleQuickItem::centerOn(qreal longitude, qreal latitude)
0754     {
0755         d->m_presenter.centerOn(longitude, latitude);
0756     }
0757 
0758     void MarbleQuickItem::centerOnCoordinates(qreal longitude, qreal latitude) {
0759         centerOn(longitude, latitude);
0760     }
0761 
0762     void MarbleQuickItem::centerOnCurrentPosition()
0763     {
0764         GeoDataCoordinates coordinates = d->m_model.positionTracking()->currentLocation();
0765         if ( coordinates == GeoDataCoordinates() ) {
0766             return;
0767         }
0768 
0769         d->m_presenter.centerOn(coordinates, true);
0770         if (d->m_presenter.zoom() < 3000) {
0771             d->m_presenter.setZoom(3500);
0772         }
0773     }
0774 
0775     void MarbleQuickItem::selectPlacemarkAt(int x, int y)
0776     {
0777         auto features = d->m_map.whichFeatureAt(QPoint(x, y));
0778         QVector<GeoDataPlacemark const *> placemarks;
0779         for(auto feature: features) {
0780             if (const auto placemark = geodata_cast<GeoDataPlacemark>(feature)) {
0781                 placemarks << placemark;
0782             }
0783         }
0784 
0785         for(auto placemark: placemarks) {
0786             if (d->m_placemark && placemark->coordinate() == d->m_placemark->placemark().coordinate()) {
0787                 d->m_placemark->deleteLater();
0788                 d->m_placemark = nullptr;
0789             } else {
0790                 if (d->m_placemark) {
0791                     d->m_placemark->deleteLater();
0792                 }
0793                 d->m_placemark = new Placemark(this);
0794                 d->m_placemark->setGeoDataPlacemark(*placemark);
0795             }
0796             delete d->m_placemarkItem;
0797             d->m_placemarkItem = nullptr;
0798             updatePlacemarks();
0799             return;
0800         }
0801 
0802         if (d->m_placemark) {
0803             d->m_placemark->deleteLater();
0804             d->m_placemark = nullptr;
0805             delete d->m_placemarkItem;
0806             d->m_placemarkItem = nullptr;
0807             updatePlacemarks();
0808         }
0809     }
0810 
0811     void MarbleQuickItem::goHome()
0812     {
0813         d->m_presenter.goHome();
0814     }
0815 
0816     void MarbleQuickItem::zoomIn(FlyToMode mode)
0817     {
0818         d->m_presenter.zoomIn(mode);
0819     }
0820 
0821     void MarbleQuickItem::zoomOut(FlyToMode mode)
0822     {
0823         d->m_presenter.zoomOut(mode);
0824     }
0825 
0826     void MarbleQuickItem::handlePinchStarted(const QPointF &point)
0827     {
0828         pinch(point, 1, Qt::GestureStarted);
0829     }
0830 
0831     void MarbleQuickItem::handlePinchFinished(const QPointF &point)
0832     {
0833         pinch(point, 1, Qt::GestureFinished);
0834     }
0835 
0836     void MarbleQuickItem::handlePinchUpdated(const QPointF &point, qreal scale)
0837     {
0838         scale = sqrt(sqrt(scale));
0839         scale = qBound(static_cast<qreal>(0.5), scale, static_cast<qreal>(2.0));
0840         pinch(point, scale, Qt::GestureUpdated);
0841     }
0842 
0843     void MarbleQuickItem::setMapWidth(int mapWidth)
0844     {
0845         if (d->m_map.width() == mapWidth) {
0846             return;
0847         }
0848 
0849         d->m_map.setSize(mapWidth, mapHeight());
0850         emit mapWidthChanged(mapWidth);
0851     }
0852 
0853     void MarbleQuickItem::setMapHeight(int mapHeight)
0854     {
0855         if (this->mapHeight() == mapHeight) {
0856             return;
0857         }
0858 
0859         d->m_map.setSize(mapWidth(), mapHeight);
0860         emit mapHeightChanged(mapHeight);
0861     }
0862 
0863     void MarbleQuickItem::setShowFrameRate(bool showFrameRate)
0864     {
0865         if (this->showFrameRate() == showFrameRate) {
0866             return;
0867         }
0868 
0869         d->m_map.setShowFrameRate(showFrameRate);
0870         emit showFrameRateChanged(showFrameRate);
0871     }
0872 
0873     void MarbleQuickItem::setProjection(Projection projection)
0874     {
0875         if (this->projection() == projection) {
0876             return;
0877         }
0878 
0879         d->m_map.setProjection(Marble::Projection(projection));
0880         emit projectionChanged(projection);
0881     }
0882 
0883     void MarbleQuickItem::setMapThemeId(const QString& mapThemeId)
0884     {
0885         if (this->mapThemeId() == mapThemeId) {
0886             return;
0887         }
0888 
0889         bool invertColor = invertColorEnabled();
0890 
0891         bool const showCompass = d->m_map.showCompass();
0892         bool const showOverviewMap = d->m_map.showOverviewMap();
0893         bool const showOtherPlaces = d->m_map.showOtherPlaces();
0894         bool const showGrid = d->m_map.showGrid();
0895 
0896         d->m_map.setMapThemeId(mapThemeId);
0897 
0898         // Map themes are allowed to change properties. Enforce ours.
0899         d->m_map.setShowCompass(showCompass);
0900         d->m_map.setShowOverviewMap(showOverviewMap);
0901         d->m_map.setShowOtherPlaces(showOtherPlaces);
0902         d->m_map.setShowGrid(showGrid);
0903         d->m_map.setShowScaleBar(d->m_showScaleBar);
0904 
0905         emit mapThemeIdChanged(mapThemeId);
0906 
0907         setInvertColorEnabled(invertColor);
0908     }
0909 
0910     void MarbleQuickItem::setShowAtmosphere(bool showAtmosphere)
0911     {
0912         if (this->showAtmosphere() == showAtmosphere) {
0913             return;
0914         }
0915 
0916         d->m_map.setShowAtmosphere(showAtmosphere);
0917         emit showAtmosphereChanged(showAtmosphere);
0918     }
0919 
0920     void MarbleQuickItem::setShowCompass(bool showCompass)
0921     {
0922         if (this->showCompass() == showCompass) {
0923             return;
0924         }
0925 
0926         d->m_map.setShowCompass(showCompass);
0927         emit showCompassChanged(showCompass);
0928     }
0929 
0930     void MarbleQuickItem::setShowClouds(bool showClouds)
0931     {
0932         if (this->showClouds() == showClouds) {
0933             return;
0934         }
0935 
0936         d->m_map.setShowClouds(showClouds);
0937         emit showCloudsChanged(showClouds);
0938     }
0939 
0940     void MarbleQuickItem::setShowCrosshairs(bool showCrosshairs)
0941     {
0942         if (this->showCrosshairs() == showCrosshairs) {
0943             return;
0944         }
0945 
0946         d->m_map.setShowCrosshairs(showCrosshairs);
0947         emit showCrosshairsChanged(showCrosshairs);
0948     }
0949 
0950     void MarbleQuickItem::setShowGrid(bool showGrid)
0951     {
0952         if (this->showGrid() == showGrid) {
0953             return;
0954         }
0955 
0956         d->m_map.setShowGrid(showGrid);
0957         emit showGridChanged(showGrid);
0958     }
0959 
0960     void MarbleQuickItem::setShowOverviewMap(bool showOverviewMap)
0961     {
0962         if (this->showOverviewMap() == showOverviewMap) {
0963             return;
0964         }
0965 
0966         d->m_map.setShowOverviewMap(showOverviewMap);
0967         emit showOverviewMapChanged(showOverviewMap);
0968     }
0969 
0970     void MarbleQuickItem::setShowOtherPlaces(bool showOtherPlaces)
0971     {
0972         if (this->showOtherPlaces() == showOtherPlaces) {
0973             return;
0974         }
0975 
0976         d->m_map.setShowOtherPlaces(showOtherPlaces);
0977         emit showOtherPlacesChanged(showOtherPlaces);
0978     }
0979 
0980     void MarbleQuickItem::setShowScaleBar(bool showScaleBar)
0981     {
0982         if (d->m_showScaleBar == showScaleBar) {
0983             return;
0984         }
0985 
0986         d->m_showScaleBar = showScaleBar;
0987         d->m_map.setShowScaleBar(d->m_showScaleBar);
0988         emit showScaleBarChanged(showScaleBar);
0989     }
0990 
0991     void MarbleQuickItem::setShowBackground(bool showBackground)
0992     {
0993         if (this->showBackground() == showBackground) {
0994             return;
0995         }
0996 
0997         d->m_map.setShowBackground(showBackground);
0998         emit showBackgroundChanged(showBackground);
0999     }
1000 
1001     void MarbleQuickItem::setShowPositionMarker(bool showPositionMarker)
1002     {
1003         if (this->showPositionMarker() == showPositionMarker) {
1004             return;
1005         }
1006 
1007         QList<RenderPlugin *> plugins = d->m_map.renderPlugins();
1008         for ( RenderPlugin * plugin: plugins ) {
1009             if (plugin->nameId() == QLatin1String("positionMarker")) {
1010                 plugin->setVisible(showPositionMarker);
1011                 break;
1012             }
1013         }
1014 
1015         emit showPositionMarkerChanged(showPositionMarker);
1016     }
1017 
1018     void MarbleQuickItem::setShowPublicTransport(bool enabled)
1019     {
1020         if (d->m_showPublicTransport != enabled) {
1021             d->m_showPublicTransport = enabled;
1022             d->updateVisibleRoutes();
1023             emit showPublicTransportChanged(enabled);
1024         }
1025     }
1026 
1027     void MarbleQuickItem::setShowOutdoorActivities(bool showOutdoorActivities)
1028     {
1029         if (d->m_showOutdoorActivities != showOutdoorActivities) {
1030             d->m_showOutdoorActivities = showOutdoorActivities;
1031             d->updateVisibleRoutes();
1032             emit showOutdoorActivitiesChanged(showOutdoorActivities);
1033         }
1034     }
1035 
1036     void MarbleQuickItem::setPositionProvider(const QString &positionProvider)
1037     {
1038         QString name;
1039         if ( d->m_model.positionTracking()->positionProviderPlugin() ) {
1040             name = d->m_model.positionTracking()->positionProviderPlugin()->nameId();
1041             if ( name == positionProvider ) {
1042                 return;
1043             }
1044         }
1045 
1046         if ( positionProvider.isEmpty() ) {
1047             d->m_model.positionTracking()->setPositionProviderPlugin( nullptr );
1048             return;
1049         }
1050 
1051         QList<const PositionProviderPlugin*> plugins = d->m_model.pluginManager()->positionProviderPlugins();
1052         for (const PositionProviderPlugin* plugin: plugins) {
1053             if ( plugin->nameId() == positionProvider) {
1054                 PositionProviderPlugin * newPlugin = plugin->newInstance();
1055                 d->m_model.positionTracking()->setPositionProviderPlugin(newPlugin);
1056                 connect(newPlugin, SIGNAL(statusChanged(PositionProviderStatus)), this, SLOT(positionDataStatusChanged(PositionProviderStatus)));
1057                 connect(newPlugin, SIGNAL(positionChanged(GeoDataCoordinates,GeoDataAccuracy)), this, SLOT(updateCurrentPosition(GeoDataCoordinates)));
1058                 connect(newPlugin, SIGNAL(positionChanged(GeoDataCoordinates,GeoDataAccuracy)), this, SIGNAL(speedChanged()));
1059                 connect(newPlugin, SIGNAL(positionChanged(GeoDataCoordinates,GeoDataAccuracy)), this, SIGNAL(angleChanged()));
1060                 emit positionProviderChanged(positionProvider);
1061                 break;
1062             }
1063         }
1064     }
1065 
1066     void MarbleQuickItem::setInertialGlobeRotation(bool inertialGlobeRotation)
1067     {
1068         if (inertialGlobeRotation == d->m_inputHandler.inertialEarthRotationEnabled()) {
1069             return;
1070         }
1071 
1072         d->m_inputHandler.setInertialEarthRotationEnabled(inertialGlobeRotation);
1073         emit inertialGlobeRotationChanged(inertialGlobeRotation);
1074     }
1075 
1076     void MarbleQuickItem::setAnimationViewContext(bool animationViewContext)
1077     {
1078         d->m_map.setViewContext(animationViewContext ? Animation : Still );
1079 
1080         emit inertialGlobeRotationChanged(animationViewContext);
1081     }
1082 
1083     void MarbleQuickItem::setAnimationsEnabled(bool animationsEnabled)
1084     {
1085         if (d->m_presenter.animationsEnabled() == animationsEnabled)
1086             return;
1087 
1088         d->m_presenter.setAnimationsEnabled(animationsEnabled);
1089         emit animationsEnabledChanged(d->m_presenter.animationsEnabled());
1090     }
1091 
1092     void MarbleQuickItem::setPluginSetting(const QString &pluginId, const QString &key, const QString &value)
1093     {
1094         for (RenderPlugin* plugin: d->m_map.renderPlugins()) {
1095             if (plugin->nameId() == pluginId) {
1096                 plugin->setSetting(key, value);
1097             }
1098         }
1099     }
1100 
1101     void MarbleQuickItem::setPropertyEnabled(const QString &property, bool enabled)
1102     {
1103         d->m_map.setPropertyValue(property, enabled);
1104     }
1105 
1106     bool MarbleQuickItem::isPropertyEnabled(const QString &property) const
1107     {
1108         return d->m_map.propertyValue(property);
1109     }
1110 
1111     void MarbleQuickItem::setWorkOffline(bool enabled)
1112     {
1113         if (d->m_map.model()->workOffline() == enabled)
1114             return;
1115 
1116         else {
1117             d->m_map.model()->setWorkOffline(enabled);
1118         }
1119     }
1120 
1121     void MarbleQuickItem::setInvertColorEnabled(bool enabled, const QString &blendingName)
1122     {
1123         d->changeBlending(enabled, blendingName);
1124 
1125         d->changeStyleBuilder(enabled);
1126 
1127         if (d->m_invertColorEnabled == enabled)
1128             return;
1129 
1130         d->m_invertColorEnabled = enabled;
1131 
1132         emit invertColorEnabledChanged(d->m_invertColorEnabled);
1133     }
1134 
1135     bool MarbleQuickItem::invertColorEnabled()
1136     {
1137         return d->m_invertColorEnabled;
1138     }
1139 
1140     bool MarbleQuickItem::workOffline()
1141     {
1142         return d->m_map.model()->workOffline();
1143     }
1144 
1145     void MarbleQuickItem::setShowRuntimeTrace(bool showRuntimeTrace)
1146     {
1147         d->m_map.setShowRuntimeTrace(showRuntimeTrace);
1148         update();
1149     }
1150 
1151     void MarbleQuickItem::setShowDebugPolygons(bool showDebugPolygons)
1152     {
1153         d->m_map.setShowDebugPolygons(showDebugPolygons);
1154         update();
1155     }
1156 
1157     void MarbleQuickItem::setShowDebugPlacemarks(bool showDebugPlacemarks)
1158     {
1159         d->m_map.setShowDebugPlacemarks(showDebugPlacemarks);
1160         update();
1161     }
1162 
1163     void MarbleQuickItem::setShowDebugBatches(bool showDebugBatches)
1164     {
1165         d->m_map.setShowDebugBatchRender(showDebugBatches);
1166         update();
1167     }
1168 
1169     void MarbleQuickItem::setPlacemarkDelegate(QQmlComponent *placemarkDelegate)
1170     {
1171         if (d->m_placemarkDelegate == placemarkDelegate) {
1172             return;
1173         }
1174 
1175         delete d->m_placemarkItem;
1176         d->m_placemarkItem = nullptr;
1177         d->m_placemarkDelegate = placemarkDelegate;
1178         emit placemarkDelegateChanged(placemarkDelegate);
1179     }
1180 
1181     void MarbleQuickItem::loadSettings()
1182     {
1183         QSettings settings;
1184         settings.beginGroup(QStringLiteral("MarbleQuickItem"));
1185         double lon = settings.value(QStringLiteral("centerLon"), QVariant(0.0)).toDouble();
1186         double lat = settings.value(QStringLiteral("centerLat"), QVariant(0.0)).toDouble();
1187         if (lat == 0.0 && lon == 0.0) {
1188             centerOnCurrentPosition();
1189         } else {
1190             centerOn(lon, lat);
1191         }
1192         int const zoom = settings.value(QStringLiteral("zoom"), QVariant(0)).toInt();
1193         if (zoom > 0) {
1194             setZoom(zoom);
1195         }
1196         auto const defaultRelationTypes = QStringList() << "ferry" << "train" << "subway" << "tram" << "bus" << "trolley-bus" << "hiking";
1197         auto const visibleRelationTypes = settings.value(QStringLiteral("visibleRelationTypes"), defaultRelationTypes).toStringList();
1198         d->m_enabledRelationTypes = GeoDataRelation::UnknownType;
1199         for (auto const &route: visibleRelationTypes) {
1200             d->m_enabledRelationTypes |= d->m_relationTypeConverter.value(route, GeoDataRelation::UnknownType);
1201         }
1202         setShowPublicTransport(settings.value(QStringLiteral("showPublicTransport"), false).toBool());
1203         setShowOutdoorActivities(settings.value(QStringLiteral("showOutdoorActivities"), false).toBool());
1204         settings.endGroup();
1205         d->m_model.routingManager()->readSettings();
1206         d->m_model.bookmarkManager()->loadFile(QStringLiteral("bookmarks/bookmarks.kml"));
1207         d->m_model.bookmarkManager()->setShowBookmarks(true);
1208         d->updateVisibleRoutes();
1209     }
1210 
1211     void MarbleQuickItem::writeSettings()
1212     {
1213         QSettings settings;
1214         settings.beginGroup(QStringLiteral("MarbleQuickItem"));
1215         settings.setValue(QStringLiteral("centerLon"), QVariant(d->m_map.centerLongitude()));
1216         settings.setValue(QStringLiteral("centerLat"), QVariant(d->m_map.centerLatitude()));
1217         settings.setValue(QStringLiteral("zoom"), QVariant(zoom()));
1218         QStringList enabledRoutes;
1219         QMap<GeoDataRelation::RelationType, QString> relationConverter;
1220         for (auto iter = d->m_relationTypeConverter.cbegin(), end = d->m_relationTypeConverter.cend(); iter != end; ++iter) {
1221             relationConverter[iter.value()] = iter.key();
1222         }
1223         for (auto iter = relationConverter.cbegin(), end = relationConverter.cend(); iter != end; ++iter) {
1224             if (d->m_enabledRelationTypes & iter.key()) {
1225                 enabledRoutes << iter.value();
1226             }
1227         }
1228         settings.setValue(QStringLiteral("visibleRelationTypes"), enabledRoutes);
1229         settings.setValue(QStringLiteral("showPublicTransport"), d->m_showPublicTransport);
1230         settings.setValue(QStringLiteral("showOutdoorActivities"), d->m_showOutdoorActivities);
1231 
1232         settings.endGroup();
1233         d->m_model.routingManager()->writeSettings();
1234     }
1235 
1236     void MarbleQuickItem::reloadTiles()
1237     {
1238         d->m_map.reload();
1239     }
1240 
1241     void MarbleQuickItem::highlightRouteRelation(qint64 osmId, bool enabled)
1242     {
1243         d->m_map.highlightRouteRelation(osmId, enabled);
1244     }
1245 
1246     void MarbleQuickItem::setRelationTypeVisible(const QString &relationType, bool visible)
1247     {
1248         auto const relation = d->m_relationTypeConverter.value(relationType, GeoDataRelation::UnknownType);
1249         if (visible) {
1250             d->m_enabledRelationTypes |= relation;
1251         } else {
1252             d->m_enabledRelationTypes &= ~relation;
1253         }
1254         d->updateVisibleRoutes();
1255     }
1256 
1257     bool MarbleQuickItem::isRelationTypeVisible(const QString &relationType) const
1258     {
1259         auto const relation = d->m_relationTypeConverter.value(relationType, GeoDataRelation::UnknownType);
1260         return d->m_enabledRelationTypes & relation;
1261     }
1262 
1263     QObject *MarbleQuickItem::getEventFilter() const
1264     {   //We would want to install the same event filter for abstract layer QuickItems such as PinchArea
1265         return &d->m_inputHandler;
1266     }
1267 
1268     void MarbleQuickItem::pinch(const QPointF& center, qreal scale, Qt::GestureState state)
1269     {
1270         d->m_inputHandler.pinch(center, scale, state);
1271     }
1272 
1273     MarbleInputHandler *MarbleQuickItem::inputHandler()
1274     {
1275         return &d->m_inputHandler;
1276     }
1277 
1278     int MarbleQuickItem::radius() const
1279     {
1280         return d->m_map.radius();
1281     }
1282 
1283     qreal MarbleQuickItem::heading() const
1284     {
1285         return d->m_map.heading();
1286     }
1287 
1288 
1289     int MarbleQuickItem::zoom() const
1290     {
1291         return d->m_presenter.logzoom();
1292     }
1293 
1294     int MarbleQuickItem::minimumZoom() const
1295     {
1296         return d->m_presenter.minimumZoom();
1297     }
1298 
1299     int MarbleQuickItem::maximumZoom() const
1300     {
1301         return d->m_presenter.maximumZoom();
1302     }
1303 
1304     bool MarbleQuickItem::layersEventFilter(QObject *, QEvent *)
1305     {   //Does nothing, but can be reimplemented in a subclass
1306         return false;
1307     }
1308 
1309     QuickItemSelectionRubber::QuickItemSelectionRubber() :
1310         m_visible(false)
1311     {
1312         // nothing to do
1313     }
1314 
1315     void MarbleQuickItemPrivate::updateVisibleRoutes()
1316     {
1317         GeoDataRelation::RelationTypes relationTypes = m_enabledRelationTypes;
1318         if (!m_showPublicTransport) {
1319             relationTypes &= ~GeoDataRelation::RouteTrain;
1320             relationTypes &= ~GeoDataRelation::RouteSubway;
1321             relationTypes &= ~GeoDataRelation::RouteTram;
1322             relationTypes &= ~GeoDataRelation::RouteBus;
1323             relationTypes &= ~GeoDataRelation::RouteTrolleyBus;
1324         }
1325         if (!m_showOutdoorActivities) {
1326             relationTypes &= ~GeoDataRelation::RouteBicycle;
1327             relationTypes &= ~GeoDataRelation::RouteMountainbike;
1328             relationTypes &= ~GeoDataRelation::RouteFoot;
1329             relationTypes &= ~GeoDataRelation::RouteHiking;
1330             relationTypes &= ~GeoDataRelation::RouteHorse;
1331             relationTypes &= ~GeoDataRelation::RouteInlineSkates;
1332             relationTypes &= ~GeoDataRelation::RouteSkiDownhill;
1333             relationTypes &= ~GeoDataRelation::RouteSkiNordic;
1334             relationTypes &= ~GeoDataRelation::RouteSkitour;
1335             relationTypes &= ~GeoDataRelation::RouteSled;
1336         }
1337         m_map.setVisibleRelationTypes(relationTypes);
1338     }
1339 
1340     void MarbleQuickItemPrivate::changeBlending(bool enabled, const QString &blendingName)
1341     {
1342         GeoSceneDocument * mapTheme = m_map.model()->mapTheme();
1343         if (mapTheme == nullptr) return;
1344 
1345         GeoSceneMap * map = mapTheme->map();
1346         if (map == nullptr) return;
1347 
1348         GeoSceneTextureTileDataset * textureDataset = nullptr;
1349         if (map->hasTextureLayers()) {
1350             for (auto layer : map->layers()) {
1351                 for (auto dataset : layer->datasets()) {
1352                     if (dataset->nodeType() == GeoSceneTypes::GeoSceneTextureTileType) {
1353                         textureDataset = dynamic_cast<GeoSceneTextureTileDataset*>(dataset);
1354                         break;
1355                     }
1356                 }
1357             }
1358             if (textureDataset == nullptr) return;
1359             if (enabled && textureDataset->blending().isEmpty()) {
1360                 textureDataset->setBlending(blendingName);
1361                 m_map.clearVolatileTileCache();
1362             }
1363             else if (!enabled && textureDataset->blending() == blendingName) {
1364                 textureDataset->setBlending("");
1365                 m_map.clearVolatileTileCache();
1366             }
1367         }
1368     }
1369 
1370     void MarbleQuickItemPrivate::changeStyleBuilder(bool invert)
1371     {
1372         GeoSceneDocument * mapTheme = m_map.model()->mapTheme();
1373         if (mapTheme == nullptr) return;
1374 
1375         GeoSceneMap * map = mapTheme->map();
1376         if (map == nullptr) return;
1377 
1378         if (map->hasVectorLayers()) {
1379             StyleBuilder * styleBuilder = const_cast<StyleBuilder*>(m_map.styleBuilder());
1380 
1381             if (invert) {
1382                 styleBuilder->setStyleEffect(InvertedEffect);
1383             }
1384             else {
1385                 styleBuilder->setStyleEffect(NoEffect);
1386             }
1387             styleBuilder->reset();
1388             // trigger groundlayer update
1389             emit m_map.model()->themeChanged(QString());
1390         }
1391     }
1392 }
1393 
1394 #include "moc_MarbleQuickItem.cpp"