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