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

KDE's Doxygen guidelines are available online.