File indexing completed on 2024-04-14 03:47:54

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2006-2007 Torsten Rahn <tackat@kde.org>
0004 // SPDX-FileCopyrightText: 2007 Inge Wallin <ingwa@kde.org>
0005 // SPDX-FileCopyrightText: 2008, 2009, 2010 Jens-Michael Hoffmann <jmho@c-xx.com>
0006 // SPDX-FileCopyrightText: 2008-2009 Patrick Spendrin <ps_ml@gmx.de>
0007 // SPDX-FileCopyrightText: 2010-2013 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
0008 // SPDX-FileCopyrightText: 2014 Abhinav Gangwar <abhgang@gmail.com>
0009 //
0010 
0011 #include "MarbleModel.h"
0012 
0013 #include <cmath>
0014 
0015 #include <QAtomicInt>
0016 #include <QPointer>
0017 #include <QAbstractItemModel>
0018 #include <QItemSelectionModel>
0019 #include <QSortFilterProxyModel>
0020 #include <QTextDocument>
0021 
0022 #include "kdescendantsproxymodel.h"
0023 
0024 #include "MapThemeManager.h"
0025 #include "MarbleDebug.h"
0026 
0027 #include "GeoSceneDocument.h"
0028 #include "GeoSceneGeodata.h"
0029 #include "GeoSceneHead.h"
0030 #include "GeoSceneLayer.h"
0031 #include "GeoSceneMap.h"
0032 #include "GeoScenePalette.h"
0033 #include "GeoSceneTileDataset.h"
0034 #include "GeoSceneVector.h"
0035 
0036 #include "GeoDataDocument.h"
0037 #include "GeoDataFeature.h"
0038 #include "GeoDataPlacemark.h"
0039 #include "GeoDataPoint.h"
0040 #include "GeoDataStyle.h"
0041 #include "GeoDataStyleMap.h"
0042 #include "GeoDataTrack.h"
0043 #include "GeoDataLineStyle.h"
0044 #include "GeoDataPolyStyle.h"
0045 #include "GeoDataTypes.h"
0046 
0047 #include "DgmlAuxillaryDictionary.h"
0048 #include "MarbleClock.h"
0049 #include "FileStoragePolicy.h"
0050 #include "FileStorageWatcher.h"
0051 #include "PositionTracking.h"
0052 #include "HttpDownloadManager.h"
0053 #include "MarbleDirs.h"
0054 #include "FileManager.h"
0055 #include "GeoDataTreeModel.h"
0056 #include "PlacemarkPositionProviderPlugin.h"
0057 #include "Planet.h"
0058 #include "PlanetFactory.h"
0059 #include "PluginManager.h"
0060 #include "StoragePolicy.h"
0061 #include "SunLocator.h"
0062 #include "TileCreator.h"
0063 #include "TileCreatorDialog.h"
0064 #include "TileLoader.h"
0065 #include "routing/RoutingManager.h"
0066 #include "RouteSimulationPositionProviderPlugin.h"
0067 #include "BookmarkManager.h"
0068 #include "ElevationModel.h"
0069 
0070 namespace Marble
0071 {
0072 
0073 class MarbleModelPrivate
0074 {
0075  public:
0076     MarbleModelPrivate()
0077         : m_clock(),
0078           m_planet(PlanetFactory::construct(QStringLiteral("earth"))),
0079           m_sunLocator( &m_clock, &m_planet ),
0080           m_pluginManager(),
0081           m_homePoint( -9.4, 54.8, 0.0, GeoDataCoordinates::Degree ),  // Some point that tackat defined. :-)
0082           m_homeZoom( 1050 ),
0083           m_mapTheme( nullptr ),
0084           m_storagePolicy( MarbleDirs::localPath() ),
0085           m_downloadManager( &m_storagePolicy ),
0086           m_storageWatcher( MarbleDirs::localPath() ),
0087           m_treeModel(),
0088           m_descendantProxy(),
0089           m_placemarkProxyModel(),
0090           m_placemarkSelectionModel( nullptr ),
0091           m_fileManager( &m_treeModel, &m_pluginManager ),
0092           m_positionTracking( &m_treeModel ),
0093           m_trackedPlacemark( nullptr ),
0094           m_bookmarkManager( &m_treeModel ),
0095           m_routingManager( nullptr ),
0096           m_legend( nullptr ),
0097           m_workOffline( false ),
0098           m_elevationModel( &m_downloadManager, &m_pluginManager )
0099     {
0100         m_descendantProxy.setSourceModel( &m_treeModel );
0101 
0102         m_placemarkProxyModel.setFilterFixedString( GeoDataTypes::GeoDataPlacemarkType );
0103         m_placemarkProxyModel.setFilterKeyColumn( 1 );
0104         m_placemarkProxyModel.setSourceModel( &m_descendantProxy );
0105         m_placemarkSelectionModel.setModel(&m_placemarkProxyModel);
0106 
0107         m_groundOverlayProxyModel.setFilterFixedString( GeoDataTypes::GeoDataGroundOverlayType );
0108         m_groundOverlayProxyModel.setFilterKeyColumn( 1 );
0109         m_groundOverlayProxyModel.setSourceModel( &m_descendantProxy );
0110     }
0111 
0112     ~MarbleModelPrivate()
0113     {
0114         delete m_mapTheme;
0115         delete m_legend;
0116     }
0117     /**
0118      * @brief Assigns each placemark an inline
0119      * style based on the color values specified
0120      * by colorMap attribute under <brush> element
0121      * in theme file.
0122      */
0123     void assignFillColors( const QString &filePath );
0124     void assignFillColors(GeoDataDocument *doc, const GeoSceneGeodata &data) const;
0125 
0126     void addHighlightStyle(GeoDataDocument *doc) const;
0127 
0128     // Misc stuff.
0129     MarbleClock              m_clock;
0130     Planet                   m_planet;
0131     SunLocator               m_sunLocator;
0132 
0133     PluginManager            m_pluginManager;
0134 
0135     // The home position
0136     GeoDataCoordinates       m_homePoint;
0137     int                      m_homeZoom;
0138 
0139     // View and paint stuff
0140     GeoSceneDocument        *m_mapTheme;
0141 
0142     FileStoragePolicy        m_storagePolicy;
0143     HttpDownloadManager      m_downloadManager;
0144 
0145     // Cache related
0146     FileStorageWatcher       m_storageWatcher;
0147 
0148     // Places on the map
0149     GeoDataTreeModel         m_treeModel;
0150     KDescendantsProxyModel   m_descendantProxy;
0151     QSortFilterProxyModel    m_placemarkProxyModel;
0152     QSortFilterProxyModel    m_groundOverlayProxyModel;
0153 
0154     // Selection handling
0155     QItemSelectionModel      m_placemarkSelectionModel;
0156 
0157     FileManager              m_fileManager;
0158 
0159     //Gps Stuff
0160     PositionTracking         m_positionTracking;
0161 
0162     const GeoDataPlacemark  *m_trackedPlacemark;
0163 
0164     BookmarkManager          m_bookmarkManager;
0165     RoutingManager          *m_routingManager;
0166     QTextDocument           *m_legend;
0167 
0168     bool                     m_workOffline;
0169 
0170     ElevationModel           m_elevationModel;
0171 };
0172 
0173 MarbleModel::MarbleModel( QObject *parent )
0174     : QObject( parent ),
0175       d( new MarbleModelPrivate() )
0176 {
0177     // connect the StoragePolicy used by the download manager to the FileStorageWatcher
0178     connect( &d->m_storagePolicy, SIGNAL(cleared()),
0179              &d->m_storageWatcher, SLOT(resetCurrentSize()) );
0180     connect( &d->m_storagePolicy, SIGNAL(sizeChanged(qint64)),
0181              &d->m_storageWatcher, SLOT(addToCurrentSize(qint64)) );
0182 
0183     connect( &d->m_fileManager, SIGNAL(fileAdded(QString)),
0184              this, SLOT(assignFillColors(QString)) );
0185 
0186     d->m_routingManager = new RoutingManager( this, this );
0187 
0188     connect(&d->m_clock,   SIGNAL(timeChanged()),
0189             &d->m_sunLocator, SLOT(update()) );
0190 
0191     d->m_pluginManager.addPositionProviderPlugin(new PlacemarkPositionProviderPlugin(this, this));
0192     d->m_pluginManager.addPositionProviderPlugin(new RouteSimulationPositionProviderPlugin(this, this));
0193 }
0194 
0195 MarbleModel::~MarbleModel()
0196 {
0197     delete d;
0198 
0199     mDebug() << "Model deleted:" << this;
0200 }
0201 
0202 BookmarkManager *MarbleModel::bookmarkManager()
0203 {
0204     return &d->m_bookmarkManager;
0205 }
0206 
0207 QString MarbleModel::mapThemeId() const
0208 {
0209     QString mapThemeId;
0210 
0211     if (d->m_mapTheme)
0212         mapThemeId = d->m_mapTheme->head()->mapThemeId();
0213 
0214     return mapThemeId;
0215 }
0216 
0217 GeoSceneDocument *MarbleModel::mapTheme()
0218 {
0219     return d->m_mapTheme;
0220 }
0221 
0222 const GeoSceneDocument *MarbleModel::mapTheme() const
0223 {
0224     return d->m_mapTheme;
0225 }
0226 
0227 // Set a particular theme for the map and load the appropriate tile level.
0228 // If the tiles (for the lowest tile level) haven't been created already
0229 // then create them here and now.
0230 //
0231 // FIXME: Move the tile creation dialogs out of this function.  Change
0232 //        them into signals instead.
0233 // FIXME: Get rid of 'currentProjection' here.  It's totally misplaced.
0234 //
0235 
0236 void MarbleModel::setMapThemeId( const QString &mapThemeId )
0237 {
0238     if ( !mapThemeId.isEmpty() && mapThemeId == this->mapThemeId() )
0239         return;
0240 
0241     GeoSceneDocument *mapTheme = MapThemeManager::loadMapTheme( mapThemeId );
0242     setMapTheme( mapTheme );
0243 }
0244 
0245 void MarbleModel::setMapTheme( GeoSceneDocument *document )
0246 {
0247     GeoSceneDocument *mapTheme = document;
0248     if ( !mapTheme ) {
0249         // Check whether the previous theme works
0250         if ( d->m_mapTheme ){
0251             qWarning() << "Selected theme doesn't work, so we stick to the previous one";
0252             return;
0253         }
0254 
0255         // Fall back to default theme
0256         QString defaultTheme = "earth/srtm/srtm.dgml";
0257         qWarning() << "Falling back to default theme:" << defaultTheme;
0258         mapTheme = MapThemeManager::loadMapTheme( defaultTheme );
0259     }
0260 
0261     // If this last resort doesn't work either shed a tear and exit
0262     if ( !mapTheme ) {
0263         qWarning() << "Couldn't find a valid DGML map.";
0264         return;
0265     }
0266 
0267     // find the list of previous theme's geodata
0268     QList<GeoSceneGeodata> currentDatasets;
0269     if ( d->m_mapTheme ) {
0270         for ( GeoSceneLayer *layer: d->m_mapTheme->map()->layers() ) {
0271             if ( layer->backend() != dgml::dgmlValue_geodata
0272                  && layer->backend() != dgml::dgmlValue_vector )
0273                 continue;
0274 
0275             // look for documents
0276             for ( GeoSceneAbstractDataset *dataset: layer->datasets() ) {
0277                 GeoSceneGeodata *data = dynamic_cast<GeoSceneGeodata*>( dataset );
0278                 Q_ASSERT( data );
0279                 currentDatasets << *data;
0280             }
0281         }
0282     }
0283 
0284     delete d->m_mapTheme;
0285     d->m_mapTheme = mapTheme;
0286 
0287     addDownloadPolicies( d->m_mapTheme );
0288 
0289     // Some output to show how to use this stuff ...
0290     mDebug() << "DGML2 Name       : " << d->m_mapTheme->head()->name();
0291 /*
0292     mDebug() << "DGML2 Description: " << d->m_mapTheme->head()->description();
0293 
0294     if ( d->m_mapTheme->map()->hasTextureLayers() )
0295         mDebug() << "Contains texture layers! ";
0296     else
0297         mDebug() << "Does not contain any texture layers! ";
0298 
0299     mDebug() << "Number of SRTM textures: " << d->m_mapTheme->map()->layer("srtm")->datasets().count();
0300 
0301     if ( d->m_mapTheme->map()->hasVectorLayers() )
0302         mDebug() << "Contains vector layers! ";
0303     else
0304         mDebug() << "Does not contain any vector layers! ";
0305 */
0306     //Don't change the planet unless we have to...
0307     qreal const radiusAttributeValue = d->m_mapTheme->head()->radius();
0308     if( d->m_mapTheme->head()->target().toLower() != d->m_planet.id() || radiusAttributeValue != d->m_planet.radius() ) {
0309         mDebug() << "Changing Planet";
0310         d->m_planet = PlanetFactory::construct(d->m_mapTheme->head()->target().toLower());
0311         if ( radiusAttributeValue > 0.0 ) {
0312             d->m_planet.setRadius( radiusAttributeValue );
0313         }
0314         sunLocator()->setPlanet( &d->m_planet );
0315     }
0316 
0317     QStringList fileList;
0318     QStringList propertyList;
0319     QList<GeoDataStyle::Ptr> styleList;
0320     QList<int> renderOrderList;
0321 
0322     for ( GeoSceneLayer *layer: d->m_mapTheme->map()->layers() ) {
0323         if ( layer->backend() != dgml::dgmlValue_geodata
0324              && layer->backend() != dgml::dgmlValue_vector )
0325             continue;
0326 
0327         // look for datasets which are different from currentDatasets
0328         for ( const GeoSceneAbstractDataset *dataset: layer->datasets() ) {
0329             const GeoSceneGeodata *data = dynamic_cast<const GeoSceneGeodata*>( dataset );
0330             Q_ASSERT( data );
0331             bool skip = false;
0332             GeoDataDocument *doc = nullptr;
0333             for ( int i = 0; i < currentDatasets.size(); ++i ) {
0334                 if ( currentDatasets[i] == *data ) {
0335                     currentDatasets.removeAt( i );
0336                     skip = true;
0337                     break;
0338                 }
0339                 /*
0340                  * If the sourcefile of data matches any in the currentDatasets then there
0341                  * is no need to parse the file again just update the style
0342                  * i.e. <brush> and <pen> values of already parsed file. assignNewStyle() does that
0343                  */
0344                 if ( currentDatasets[i].sourceFile() == data->sourceFile() ) {
0345                     doc = d->m_fileManager.at(data->sourceFile());
0346                     currentDatasets.removeAt(i);
0347                 }
0348             }
0349             if ( skip ) {
0350                 continue;
0351             }
0352 
0353             if (doc) {
0354                 d->assignFillColors(doc, *data);
0355             }
0356             else {
0357                 const QString filename = data->sourceFile();
0358                 const QString property = data->property();
0359                 const QPen pen = data->pen();
0360                 const QBrush brush = data->brush();
0361                 GeoDataStyle::Ptr style;
0362                 const int renderOrder = data->renderOrder();
0363 
0364                 /*
0365                  * data->colors() are the colorMap values from dgml file. If this is not
0366                  * empty then we are supposed to assign every placemark a different style
0367                  * by giving it a color from colorMap values based on color index
0368                  * of that placemark. See assignFillColors() for details. So, we need to
0369                  * send an empty style to fileManeger otherwise the FileLoader::createFilterProperties()
0370                  * will overwrite the parsed value of color index ( GeoDataPolyStyle::d->m_colorIndex ).
0371                  */
0372                 if ( data->colors().isEmpty() ) {
0373                     GeoDataLineStyle lineStyle( pen.color() );
0374                     lineStyle.setPenStyle( pen.style() );
0375                     lineStyle.setWidth( pen.width() );
0376                     GeoDataPolyStyle polyStyle( brush.color() );
0377                     polyStyle.setFill( true );
0378                     style = GeoDataStyle::Ptr(new GeoDataStyle);
0379                     style->setLineStyle( lineStyle );
0380                     style->setPolyStyle( polyStyle );
0381                     style->setId(QStringLiteral("default"));
0382                 }
0383 
0384                 fileList << filename;
0385                 propertyList << property;
0386                 styleList << style;
0387                 renderOrderList << renderOrder;
0388             }
0389         }
0390     }
0391     // unload old currentDatasets which are not part of the new map
0392     for(const GeoSceneGeodata &data: currentDatasets) {
0393         d->m_fileManager.removeFile( data.sourceFile() );
0394     }
0395     // load new datasets
0396     for ( int i = 0 ; i < fileList.size(); ++i ) {
0397         d->m_fileManager.addFile( fileList.at(i), propertyList.at(i), styleList.at(i), MapDocument, renderOrderList.at(i) );
0398     }
0399 
0400     mDebug() << "THEME CHANGED: ***" << mapTheme->head()->mapThemeId();
0401     emit themeChanged( mapTheme->head()->mapThemeId() );
0402 }
0403 
0404 void MarbleModelPrivate::addHighlightStyle(GeoDataDocument *doc) const
0405 {
0406     if ( doc ) {
0407         /*
0408          * Add a highlight style to GeoDataDocument if
0409          *the theme file specifies any highlight color.
0410          */
0411         QColor highlightBrushColor = m_mapTheme->map()->highlightBrushColor();
0412         QColor highlightPenColor = m_mapTheme->map()->highlightPenColor();
0413 
0414         GeoDataStyle::Ptr highlightStyle(new GeoDataStyle);
0415         highlightStyle->setId(QStringLiteral("highlight"));
0416 
0417         if ( highlightBrushColor.isValid() ) {
0418             GeoDataPolyStyle highlightPolyStyle;
0419             highlightPolyStyle.setColor( highlightBrushColor );
0420             highlightPolyStyle.setFill( true );
0421             highlightStyle->setPolyStyle( highlightPolyStyle );
0422         }
0423         if ( highlightPenColor.isValid() ) {
0424             GeoDataLineStyle highlightLineStyle( highlightPenColor );
0425             highlightStyle->setLineStyle( highlightLineStyle );
0426         }
0427         if ( highlightBrushColor.isValid()
0428             || highlightPenColor.isValid() )
0429         {
0430             GeoDataStyleMap styleMap = doc->styleMap(QStringLiteral("default-map"));
0431             styleMap.insert(QStringLiteral("highlight"), QLatin1Char('#') + highlightStyle->id());
0432             doc->addStyle( highlightStyle );
0433             doc->addStyleMap( styleMap );
0434         }
0435     }
0436 }
0437 
0438 void MarbleModel::home( qreal &lon, qreal &lat, int& zoom ) const
0439 {
0440     d->m_homePoint.geoCoordinates( lon, lat, GeoDataCoordinates::Degree );
0441     zoom = d->m_homeZoom;
0442 }
0443 
0444 void MarbleModel::setHome( qreal lon, qreal lat, int zoom )
0445 {
0446     d->m_homePoint = GeoDataCoordinates( lon, lat, 0, GeoDataCoordinates::Degree );
0447     d->m_homeZoom = zoom;
0448     emit homeChanged( d->m_homePoint );
0449 }
0450 
0451 void MarbleModel::setHome( const GeoDataCoordinates& homePoint, int zoom )
0452 {
0453     d->m_homePoint = homePoint;
0454     d->m_homeZoom = zoom;
0455     emit homeChanged( d->m_homePoint );
0456 }
0457 
0458 HttpDownloadManager *MarbleModel::downloadManager()
0459 {
0460     return &d->m_downloadManager;
0461 }
0462 
0463 const HttpDownloadManager *MarbleModel::downloadManager() const
0464 {
0465     return &d->m_downloadManager;
0466 }
0467 
0468 
0469 GeoDataTreeModel *MarbleModel::treeModel()
0470 {
0471     return &d->m_treeModel;
0472 }
0473 
0474 const GeoDataTreeModel *MarbleModel::treeModel() const
0475 {
0476     return &d->m_treeModel;
0477 }
0478 
0479 QAbstractItemModel *MarbleModel::placemarkModel()
0480 {
0481     return &d->m_placemarkProxyModel;
0482 }
0483 
0484 const QAbstractItemModel *MarbleModel::placemarkModel() const
0485 {
0486     return &d->m_placemarkProxyModel;
0487 }
0488 
0489 QAbstractItemModel *MarbleModel::groundOverlayModel()
0490 {
0491     return &d->m_groundOverlayProxyModel;
0492 }
0493 
0494 const QAbstractItemModel *MarbleModel::groundOverlayModel() const
0495 {
0496     return &d->m_groundOverlayProxyModel;
0497 }
0498 
0499 QItemSelectionModel *MarbleModel::placemarkSelectionModel()
0500 {
0501     return &d->m_placemarkSelectionModel;
0502 }
0503 
0504 PositionTracking *MarbleModel::positionTracking() const
0505 {
0506     return &d->m_positionTracking;
0507 }
0508 
0509 FileManager *MarbleModel::fileManager()
0510 {
0511     return &d->m_fileManager;
0512 }
0513 
0514 qreal MarbleModel::planetRadius()   const
0515 {
0516     return d->m_planet.radius();
0517 }
0518 
0519 QString MarbleModel::planetName()   const
0520 {
0521     return d->m_planet.name();
0522 }
0523 
0524 QString MarbleModel::planetId() const
0525 {
0526     return d->m_planet.id();
0527 }
0528 
0529 MarbleClock *MarbleModel::clock()
0530 {
0531     return &d->m_clock;
0532 }
0533 
0534 const MarbleClock *MarbleModel::clock() const
0535 {
0536     return &d->m_clock;
0537 }
0538 
0539 SunLocator *MarbleModel::sunLocator()
0540 {
0541     return &d->m_sunLocator;
0542 }
0543 
0544 const SunLocator *MarbleModel::sunLocator() const
0545 {
0546     return &d->m_sunLocator;
0547 }
0548 
0549 quint64 MarbleModel::persistentTileCacheLimit() const
0550 {
0551     return d->m_storageWatcher.cacheLimit() / 1024;
0552 }
0553 
0554 void MarbleModel::clearPersistentTileCache()
0555 {
0556     d->m_storagePolicy.clearCache();
0557 
0558     // Now create base tiles again if needed
0559     if ( d->m_mapTheme->map()->hasTextureLayers() || d->m_mapTheme->map()->hasVectorLayers() ) {
0560         // If the tiles aren't already there, put up a progress dialog
0561         // while creating them.
0562 
0563         // As long as we don't have an Layer Management Class we just lookup
0564         // the name of the layer that has the same name as the theme ID
0565         QString themeID = d->m_mapTheme->head()->theme();
0566 
0567         const GeoSceneLayer *layer =
0568             static_cast<const GeoSceneLayer*>( d->m_mapTheme->map()->layer( themeID ) );
0569         const GeoSceneTileDataset *texture =
0570             static_cast<const GeoSceneTileDataset*>( layer->groundDataset() );
0571 
0572         QString sourceDir = texture->sourceDir();
0573         QString installMap = texture->installMap();
0574         QString role = d->m_mapTheme->map()->layer( themeID )->role();
0575 
0576         if ( !TileLoader::baseTilesAvailable( *texture )
0577             && !installMap.isEmpty() )
0578         {
0579             mDebug() << "Base tiles not available. Creating Tiles ... \n"
0580                      << "SourceDir: " << sourceDir << "InstallMap:" << installMap;
0581             MarbleDirs::debug();
0582 
0583             TileCreator *tileCreator = new TileCreator(
0584                                      sourceDir,
0585                                      installMap,
0586                                      (role == QLatin1String("dem")) ? "true" : "false" );
0587             tileCreator->setTileFormat( texture->fileFormat().toLower() );
0588 
0589             QPointer<TileCreatorDialog> tileCreatorDlg = new TileCreatorDialog( tileCreator, nullptr );
0590             tileCreatorDlg->setSummary( d->m_mapTheme->head()->name(),
0591                                         d->m_mapTheme->head()->description() );
0592             tileCreatorDlg->exec();
0593             qDebug("Tile creation completed");
0594             delete tileCreatorDlg;
0595         }
0596     }
0597 }
0598 
0599 void MarbleModel::setPersistentTileCacheLimit(quint64 kiloBytes)
0600 {
0601     d->m_storageWatcher.setCacheLimit( kiloBytes * 1024 );
0602 
0603     if( kiloBytes != 0 )
0604     {
0605         if( !d->m_storageWatcher.isRunning() )
0606             d->m_storageWatcher.start( QThread::IdlePriority );
0607     }
0608     else
0609     {
0610         d->m_storageWatcher.quit();
0611     }
0612     // TODO: trigger update
0613 }
0614 
0615 void MarbleModel::setTrackedPlacemark( const GeoDataPlacemark *placemark )
0616 {
0617     d->m_trackedPlacemark = placemark;
0618     emit trackedPlacemarkChanged( placemark );
0619 }
0620 
0621 const GeoDataPlacemark* MarbleModel::trackedPlacemark() const
0622 {
0623     return d->m_trackedPlacemark;
0624 }
0625 
0626 const PluginManager* MarbleModel::pluginManager() const
0627 {
0628     return &d->m_pluginManager;
0629 }
0630 
0631 PluginManager* MarbleModel::pluginManager()
0632 {
0633     return &d->m_pluginManager;
0634 }
0635 
0636 const Planet *MarbleModel::planet() const
0637 {
0638     return &d->m_planet;
0639 }
0640 
0641 void MarbleModel::addDownloadPolicies( const GeoSceneDocument *mapTheme )
0642 {
0643     if ( !mapTheme )
0644         return;
0645     if ( !mapTheme->map()->hasTextureLayers() && !mapTheme->map()->hasVectorLayers() )
0646         return;
0647 
0648     // As long as we don't have an Layer Management Class we just lookup
0649     // the name of the layer that has the same name as the theme ID
0650     const QString themeId = mapTheme->head()->theme();
0651     const GeoSceneLayer * const layer = static_cast<const GeoSceneLayer*>( mapTheme->map()->layer( themeId ));
0652     if ( !layer )
0653         return;
0654 
0655     const GeoSceneTileDataset * const texture = static_cast<const GeoSceneTileDataset*>( layer->groundDataset() );
0656     if ( !texture )
0657         return;
0658 
0659     QList<const DownloadPolicy *> policies = texture->downloadPolicies();
0660     QList<const DownloadPolicy *>::const_iterator pos = policies.constBegin();
0661     QList<const DownloadPolicy *>::const_iterator const end = policies.constEnd();
0662     for (; pos != end; ++pos ) {
0663         d->m_downloadManager.addDownloadPolicy( **pos );
0664     }
0665 }
0666 
0667 RoutingManager* MarbleModel::routingManager()
0668 {
0669     return d->m_routingManager;
0670 }
0671 
0672 const RoutingManager* MarbleModel::routingManager() const
0673 {
0674     return d->m_routingManager;
0675 }
0676 
0677 void MarbleModel::setClockDateTime( const QDateTime& datetime )
0678 {
0679     d->m_clock.setDateTime( datetime );
0680 }
0681 
0682 QDateTime MarbleModel::clockDateTime() const
0683 {
0684     return d->m_clock.dateTime();
0685 }
0686 
0687 int MarbleModel::clockSpeed() const
0688 {
0689     return d->m_clock.speed();
0690 }
0691 
0692 void MarbleModel::setClockSpeed( int speed )
0693 {
0694     d->m_clock.setSpeed( speed );
0695 }
0696 
0697 void MarbleModel::setClockTimezone( int timeInSec )
0698 {
0699     d->m_clock.setTimezone( timeInSec );
0700 }
0701 
0702 int MarbleModel::clockTimezone() const
0703 {
0704     return d->m_clock.timezone();
0705 }
0706 
0707 QTextDocument * MarbleModel::legend()
0708 {
0709     return d->m_legend;
0710 }
0711 
0712 void MarbleModel::setLegend( QTextDocument * legend )
0713 {
0714     delete d->m_legend;
0715     d->m_legend = legend;
0716 }
0717 
0718 void MarbleModel::addGeoDataFile( const QString& filename )
0719 {
0720     d->m_fileManager.addFile( filename, filename, GeoDataStyle::Ptr(), UserDocument, 0, true );
0721 }
0722 
0723 void MarbleModel::addGeoDataString( const QString& data, const QString& key )
0724 {
0725     d->m_fileManager.addData( key, data, UserDocument );
0726 }
0727 
0728 void MarbleModel::removeGeoData( const QString& fileName )
0729 {
0730     d->m_fileManager.removeFile( fileName );
0731 }
0732 
0733 void MarbleModel::updateProperty( const QString &property, bool value )
0734 {
0735     for( GeoDataFeature *feature: d->m_treeModel.rootDocument()->featureList()) {
0736         if (auto document = geodata_cast<GeoDataDocument>(feature)) {
0737             if( document->property() == property ){
0738                 document->setVisible( value );
0739                 d->m_treeModel.updateFeature( document );
0740             }
0741         }
0742     }
0743 }
0744 
0745 void MarbleModelPrivate::assignFillColors(const QString &filePath)
0746 {
0747     const GeoSceneGeodata *data = nullptr;
0748 
0749     for (auto layer : m_mapTheme->map()->layers()) {
0750         if (layer->backend() != dgml::dgmlValue_geodata
0751             && layer->backend() != dgml::dgmlValue_vector) {
0752             continue;
0753         }
0754 
0755         for (auto dataset: layer->datasets()) {
0756             auto sceneData = dynamic_cast<const GeoSceneGeodata *>(dataset);
0757             if (sceneData != nullptr && sceneData->sourceFile() == filePath) {
0758                 data = sceneData;
0759                 break;
0760             }
0761         }
0762 
0763         if (data) {
0764             break;
0765         }
0766     }
0767 
0768     if (data == nullptr) {
0769         return;
0770     }
0771 
0772     GeoDataDocument *doc = m_fileManager.at(filePath);
0773     Q_ASSERT( doc );
0774 
0775     assignFillColors(doc, *data);
0776 }
0777 
0778 void MarbleModelPrivate::assignFillColors(GeoDataDocument *doc, const GeoSceneGeodata &data) const
0779 {
0780     addHighlightStyle( doc );
0781 
0782     const QPen pen = data.pen();
0783     const QBrush brush = data.brush();
0784     const QVector<QColor> colors = data.colors();
0785     GeoDataLineStyle lineStyle( pen.color() );
0786     lineStyle.setPenStyle( pen.style() );
0787     lineStyle.setWidth( pen.width() );
0788 
0789     if (!colors.isEmpty()) {
0790         const qreal alpha = data.alpha();
0791         for (auto feature : *doc) {
0792             auto placemark = geodata_cast<GeoDataPlacemark>(feature);
0793             if (placemark == nullptr) {
0794                 continue;
0795             }
0796 
0797             GeoDataStyle::Ptr style(new GeoDataStyle);
0798             style->setId(QStringLiteral("normal"));
0799             style->setLineStyle( lineStyle );
0800             quint8 colorIndex = placemark->style()->polyStyle().colorIndex();
0801             GeoDataPolyStyle polyStyle;
0802             // Set the colorIndex so that it's not lost after setting new style.
0803             polyStyle.setColorIndex( colorIndex );
0804             QColor color;
0805             // color index having value 99 is undefined
0806             Q_ASSERT( colors.size() );
0807             if (colorIndex > colors.size() || (colorIndex - 1) < 0) {
0808                 color = colors[0];      // Assign the first color as default
0809             }
0810             else {
0811                 color = colors[colorIndex-1];
0812             }
0813             color.setAlphaF( alpha );
0814             polyStyle.setColor( color );
0815             polyStyle.setFill( true );
0816             style->setPolyStyle( polyStyle );
0817             placemark->setStyle( style );
0818         }
0819     }
0820     else {
0821         GeoDataStyle::Ptr style(new GeoDataStyle);
0822         GeoDataPolyStyle polyStyle( brush.color() );
0823         polyStyle.setFill( true );
0824         style->setLineStyle( lineStyle );
0825         style->setPolyStyle( polyStyle );
0826         style->setId(QStringLiteral("default"));
0827         GeoDataStyleMap styleMap;
0828         styleMap.setId(QStringLiteral("default-map"));
0829         styleMap.insert(QStringLiteral("normal"), QLatin1Char('#') + style->id());
0830         doc->addStyle( style );
0831         doc->addStyleMap( styleMap );
0832 
0833         const QString styleUrl = QLatin1Char('#') + styleMap.id();
0834 
0835         for (auto feature : *doc) {
0836             auto placemark = geodata_cast<GeoDataPlacemark>(feature);
0837             if (placemark == nullptr) {
0838                 continue;
0839             }
0840 
0841             if (geodata_cast<GeoDataTrack>(placemark->geometry()) ||
0842                 geodata_cast<GeoDataPoint>(placemark->geometry())) {
0843                 continue;
0844             }
0845 
0846             placemark->setStyleUrl(styleUrl);
0847         }
0848     }
0849 }
0850 
0851 bool MarbleModel::workOffline() const
0852 {
0853     return d->m_workOffline;
0854 }
0855 
0856 void MarbleModel::setWorkOffline( bool workOffline )
0857 {
0858     if ( d->m_workOffline != workOffline ) {
0859         downloadManager()->setDownloadEnabled( !workOffline );
0860 
0861         d->m_workOffline = workOffline;
0862         emit workOfflineChanged();
0863     }
0864 }
0865 
0866 ElevationModel* MarbleModel::elevationModel()
0867 {
0868     return &d->m_elevationModel;
0869 }
0870 
0871 const ElevationModel* MarbleModel::elevationModel() const
0872 {
0873     return &d->m_elevationModel;
0874 }
0875 
0876 }
0877 
0878 #include "moc_MarbleModel.cpp"