File indexing completed on 2024-04-28 15:15:55
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"