Marble

MarbleModel.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2006-2007 Torsten Rahn <tackat@kde.org>
4// SPDX-FileCopyrightText: 2007 Inge Wallin <ingwa@kde.org>
5// SPDX-FileCopyrightText: 2008, 2009, 2010 Jens-Michael Hoffmann <jmho@c-xx.com>
6// SPDX-FileCopyrightText: 2008-2009 Patrick Spendrin <ps_ml@gmx.de>
7// SPDX-FileCopyrightText: 2010-2013 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
8// SPDX-FileCopyrightText: 2014 Abhinav Gangwar <abhgang@gmail.com>
9//
10
11#include "MarbleModel.h"
12
13#include <cmath>
14
15#include <QAtomicInt>
16#include <QPointer>
17#include <QAbstractItemModel>
18#include <QItemSelectionModel>
19#include <QSortFilterProxyModel>
20#include <QTextDocument>
21
22#include "kdescendantsproxymodel.h"
23
24#include "MapThemeManager.h"
25#include "MarbleDebug.h"
26
27#include "GeoSceneDocument.h"
28#include "GeoSceneGeodata.h"
29#include "GeoSceneHead.h"
30#include "GeoSceneLayer.h"
31#include "GeoSceneMap.h"
32#include "GeoScenePalette.h"
33#include "GeoSceneTileDataset.h"
34#include "GeoSceneVector.h"
35
36#include "GeoDataDocument.h"
37#include "GeoDataFeature.h"
38#include "GeoDataPlacemark.h"
39#include "GeoDataPoint.h"
40#include "GeoDataStyle.h"
41#include "GeoDataStyleMap.h"
42#include "GeoDataTrack.h"
43#include "GeoDataLineStyle.h"
44#include "GeoDataPolyStyle.h"
45#include "GeoDataTypes.h"
46
47#include "DgmlAuxillaryDictionary.h"
48#include "MarbleClock.h"
49#include "FileStoragePolicy.h"
50#include "FileStorageWatcher.h"
51#include "PositionTracking.h"
52#include "HttpDownloadManager.h"
53#include "MarbleDirs.h"
54#include "FileManager.h"
55#include "GeoDataTreeModel.h"
56#include "PlacemarkPositionProviderPlugin.h"
57#include "Planet.h"
58#include "PlanetFactory.h"
59#include "PluginManager.h"
60#include "StoragePolicy.h"
61#include "SunLocator.h"
62#include "TileCreator.h"
63#include "TileCreatorDialog.h"
64#include "TileLoader.h"
65#include "routing/RoutingManager.h"
66#include "RouteSimulationPositionProviderPlugin.h"
67#include "BookmarkManager.h"
68#include "ElevationModel.h"
69
70namespace Marble
71{
72
73class MarbleModelPrivate
74{
75 public:
76 MarbleModelPrivate()
77 : m_clock(),
78 m_planet(PlanetFactory::construct(QStringLiteral("earth"))),
79 m_sunLocator( &m_clock, &m_planet ),
80 m_pluginManager(),
81 m_homePoint( -9.4, 54.8, 0.0, GeoDataCoordinates::Degree ), // Some point that tackat defined. :-)
82 m_homeZoom( 1050 ),
83 m_mapTheme( nullptr ),
84 m_storagePolicy( MarbleDirs::localPath() ),
85 m_downloadManager( &m_storagePolicy ),
86 m_storageWatcher( MarbleDirs::localPath() ),
87 m_treeModel(),
88 m_descendantProxy(),
89 m_placemarkProxyModel(),
90 m_placemarkSelectionModel( nullptr ),
91 m_fileManager( &m_treeModel, &m_pluginManager ),
92 m_positionTracking( &m_treeModel ),
93 m_trackedPlacemark( nullptr ),
94 m_bookmarkManager( &m_treeModel ),
95 m_routingManager( nullptr ),
96 m_legend( nullptr ),
97 m_workOffline( false ),
98 m_elevationModel( &m_downloadManager, &m_pluginManager )
99 {
100 m_descendantProxy.setSourceModel( &m_treeModel );
101
102 m_placemarkProxyModel.setFilterFixedString( GeoDataTypes::GeoDataPlacemarkType );
103 m_placemarkProxyModel.setFilterKeyColumn( 1 );
104 m_placemarkProxyModel.setSourceModel( &m_descendantProxy );
105 m_placemarkSelectionModel.setModel(&m_placemarkProxyModel);
106
107 m_groundOverlayProxyModel.setFilterFixedString( GeoDataTypes::GeoDataGroundOverlayType );
108 m_groundOverlayProxyModel.setFilterKeyColumn( 1 );
109 m_groundOverlayProxyModel.setSourceModel( &m_descendantProxy );
110 }
111
112 ~MarbleModelPrivate()
113 {
114 delete m_mapTheme;
115 delete m_legend;
116 }
117 /**
118 * @brief Assigns each placemark an inline
119 * style based on the color values specified
120 * by colorMap attribute under <brush> element
121 * in theme file.
122 */
123 void assignFillColors( const QString &filePath );
124 void assignFillColors(GeoDataDocument *doc, const GeoSceneGeodata &data) const;
125
126 void addHighlightStyle(GeoDataDocument *doc) const;
127
128 // Misc stuff.
129 MarbleClock m_clock;
130 Planet m_planet;
131 SunLocator m_sunLocator;
132
133 PluginManager m_pluginManager;
134
135 // The home position
136 GeoDataCoordinates m_homePoint;
137 int m_homeZoom;
138
139 // View and paint stuff
140 GeoSceneDocument *m_mapTheme;
141
142 FileStoragePolicy m_storagePolicy;
143 HttpDownloadManager m_downloadManager;
144
145 // Cache related
146 FileStorageWatcher m_storageWatcher;
147
148 // Places on the map
149 GeoDataTreeModel m_treeModel;
150 KDescendantsProxyModel m_descendantProxy;
151 QSortFilterProxyModel m_placemarkProxyModel;
152 QSortFilterProxyModel m_groundOverlayProxyModel;
153
154 // Selection handling
155 QItemSelectionModel m_placemarkSelectionModel;
156
157 FileManager m_fileManager;
158
159 //Gps Stuff
160 PositionTracking m_positionTracking;
161
162 const GeoDataPlacemark *m_trackedPlacemark;
163
164 BookmarkManager m_bookmarkManager;
165 RoutingManager *m_routingManager;
166 QTextDocument *m_legend;
167
168 bool m_workOffline;
169
170 ElevationModel m_elevationModel;
171};
172
174 : QObject( parent ),
175 d( new MarbleModelPrivate() )
176{
177 // connect the StoragePolicy used by the download manager to the FileStorageWatcher
178 connect( &d->m_storagePolicy, SIGNAL(cleared()),
179 &d->m_storageWatcher, SLOT(resetCurrentSize()) );
180 connect( &d->m_storagePolicy, SIGNAL(sizeChanged(qint64)),
181 &d->m_storageWatcher, SLOT(addToCurrentSize(qint64)) );
182
183 connect( &d->m_fileManager, SIGNAL(fileAdded(QString)),
184 this, SLOT(assignFillColors(QString)) );
185
186 d->m_routingManager = new RoutingManager( this, this );
187
188 connect(&d->m_clock, SIGNAL(timeChanged()),
189 &d->m_sunLocator, SLOT(update()) );
190
191 d->m_pluginManager.addPositionProviderPlugin(new PlacemarkPositionProviderPlugin(this, this));
192 d->m_pluginManager.addPositionProviderPlugin(new RouteSimulationPositionProviderPlugin(this, this));
193}
194
195MarbleModel::~MarbleModel()
196{
197 delete d;
198
199 mDebug() << "Model deleted:" << this;
200}
201
203{
204 return &d->m_bookmarkManager;
205}
206
207QString MarbleModel::mapThemeId() const
208{
209 QString mapThemeId;
210
211 if (d->m_mapTheme)
212 mapThemeId = d->m_mapTheme->head()->mapThemeId();
213
214 return mapThemeId;
215}
216
217GeoSceneDocument *MarbleModel::mapTheme()
218{
219 return d->m_mapTheme;
220}
221
222const GeoSceneDocument *MarbleModel::mapTheme() const
223{
224 return d->m_mapTheme;
225}
226
227// Set a particular theme for the map and load the appropriate tile level.
228// If the tiles (for the lowest tile level) haven't been created already
229// then create them here and now.
230//
231// FIXME: Move the tile creation dialogs out of this function. Change
232// them into signals instead.
233// FIXME: Get rid of 'currentProjection' here. It's totally misplaced.
234//
235
236void MarbleModel::setMapThemeId( const QString &mapThemeId )
237{
238 if ( !mapThemeId.isEmpty() && mapThemeId == this->mapThemeId() )
239 return;
240
241 GeoSceneDocument *mapTheme = MapThemeManager::loadMapTheme( mapThemeId );
242 setMapTheme( mapTheme );
243}
244
245void MarbleModel::setMapTheme( GeoSceneDocument *document )
246{
247 GeoSceneDocument *mapTheme = document;
248 if ( !mapTheme ) {
249 // Check whether the previous theme works
250 if ( d->m_mapTheme ){
251 qWarning() << "Selected theme doesn't work, so we stick to the previous one";
252 return;
253 }
254
255 // Fall back to default theme
256 QString defaultTheme = "earth/srtm/srtm.dgml";
257 qWarning() << "Falling back to default theme:" << defaultTheme;
258 mapTheme = MapThemeManager::loadMapTheme( defaultTheme );
259 }
260
261 // If this last resort doesn't work either shed a tear and exit
262 if ( !mapTheme ) {
263 qWarning() << "Couldn't find a valid DGML map.";
264 return;
265 }
266
267 // find the list of previous theme's geodata
269 if ( d->m_mapTheme ) {
270 for ( GeoSceneLayer *layer: d->m_mapTheme->map()->layers() ) {
271 if ( layer->backend() != dgml::dgmlValue_geodata
272 && layer->backend() != dgml::dgmlValue_vector )
273 continue;
274
275 // look for documents
276 for ( GeoSceneAbstractDataset *dataset: layer->datasets() ) {
277 GeoSceneGeodata *data = dynamic_cast<GeoSceneGeodata*>( dataset );
278 Q_ASSERT( data );
279 currentDatasets << *data;
280 }
281 }
282 }
283
284 delete d->m_mapTheme;
285 d->m_mapTheme = mapTheme;
286
287 addDownloadPolicies( d->m_mapTheme );
288
289 // Some output to show how to use this stuff ...
290 mDebug() << "DGML2 Name : " << d->m_mapTheme->head()->name();
291/*
292 mDebug() << "DGML2 Description: " << d->m_mapTheme->head()->description();
293
294 if ( d->m_mapTheme->map()->hasTextureLayers() )
295 mDebug() << "Contains texture layers! ";
296 else
297 mDebug() << "Does not contain any texture layers! ";
298
299 mDebug() << "Number of SRTM textures: " << d->m_mapTheme->map()->layer("srtm")->datasets().count();
300
301 if ( d->m_mapTheme->map()->hasVectorLayers() )
302 mDebug() << "Contains vector layers! ";
303 else
304 mDebug() << "Does not contain any vector layers! ";
305*/
306 //Don't change the planet unless we have to...
307 qreal const radiusAttributeValue = d->m_mapTheme->head()->radius();
308 if( d->m_mapTheme->head()->target().toLower() != d->m_planet.id() || radiusAttributeValue != d->m_planet.radius() ) {
309 mDebug() << "Changing Planet";
310 d->m_planet = PlanetFactory::construct(d->m_mapTheme->head()->target().toLower());
311 if ( radiusAttributeValue > 0.0 ) {
312 d->m_planet.setRadius( radiusAttributeValue );
313 }
314 sunLocator()->setPlanet( &d->m_planet );
315 }
316
321
322 for ( GeoSceneLayer *layer: d->m_mapTheme->map()->layers() ) {
323 if ( layer->backend() != dgml::dgmlValue_geodata
324 && layer->backend() != dgml::dgmlValue_vector )
325 continue;
326
327 // look for datasets which are different from currentDatasets
328 for ( const GeoSceneAbstractDataset *dataset: layer->datasets() ) {
329 const GeoSceneGeodata *data = dynamic_cast<const GeoSceneGeodata*>( dataset );
330 Q_ASSERT( data );
331 bool skip = false;
332 GeoDataDocument *doc = nullptr;
333 for ( int i = 0; i < currentDatasets.size(); ++i ) {
334 if ( currentDatasets[i] == *data ) {
335 currentDatasets.removeAt( i );
336 skip = true;
337 break;
338 }
339 /*
340 * If the sourcefile of data matches any in the currentDatasets then there
341 * is no need to parse the file again just update the style
342 * i.e. <brush> and <pen> values of already parsed file. assignNewStyle() does that
343 */
344 if ( currentDatasets[i].sourceFile() == data->sourceFile() ) {
345 doc = d->m_fileManager.at(data->sourceFile());
346 currentDatasets.removeAt(i);
347 }
348 }
349 if ( skip ) {
350 continue;
351 }
352
353 if (doc) {
354 d->assignFillColors(doc, *data);
355 }
356 else {
357 const QString filename = data->sourceFile();
358 const QString property = data->property();
359 const QPen pen = data->pen();
360 const QBrush brush = data->brush();
361 GeoDataStyle::Ptr style;
362 const int renderOrder = data->renderOrder();
363
364 /*
365 * data->colors() are the colorMap values from dgml file. If this is not
366 * empty then we are supposed to assign every placemark a different style
367 * by giving it a color from colorMap values based on color index
368 * of that placemark. See assignFillColors() for details. So, we need to
369 * send an empty style to fileManeger otherwise the FileLoader::createFilterProperties()
370 * will overwrite the parsed value of color index ( GeoDataPolyStyle::d->m_colorIndex ).
371 */
372 if ( data->colors().isEmpty() ) {
373 GeoDataLineStyle lineStyle( pen.color() );
374 lineStyle.setPenStyle( pen.style() );
375 lineStyle.setWidth( pen.width() );
376 GeoDataPolyStyle polyStyle( brush.color() );
377 polyStyle.setFill( true );
378 style = GeoDataStyle::Ptr(new GeoDataStyle);
379 style->setLineStyle( lineStyle );
380 style->setPolyStyle( polyStyle );
381 style->setId(QStringLiteral("default"));
382 }
383
384 fileList << filename;
386 styleList << style;
387 renderOrderList << renderOrder;
388 }
389 }
390 }
391 // unload old currentDatasets which are not part of the new map
392 for(const GeoSceneGeodata &data: currentDatasets) {
393 d->m_fileManager.removeFile( data.sourceFile() );
394 }
395 // load new datasets
396 for ( int i = 0 ; i < fileList.size(); ++i ) {
397 d->m_fileManager.addFile( fileList.at(i), propertyList.at(i), styleList.at(i), MapDocument, renderOrderList.at(i) );
398 }
399
400 mDebug() << "THEME CHANGED: ***" << mapTheme->head()->mapThemeId();
401 emit themeChanged( mapTheme->head()->mapThemeId() );
402}
403
404void MarbleModelPrivate::addHighlightStyle(GeoDataDocument *doc) const
405{
406 if ( doc ) {
407 /*
408 * Add a highlight style to GeoDataDocument if
409 *the theme file specifies any highlight color.
410 */
411 QColor highlightBrushColor = m_mapTheme->map()->highlightBrushColor();
412 QColor highlightPenColor = m_mapTheme->map()->highlightPenColor();
413
414 GeoDataStyle::Ptr highlightStyle(new GeoDataStyle);
415 highlightStyle->setId(QStringLiteral("highlight"));
416
417 if ( highlightBrushColor.isValid() ) {
418 GeoDataPolyStyle highlightPolyStyle;
419 highlightPolyStyle.setColor( highlightBrushColor );
420 highlightPolyStyle.setFill( true );
421 highlightStyle->setPolyStyle( highlightPolyStyle );
422 }
423 if ( highlightPenColor.isValid() ) {
424 GeoDataLineStyle highlightLineStyle( highlightPenColor );
425 highlightStyle->setLineStyle( highlightLineStyle );
426 }
427 if ( highlightBrushColor.isValid()
428 || highlightPenColor.isValid() )
429 {
430 GeoDataStyleMap styleMap = doc->styleMap(QStringLiteral("default-map"));
431 styleMap.insert(QStringLiteral("highlight"), QLatin1Char('#') + highlightStyle->id());
432 doc->addStyle( highlightStyle );
433 doc->addStyleMap( styleMap );
434 }
435 }
436}
437
438void MarbleModel::home( qreal &lon, qreal &lat, int& zoom ) const
439{
440 d->m_homePoint.geoCoordinates( lon, lat, GeoDataCoordinates::Degree );
441 zoom = d->m_homeZoom;
442}
443
444void MarbleModel::setHome( qreal lon, qreal lat, int zoom )
445{
446 d->m_homePoint = GeoDataCoordinates( lon, lat, 0, GeoDataCoordinates::Degree );
447 d->m_homeZoom = zoom;
448 emit homeChanged( d->m_homePoint );
449}
450
451void MarbleModel::setHome( const GeoDataCoordinates& homePoint, int zoom )
452{
453 d->m_homePoint = homePoint;
454 d->m_homeZoom = zoom;
455 emit homeChanged( d->m_homePoint );
456}
457
459{
460 return &d->m_downloadManager;
461}
462
464{
465 return &d->m_downloadManager;
466}
467
468
470{
471 return &d->m_treeModel;
472}
473
475{
476 return &d->m_treeModel;
477}
478
479QAbstractItemModel *MarbleModel::placemarkModel()
480{
481 return &d->m_placemarkProxyModel;
482}
483
484const QAbstractItemModel *MarbleModel::placemarkModel() const
485{
486 return &d->m_placemarkProxyModel;
487}
488
489QAbstractItemModel *MarbleModel::groundOverlayModel()
490{
491 return &d->m_groundOverlayProxyModel;
492}
493
494const QAbstractItemModel *MarbleModel::groundOverlayModel() const
495{
496 return &d->m_groundOverlayProxyModel;
497}
498
499QItemSelectionModel *MarbleModel::placemarkSelectionModel()
500{
501 return &d->m_placemarkSelectionModel;
502}
503
504PositionTracking *MarbleModel::positionTracking() const
505{
506 return &d->m_positionTracking;
507}
508
509FileManager *MarbleModel::fileManager()
510{
511 return &d->m_fileManager;
512}
513
514qreal MarbleModel::planetRadius() const
515{
516 return d->m_planet.radius();
517}
518
519QString MarbleModel::planetName() const
520{
521 return d->m_planet.name();
522}
523
524QString MarbleModel::planetId() const
525{
526 return d->m_planet.id();
527}
528
529MarbleClock *MarbleModel::clock()
530{
531 return &d->m_clock;
532}
533
534const MarbleClock *MarbleModel::clock() const
535{
536 return &d->m_clock;
537}
538
539SunLocator *MarbleModel::sunLocator()
540{
541 return &d->m_sunLocator;
542}
543
544const SunLocator *MarbleModel::sunLocator() const
545{
546 return &d->m_sunLocator;
547}
548
550{
551 return d->m_storageWatcher.cacheLimit() / 1024;
552}
553
554void MarbleModel::clearPersistentTileCache()
555{
556 d->m_storagePolicy.clearCache();
557
558 // Now create base tiles again if needed
559 if ( d->m_mapTheme->map()->hasTextureLayers() || d->m_mapTheme->map()->hasVectorLayers() ) {
560 // If the tiles aren't already there, put up a progress dialog
561 // while creating them.
562
563 // As long as we don't have an Layer Management Class we just lookup
564 // the name of the layer that has the same name as the theme ID
565 QString themeID = d->m_mapTheme->head()->theme();
566
567 const GeoSceneLayer *layer =
568 static_cast<const GeoSceneLayer*>( d->m_mapTheme->map()->layer( themeID ) );
569 const GeoSceneTileDataset *texture =
570 static_cast<const GeoSceneTileDataset*>( layer->groundDataset() );
571
572 QString sourceDir = texture->sourceDir();
573 QString installMap = texture->installMap();
574 QString role = d->m_mapTheme->map()->layer( themeID )->role();
575
576 if ( !TileLoader::baseTilesAvailable( *texture )
577 && !installMap.isEmpty() )
578 {
579 mDebug() << "Base tiles not available. Creating Tiles ... \n"
580 << "SourceDir: " << sourceDir << "InstallMap:" << installMap;
581 MarbleDirs::debug();
582
583 TileCreator *tileCreator = new TileCreator(
584 sourceDir,
585 installMap,
586 (role == QLatin1String("dem")) ? "true" : "false" );
587 tileCreator->setTileFormat( texture->fileFormat().toLower() );
588
589 QPointer<TileCreatorDialog> tileCreatorDlg = new TileCreatorDialog( tileCreator, nullptr );
590 tileCreatorDlg->setSummary( d->m_mapTheme->head()->name(),
591 d->m_mapTheme->head()->description() );
592 tileCreatorDlg->exec();
593 qDebug("Tile creation completed");
594 delete tileCreatorDlg;
595 }
596 }
597}
598
600{
601 d->m_storageWatcher.setCacheLimit( kiloBytes * 1024 );
602
603 if( kiloBytes != 0 )
604 {
605 if( !d->m_storageWatcher.isRunning() )
606 d->m_storageWatcher.start( QThread::IdlePriority );
607 }
608 else
609 {
610 d->m_storageWatcher.quit();
611 }
612 // TODO: trigger update
613}
614
616{
617 d->m_trackedPlacemark = placemark;
618 emit trackedPlacemarkChanged( placemark );
619}
620
622{
623 return d->m_trackedPlacemark;
624}
625
626const PluginManager* MarbleModel::pluginManager() const
627{
628 return &d->m_pluginManager;
629}
630
631PluginManager* MarbleModel::pluginManager()
632{
633 return &d->m_pluginManager;
634}
635
636const Planet *MarbleModel::planet() const
637{
638 return &d->m_planet;
639}
640
641void MarbleModel::addDownloadPolicies( const GeoSceneDocument *mapTheme )
642{
643 if ( !mapTheme )
644 return;
645 if ( !mapTheme->map()->hasTextureLayers() && !mapTheme->map()->hasVectorLayers() )
646 return;
647
648 // As long as we don't have an Layer Management Class we just lookup
649 // the name of the layer that has the same name as the theme ID
650 const QString themeId = mapTheme->head()->theme();
651 const GeoSceneLayer * const layer = static_cast<const GeoSceneLayer*>( mapTheme->map()->layer( themeId ));
652 if ( !layer )
653 return;
654
655 const GeoSceneTileDataset * const texture = static_cast<const GeoSceneTileDataset*>( layer->groundDataset() );
656 if ( !texture )
657 return;
658
659 QList<const DownloadPolicy *> policies = texture->downloadPolicies();
662 for (; pos != end; ++pos ) {
663 d->m_downloadManager.addDownloadPolicy( **pos );
664 }
665}
666
667RoutingManager* MarbleModel::routingManager()
668{
669 return d->m_routingManager;
670}
671
672const RoutingManager* MarbleModel::routingManager() const
673{
674 return d->m_routingManager;
675}
676
677void MarbleModel::setClockDateTime( const QDateTime& datetime )
678{
679 d->m_clock.setDateTime( datetime );
680}
681
682QDateTime MarbleModel::clockDateTime() const
683{
684 return d->m_clock.dateTime();
685}
686
687int MarbleModel::clockSpeed() const
688{
689 return d->m_clock.speed();
690}
691
692void MarbleModel::setClockSpeed( int speed )
693{
694 d->m_clock.setSpeed( speed );
695}
696
697void MarbleModel::setClockTimezone( int timeInSec )
698{
699 d->m_clock.setTimezone( timeInSec );
700}
701
702int MarbleModel::clockTimezone() const
703{
704 return d->m_clock.timezone();
705}
706
707QTextDocument * MarbleModel::legend()
708{
709 return d->m_legend;
710}
711
713{
714 delete d->m_legend;
715 d->m_legend = legend;
716}
717
719{
720 d->m_fileManager.addFile( filename, filename, GeoDataStyle::Ptr(), UserDocument, 0, true );
721}
722
723void MarbleModel::addGeoDataString( const QString& data, const QString& key )
724{
725 d->m_fileManager.addData( key, data, UserDocument );
726}
727
728void MarbleModel::removeGeoData( const QString& fileName )
729{
730 d->m_fileManager.removeFile( fileName );
731}
732
733void MarbleModel::updateProperty( const QString &property, bool value )
734{
735 for( GeoDataFeature *feature: d->m_treeModel.rootDocument()->featureList()) {
736 if (auto document = geodata_cast<GeoDataDocument>(feature)) {
737 if( document->property() == property ){
738 document->setVisible( value );
739 d->m_treeModel.updateFeature( document );
740 }
741 }
742 }
743}
744
745void MarbleModelPrivate::assignFillColors(const QString &filePath)
746{
747 const GeoSceneGeodata *data = nullptr;
748
749 for (auto layer : m_mapTheme->map()->layers()) {
750 if (layer->backend() != dgml::dgmlValue_geodata
751 && layer->backend() != dgml::dgmlValue_vector) {
752 continue;
753 }
754
755 for (auto dataset: layer->datasets()) {
756 auto sceneData = dynamic_cast<const GeoSceneGeodata *>(dataset);
757 if (sceneData != nullptr && sceneData->sourceFile() == filePath) {
758 data = sceneData;
759 break;
760 }
761 }
762
763 if (data) {
764 break;
765 }
766 }
767
768 if (data == nullptr) {
769 return;
770 }
771
772 GeoDataDocument *doc = m_fileManager.at(filePath);
773 Q_ASSERT( doc );
774
775 assignFillColors(doc, *data);
776}
777
778void MarbleModelPrivate::assignFillColors(GeoDataDocument *doc, const GeoSceneGeodata &data) const
779{
780 addHighlightStyle( doc );
781
782 const QPen pen = data.pen();
783 const QBrush brush = data.brush();
784 const QVector<QColor> colors = data.colors();
785 GeoDataLineStyle lineStyle( pen.color() );
786 lineStyle.setPenStyle( pen.style() );
787 lineStyle.setWidth( pen.width() );
788
789 if (!colors.isEmpty()) {
790 const qreal alpha = data.alpha();
791 for (auto feature : *doc) {
792 auto placemark = geodata_cast<GeoDataPlacemark>(feature);
793 if (placemark == nullptr) {
794 continue;
795 }
796
797 GeoDataStyle::Ptr style(new GeoDataStyle);
798 style->setId(QStringLiteral("normal"));
799 style->setLineStyle( lineStyle );
800 quint8 colorIndex = placemark->style()->polyStyle().colorIndex();
801 GeoDataPolyStyle polyStyle;
802 // Set the colorIndex so that it's not lost after setting new style.
803 polyStyle.setColorIndex( colorIndex );
804 QColor color;
805 // color index having value 99 is undefined
806 Q_ASSERT( colors.size() );
807 if (colorIndex > colors.size() || (colorIndex - 1) < 0) {
808 color = colors[0]; // Assign the first color as default
809 }
810 else {
811 color = colors[colorIndex-1];
812 }
813 color.setAlphaF( alpha );
814 polyStyle.setColor( color );
815 polyStyle.setFill( true );
816 style->setPolyStyle( polyStyle );
817 placemark->setStyle( style );
818 }
819 }
820 else {
821 GeoDataStyle::Ptr style(new GeoDataStyle);
822 GeoDataPolyStyle polyStyle( brush.color() );
823 polyStyle.setFill( true );
824 style->setLineStyle( lineStyle );
825 style->setPolyStyle( polyStyle );
826 style->setId(QStringLiteral("default"));
827 GeoDataStyleMap styleMap;
828 styleMap.setId(QStringLiteral("default-map"));
829 styleMap.insert(QStringLiteral("normal"), QLatin1Char('#') + style->id());
830 doc->addStyle( style );
831 doc->addStyleMap( styleMap );
832
833 const QString styleUrl = QLatin1Char('#') + styleMap.id();
834
835 for (auto feature : *doc) {
836 auto placemark = geodata_cast<GeoDataPlacemark>(feature);
837 if (placemark == nullptr) {
838 continue;
839 }
840
841 if (geodata_cast<GeoDataTrack>(placemark->geometry()) ||
842 geodata_cast<GeoDataPoint>(placemark->geometry())) {
843 continue;
844 }
845
846 placemark->setStyleUrl(styleUrl);
847 }
848 }
849}
850
851bool MarbleModel::workOffline() const
852{
853 return d->m_workOffline;
854}
855
856void MarbleModel::setWorkOffline( bool workOffline )
857{
858 if ( d->m_workOffline != workOffline ) {
859 downloadManager()->setDownloadEnabled( !workOffline );
860
861 d->m_workOffline = workOffline;
862 emit workOfflineChanged();
863 }
864}
865
866ElevationModel* MarbleModel::elevationModel()
867{
868 return &d->m_elevationModel;
869}
870
871const ElevationModel* MarbleModel::elevationModel() const
872{
873 return &d->m_elevationModel;
874}
875
876}
877
878#include "moc_MarbleModel.cpp"
This file contains the headers for MarbleModel.
This class is responsible for loading the book mark objects from the files and various book mark oper...
void addFile(const QString &fileName, const QString &property, const GeoDataStyle::Ptr &style, DocumentRole role, int renderOrder=0, bool recenter=false)
Loads a new file into the manager.
void removeFile(const QString &fileName)
removes an existing file from the manager
void addData(const QString &name, const QString &data, DocumentRole role)
add Data containing KML code as string
A 3d point representation.
void geoCoordinates(qreal &lon, qreal &lat, GeoDataCoordinates::Unit unit) const
use this function to get the longitude and latitude with one call - use the unit parameter to switch ...
A base class for all geodata features.
a class representing a point of interest on the map
The representation of GeoData in a model This class represents all available data given by kml-data f...
A container for features parsed from the DGML file.
qreal radius() const
Planet radius, 0.0 if unknown.
Layer of a GeoScene document.
bool hasVectorLayers() const
Checks for valid layers that contain vector data.
GeoSceneLayer * layer(const QString &name)
Return a layer by its name.
bool hasTextureLayers() const
Checks for valid layers that contain texture data.
This class manages scheduled downloads.
void setDownloadEnabled(const bool enable)
Switches loading on/off, useful for offline mode.
void setSourceModel(QAbstractItemModel *model) override
Sets the source model of the proxy.
static GeoSceneDocument * loadMapTheme(const QString &mapThemeStringID)
Returns the map theme as a GeoSceneDocument object.
BookmarkManager * bookmarkManager()
return instance of BookmarkManager
void trackedPlacemarkChanged(const GeoDataPlacemark *placemark)
Emitted when the placemark tracked by this model has changed.
void addGeoDataFile(const QString &filename)
Handle file loading into the treeModel.
HttpDownloadManager * downloadManager()
Return the downloadmanager to load missing tiles.
const Planet * planet() const
Returns the planet object for the current map.
quint64 persistentTileCacheLimit() const
Returns the limit in kilobytes of the persistent (on hard disc) tile cache.
void homeChanged(const GeoDataCoordinates &newHomePoint)
Emitted when the home location is changed.
void themeChanged(const QString &mapTheme)
Signal that the map theme has changed, and to which theme.
void setPersistentTileCacheLimit(quint64 kiloBytes)
Set the limit of the persistent (on hard disc) tile cache.
void removeGeoData(const QString &key)
Remove the file or raw data from the treeModel.
const GeoDataPlacemark * trackedPlacemark() const
Returns the placemark being tracked by this model or 0 if no placemark is currently tracked.
void setTrackedPlacemark(const GeoDataPlacemark *placemark)
Change the placemark tracked by this model.
void addGeoDataString(const QString &data, const QString &key=QLatin1String("data"))
Handle raw data loading into the treeModel.
void home(qreal &lon, qreal &lat, int &zoom) const
get the home point
void setHome(qreal lon, qreal lat, int zoom=1050)
Set the home point.
void setMapThemeId(const QString &mapThemeId)
Set a new map theme to use.
void setLegend(QTextDocument *document)
Uses the given text document as the new content of the legend Any previous legend content is overwrit...
MarbleModel(QObject *parent=nullptr)
Construct a new MarbleModel.
GeoDataTreeModel * treeModel()
Return the list of Placemarks as a QAbstractItemModel *.
static Planet construct(const QString &id)
Creates the planet with the given ID, or one with default values if ID is not among planetList()
The class that handles Marble's plugins.
void addPositionProviderPlugin(const PositionProviderPlugin *plugin)
Add a PositionProviderPlugin manually to the list of known plugins.
Delegates data retrieval and model updates to the appropriate routing provider.
Binds a QML item to a specific geodetic location in screen coordinates.
const QColor & color() const const
bool isValid() const const
void setAlphaF(float alpha)
void setModel(QAbstractItemModel *model)
const_iterator constBegin() const const
const_iterator constEnd() const const
bool isEmpty() const const
qsizetype size() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QVariant property(const char *name) const const
T qobject_cast(QObject *object)
QColor color() const const
Qt::PenStyle style() const const
int width() const const
void setFilterKeyColumn(int column)
void setFilterFixedString(const QString &pattern)
virtual void setSourceModel(QAbstractItemModel *sourceModel) override
bool isEmpty() const const
QString toLower() const const
QFuture< void > map(Iterator begin, Iterator end, MapFunctor &&function)
bool isRunning() const const
void quit()
void start(Priority priority)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:18:17 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.