Marble

MarbleModel.cpp
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2006-2007 Torsten Rahn <[email protected]>
4 // SPDX-FileCopyrightText: 2007 Inge Wallin <[email protected]>
5 // SPDX-FileCopyrightText: 2008, 2009, 2010 Jens-Michael Hoffmann <[email protected]>
6 // SPDX-FileCopyrightText: 2008-2009 Patrick Spendrin <[email protected]>
7 // SPDX-FileCopyrightText: 2010-2013 Bernhard Beschow <[email protected]>
8 // SPDX-FileCopyrightText: 2014 Abhinav Gangwar <[email protected]>
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 
70 namespace Marble
71 {
72 
73 class 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 
195 MarbleModel::~MarbleModel()
196 {
197  delete d;
198 
199  mDebug() << "Model deleted:" << this;
200 }
201 
203 {
204  return &d->m_bookmarkManager;
205 }
206 
207 QString 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 
217 GeoSceneDocument *MarbleModel::mapTheme()
218 {
219  return d->m_mapTheme;
220 }
221 
222 const 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 
236 void 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 
245 void 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
268  QList<GeoSceneGeodata> currentDatasets;
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 
317  QStringList fileList;
318  QStringList propertyList;
319  QList<GeoDataStyle::Ptr> styleList;
320  QList<int> renderOrderList;
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;
385  propertyList << property;
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 
404 void 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 
438 void 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 
444 void 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 
451 void 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 
479 QAbstractItemModel *MarbleModel::placemarkModel()
480 {
481  return &d->m_placemarkProxyModel;
482 }
483 
484 const QAbstractItemModel *MarbleModel::placemarkModel() const
485 {
486  return &d->m_placemarkProxyModel;
487 }
488 
489 QAbstractItemModel *MarbleModel::groundOverlayModel()
490 {
491  return &d->m_groundOverlayProxyModel;
492 }
493 
494 const QAbstractItemModel *MarbleModel::groundOverlayModel() const
495 {
496  return &d->m_groundOverlayProxyModel;
497 }
498 
499 QItemSelectionModel *MarbleModel::placemarkSelectionModel()
500 {
501  return &d->m_placemarkSelectionModel;
502 }
503 
504 PositionTracking *MarbleModel::positionTracking() const
505 {
506  return &d->m_positionTracking;
507 }
508 
509 FileManager *MarbleModel::fileManager()
510 {
511  return &d->m_fileManager;
512 }
513 
514 qreal MarbleModel::planetRadius() const
515 {
516  return d->m_planet.radius();
517 }
518 
519 QString MarbleModel::planetName() const
520 {
521  return d->m_planet.name();
522 }
523 
524 QString MarbleModel::planetId() const
525 {
526  return d->m_planet.id();
527 }
528 
529 MarbleClock *MarbleModel::clock()
530 {
531  return &d->m_clock;
532 }
533 
534 const MarbleClock *MarbleModel::clock() const
535 {
536  return &d->m_clock;
537 }
538 
539 SunLocator *MarbleModel::sunLocator()
540 {
541  return &d->m_sunLocator;
542 }
543 
544 const SunLocator *MarbleModel::sunLocator() const
545 {
546  return &d->m_sunLocator;
547 }
548 
550 {
551  return d->m_storageWatcher.cacheLimit() / 1024;
552 }
553 
554 void 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 
626 const PluginManager* MarbleModel::pluginManager() const
627 {
628  return &d->m_pluginManager;
629 }
630 
631 PluginManager* MarbleModel::pluginManager()
632 {
633  return &d->m_pluginManager;
634 }
635 
636 const Planet *MarbleModel::planet() const
637 {
638  return &d->m_planet;
639 }
640 
641 void 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 
667 RoutingManager* MarbleModel::routingManager()
668 {
669  return d->m_routingManager;
670 }
671 
672 const RoutingManager* MarbleModel::routingManager() const
673 {
674  return d->m_routingManager;
675 }
676 
677 void MarbleModel::setClockDateTime( const QDateTime& datetime )
678 {
679  d->m_clock.setDateTime( datetime );
680 }
681 
682 QDateTime MarbleModel::clockDateTime() const
683 {
684  return d->m_clock.dateTime();
685 }
686 
687 int MarbleModel::clockSpeed() const
688 {
689  return d->m_clock.speed();
690 }
691 
692 void MarbleModel::setClockSpeed( int speed )
693 {
694  d->m_clock.setSpeed( speed );
695 }
696 
697 void MarbleModel::setClockTimezone( int timeInSec )
698 {
699  d->m_clock.setTimezone( timeInSec );
700 }
701 
702 int MarbleModel::clockTimezone() const
703 {
704  return d->m_clock.timezone();
705 }
706 
707 QTextDocument * MarbleModel::legend()
708 {
709  return d->m_legend;
710 }
711 
713 {
714  delete d->m_legend;
715  d->m_legend = legend;
716 }
717 
718 void MarbleModel::addGeoDataFile( const QString& filename )
719 {
720  d->m_fileManager.addFile( filename, filename, GeoDataStyle::Ptr(), UserDocument, 0, true );
721 }
722 
723 void MarbleModel::addGeoDataString( const QString& data, const QString& key )
724 {
725  d->m_fileManager.addData( key, data, UserDocument );
726 }
727 
728 void MarbleModel::removeGeoData( const QString& fileName )
729 {
730  d->m_fileManager.removeFile( fileName );
731 }
732 
733 void 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 
745 void 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 
778 void 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 
851 bool MarbleModel::workOffline() const
852 {
853  return d->m_workOffline;
854 }
855 
856 void 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 
866 ElevationModel* MarbleModel::elevationModel()
867 {
868  return &d->m_elevationModel;
869 }
870 
871 const ElevationModel* MarbleModel::elevationModel() const
872 {
873  return &d->m_elevationModel;
874 }
875 
876 }
877 
878 #include "moc_MarbleModel.cpp"
void addGeoDataString(const QString &data, const QString &key=QLatin1String("data"))
Handle raw data loading into the treeModel.
const QColor & color() const const
A 3d point representation.
bool isEmpty() const const
BookmarkManager * bookmarkManager()
return instance of BookmarkManager
void setLegend(QTextDocument *document)
Uses the given text document as the new content of the legend Any previous legend content is overwrit...
Delegates data retrieval and model updates to the appropriate routing provider.
const Planet * planet() const
Returns the planet object for the current map.
This class manages scheduled downloads.
QList::const_iterator constBegin() const const
Layer of a GeoScene document.
Definition: GeoSceneLayer.h:28
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void removeAt(int i)
This class is responsible for loading the book mark objects from the files and various book mark oper...
bool hasTextureLayers() const
Checks for valid layers that contain texture data.
int size() const const
void addGeoDataFile(const QString &filename)
Handle file loading into the treeModel.
static Planet construct(const QString &id)
Creates the planet with the given ID, or one with default values if ID is not among planetList()
int width() const const
Qt::PenStyle style() const const
void setTrackedPlacemark(const GeoDataPlacemark *placemark)
Change the placemark tracked by this model.
A base class for all geodata features.
void setAlphaF(qreal alpha)
HttpDownloadManager * downloadManager()
Return the downloadmanager to load missing tiles.
bool isEmpty() const const
const T & at(int i) const const
The representation of GeoData in a model This class represents all available data given by kml-data f...
The class that handles Marble's plugins.
Definition: PluginManager.h:39
Binds a QML item to a specific geodetic location in screen coordinates.
void setDownloadEnabled(const bool enable)
Switches loading on/off, useful for offline mode.
GeoSceneLayer * layer(const QString &name)
Return a layer by its name.
Definition: GeoSceneMap.cpp:92
void themeChanged(const QString &mapTheme)
Signal that the map theme has changed, and to which theme.
a class representing a point of interest on the map
GeoDataTreeModel * treeModel()
Return the list of Placemarks as a QAbstractItemModel *.
void homeChanged(const GeoDataCoordinates &newHomePoint)
Emitted when the home location is changed.
void trackedPlacemarkChanged(const GeoDataPlacemark *placemark)
Emitted when the placemark tracked by this model has changed.
QList::const_iterator constEnd() const const
void removeGeoData(const QString &key)
Remove the file or raw data from the treeModel.
void home(qreal &lon, qreal &lat, int &zoom) const
get the home point
QColor color() const const
void setMapThemeId(const QString &mapThemeId)
Set a new map theme to use.
bool isValid() const const
int size() const const
bool hasVectorLayers() const
Checks for valid layers that contain vector data.
const GeoDataPlacemark * trackedPlacemark() const
Returns the placemark being tracked by this model or 0 if no placemark is currently tracked.
static GeoSceneDocument * loadMapTheme(const QString &mapThemeStringID)
Returns the map theme as a GeoSceneDocument object.
quint64 persistentTileCacheLimit() const
Returns the limit in kilobytes of the persistent (on hard disc) tile cache.
void setPersistentTileCacheLimit(quint64 kiloBytes)
Set the limit of the persistent (on hard disc) tile cache.
void setHome(qreal lon, qreal lat, int zoom=1050)
Set the home point.
MarbleModel(QObject *parent=nullptr)
Construct a new MarbleModel.
A container for features parsed from the DGML file.
QDebug mDebug()
a function to replace qDebug() in Marble library code
Definition: MarbleDebug.cpp:31
QVariant property(const char *name) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Sep 25 2023 03:50:19 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.