• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeedu API Reference
  • KDE Home
  • Contact Us
 

marble

  • sources
  • kde-4.14
  • kdeedu
  • marble
  • src
  • lib
  • marble
MapThemeManager.cpp
Go to the documentation of this file.
1 //
2 // This file is part of the Marble Virtual Globe.
3 //
4 // This program is free software licensed under the GNU LGPL. You can
5 // find a copy of this license in LICENSE.txt in the top directory of
6 // the source code.
7 //
8 // Copyright 2008 Torsten Rahn <tackat@kde.org>
9 // Copyright 2008 Jens-Michael Hoffmann <jensmh@gmx.de>
10 //
11 
12 
13 // Own
14 #include "MapThemeManager.h"
15 
16 // Qt
17 #include <QDir>
18 #include <QFile>
19 #include <QFileInfo>
20 #include <QFileSystemWatcher>
21 #include <QScopedPointer>
22 #include <QString>
23 #include <QStringList>
24 #include <QTimer>
25 #include <QStandardItemModel>
26 
27 // Local dir
28 #include "GeoSceneDocument.h"
29 #include "GeoSceneHead.h"
30 #include "GeoSceneIcon.h"
31 #include "GeoSceneParser.h"
32 #include "MarbleDebug.h"
33 #include "MarbleDirs.h"
34 #include "Planet.h"
35 
36 namespace
37 {
38  static const QString mapDirName = "maps";
39  static const int columnRelativePath = 1;
40 }
41 
42 namespace Marble
43 {
44 
45 class MapThemeManager::Private
46 {
47 public:
48  Private( MapThemeManager *parent );
49  ~Private();
50 
51  void directoryChanged( const QString& path );
52  void fileChanged( const QString & path );
53 
60  void updateMapThemeModel();
61 
62  void watchPaths();
63 
67  static void addMapThemePaths( const QString& mapPathName, QStringList& result );
68 
73  static QStringList findMapThemes( const QString& basePath );
74 
78  static QStringList findMapThemes();
79 
80  static GeoSceneDocument* loadMapThemeFile( const QString& mapThemeId );
81 
85  static QList<QStandardItem *> createMapThemeRow( const QString& mapThemeID );
86 
92  static bool deleteDirectory( const QString &directory );
93 
94  MapThemeManager *const q;
95  QStandardItemModel m_mapThemeModel;
96  QStandardItemModel m_celestialList;
97  QFileSystemWatcher m_fileSystemWatcher;
98  bool m_isInitialized;
99 
100 private:
105  static QStringList pathsToWatch();
106 };
107 
108 MapThemeManager::Private::Private( MapThemeManager *parent )
109  : q( parent ),
110  m_mapThemeModel( 0, 3 ),
111  m_celestialList(),
112  m_fileSystemWatcher(),
113  m_isInitialized( false )
114 {
115 }
116 
117 MapThemeManager::Private::~Private()
118 {
119 }
120 
121 
122 MapThemeManager::MapThemeManager( QObject *parent )
123  : QObject( parent ),
124  d( new Private( this ) )
125 {
126  d->watchPaths();
127  connect( &d->m_fileSystemWatcher, SIGNAL(directoryChanged(QString)),
128  this, SLOT(directoryChanged(QString)));
129  connect( &d->m_fileSystemWatcher, SIGNAL(fileChanged(QString)),
130  this, SLOT(fileChanged(QString)));
131 }
132 
133 MapThemeManager::~MapThemeManager()
134 {
135  delete d;
136 }
137 
138 QStringList MapThemeManager::mapThemeIds() const
139 {
140  QStringList result;
141 
142  if ( !d->m_isInitialized ) {
143  d->updateMapThemeModel();
144  d->m_isInitialized = true;
145  }
146 
147  for( int i = 0; i < d->m_mapThemeModel.rowCount(); ++i ) {
148  const QString id = d->m_mapThemeModel.data( d->m_mapThemeModel.index( i, 0 ), Qt::UserRole + 1 ).toString();
149  result << id;
150  }
151 
152  return result;
153 }
154 
155 GeoSceneDocument* MapThemeManager::loadMapTheme( const QString& mapThemeStringID )
156 {
157  if ( mapThemeStringID.isEmpty() )
158  return 0;
159 
160  return Private::loadMapThemeFile( mapThemeStringID );
161 }
162 
163 void MapThemeManager::deleteMapTheme( const QString &mapThemeId )
164 {
165  QString dgmlPath = MarbleDirs::localPath() + "/maps/" + mapThemeId;
166  QFileInfo dgmlFile(dgmlPath);
167 
168  QString themeDir = dgmlFile.dir().absolutePath();
169  Private::deleteDirectory( themeDir );
170 }
171 
172 bool MapThemeManager::Private::deleteDirectory( const QString& directory )
173 {
174  QDir dir( directory );
175  bool result = true;
176 
177  if ( dir.exists() ) {
178  Q_FOREACH( const QFileInfo &info, dir.entryInfoList(
179  QDir::NoDotAndDotDot | QDir::System | QDir::Hidden |
180  QDir::AllDirs | QDir::Files,
181  QDir::DirsFirst ) ) {
182 
183  if ( info.isDir() ) {
184  result = deleteDirectory( info.absoluteFilePath() );
185  } else {
186  result = QFile::remove( info.absoluteFilePath() );
187  }
188 
189  if ( !result ) {
190  return result;
191  }
192  }
193 
194  result = dir.rmdir( directory );
195 
196  if( !result ) {
197  return result;
198  }
199  }
200 
201  return result;
202 }
203 
204 GeoSceneDocument* MapThemeManager::Private::loadMapThemeFile( const QString& mapThemeStringID )
205 {
206  const QString mapThemePath = mapDirName + '/' + mapThemeStringID;
207  const QString dgmlPath = MarbleDirs::path( mapThemePath );
208 
209  // Check whether file exists
210  QFile file( dgmlPath );
211  if ( !file.exists() ) {
212  qWarning() << "Map theme file does not exist:" << dgmlPath;
213  return 0;
214  }
215 
216  // Open file in right mode
217  const bool fileReadable = file.open( QIODevice::ReadOnly );
218 
219  if ( !fileReadable ) {
220  qWarning() << "Map theme file not readable:" << dgmlPath;
221  return 0;
222  }
223 
224  GeoSceneParser parser( GeoScene_DGML );
225 
226  if ( !parser.read( &file )) {
227  qWarning() << "Map theme file not well-formed:" << dgmlPath;
228  return 0;
229  }
230 
231  mDebug() << "Map theme file successfully loaded:" << dgmlPath;
232 
233  // Get result document
234  GeoSceneDocument* document = static_cast<GeoSceneDocument*>( parser.releaseDocument() );
235  Q_ASSERT( document );
236  return document;
237 }
238 
239 QStringList MapThemeManager::Private::pathsToWatch()
240 {
241  QStringList result;
242  const QString localMapPathName = MarbleDirs::localPath() + '/' + mapDirName;
243  const QString systemMapPathName = MarbleDirs::systemPath() + '/' + mapDirName;
244 
245  if( !QDir().exists( localMapPathName ) ) {
246  QDir().mkpath( localMapPathName );
247  }
248 
249  result << localMapPathName;
250  result << systemMapPathName;
251  addMapThemePaths( localMapPathName, result );
252  addMapThemePaths( systemMapPathName, result );
253  return result;
254 }
255 
256 QStringList MapThemeManager::Private::findMapThemes( const QString& basePath )
257 {
258  const QString mapPathName = basePath + '/' + mapDirName;
259 
260  QDir paths = QDir( mapPathName );
261 
262  QStringList mapPaths = paths.entryList( QStringList( "*" ),
263  QDir::AllDirs
264  | QDir::NoSymLinks
265  | QDir::NoDotAndDotDot );
266  QStringList mapDirs;
267 
268  for ( int planet = 0; planet < mapPaths.size(); ++planet ) {
269  QDir themeDir = QDir( mapPathName + '/' + mapPaths.at( planet ) );
270  QStringList themeMapPaths = themeDir.entryList(
271  QStringList( "*" ),
272  QDir::AllDirs |
273  QDir::NoSymLinks |
274  QDir::NoDotAndDotDot );
275  for ( int theme = 0; theme < themeMapPaths.size(); ++theme ) {
276  mapDirs << mapPathName + '/' + mapPaths.at( planet ) + '/'
277  + themeMapPaths.at( theme );
278  }
279  }
280 
281  QStringList mapFiles;
282  QStringListIterator it( mapDirs );
283  while ( it.hasNext() ) {
284  QString themeDir = it.next() + '/';
285  QString themeDirName = QDir( themeDir ).path().section( '/', -2, -1 );
286  QStringList tmp = QDir( themeDir ).entryList( QStringList( "*.dgml" ),
287  QDir::Files | QDir::NoSymLinks );
288  if ( !tmp.isEmpty() ) {
289  QStringListIterator k( tmp );
290  while ( k.hasNext() ) {
291  QString themeXml = k.next();
292  mapFiles << themeDirName + '/' + themeXml;
293  }
294  }
295  }
296 
297  return mapFiles;
298 }
299 
300 QStringList MapThemeManager::Private::findMapThemes()
301 {
302  QStringList mapFilesLocal = findMapThemes( MarbleDirs::localPath() );
303  QStringList mapFilesSystem = findMapThemes( MarbleDirs::systemPath() );
304  QStringList allMapFiles( mapFilesLocal );
305  allMapFiles << mapFilesSystem;
306 
307  // remove duplicate entries
308  allMapFiles.sort();
309  for ( int i = 1; i < allMapFiles.size(); ++i ) {
310  if ( allMapFiles.at(i) == allMapFiles.at( i-1 ) ) {
311  allMapFiles.removeAt( i );
312  --i;
313  }
314  }
315 
316  return allMapFiles;
317 }
318 
319 QStandardItemModel* MapThemeManager::mapThemeModel()
320 {
321  if ( !d->m_isInitialized ) {
322  d->updateMapThemeModel();
323  d->m_isInitialized = true;
324  }
325  return &d->m_mapThemeModel;
326 }
327 
328 QStandardItemModel *MapThemeManager::celestialBodiesModel()
329 {
330  if ( !d->m_isInitialized ) {
331  d->updateMapThemeModel();
332  d->m_isInitialized = true;
333  }
334 
335  return &d->m_celestialList;
336 }
337 
338 QList<QStandardItem *> MapThemeManager::Private::createMapThemeRow( QString const& mapThemeID )
339 {
340  QList<QStandardItem *> itemList;
341 
342  QScopedPointer<GeoSceneDocument> mapTheme( loadMapThemeFile( mapThemeID ) );
343  if ( !mapTheme || !mapTheme->head()->visible() ) {
344  return itemList;
345  }
346 
347  QPixmap themeIconPixmap;
348  QString relativePath;
349 
350  relativePath = mapDirName + '/'
351  + mapTheme->head()->target() + '/' + mapTheme->head()->theme() + '/'
352  + mapTheme->head()->icon()->pixmap();
353  themeIconPixmap.load( MarbleDirs::path( relativePath ) );
354 
355  if ( themeIconPixmap.isNull() ) {
356  relativePath = "svg/application-x-marble-gray.png";
357  themeIconPixmap.load( MarbleDirs::path( relativePath ) );
358  }
359  else {
360  // Make sure we don't keep excessively large previews in memory
361  // TODO: Scale the icon down to the default icon size in MarbleSelectView.
362  // For now maxIconSize already equals what's expected by the listview.
363  QSize maxIconSize( 136, 136 );
364  if ( themeIconPixmap.size() != maxIconSize ) {
365  mDebug() << "Smooth scaling theme icon";
366  themeIconPixmap = themeIconPixmap.scaled( maxIconSize,
367  Qt::KeepAspectRatio,
368  Qt::SmoothTransformation );
369  }
370  }
371 
372  QIcon mapThemeIcon = QIcon( themeIconPixmap );
373 
374  QString name = mapTheme->head()->name();
375  QString description = mapTheme->head()->description();
376 
377  QStandardItem *item = new QStandardItem( name );
378  item->setData( QObject::tr( name.toUtf8() ), Qt::DisplayRole );
379  item->setData( mapThemeIcon, Qt::DecorationRole );
380  item->setData( QString( "<span style=\" max-width: 150 px;\"> "
381  + QObject::tr( description.toUtf8() ) + " </span>" ), Qt::ToolTipRole );
382  item->setData( mapThemeID, Qt::UserRole + 1 );
383  item->setData( QObject::tr( description.toUtf8() ), Qt::UserRole + 2 );
384 
385  itemList << item;
386 
387  return itemList;
388 }
389 
390 void MapThemeManager::Private::updateMapThemeModel()
391 {
392  mDebug() << "updateMapThemeModel";
393  m_mapThemeModel.clear();
394 
395  m_mapThemeModel.setHeaderData(0, Qt::Horizontal, QObject::tr("Name"));
396 
397  QStringList stringlist = findMapThemes();
398  QStringListIterator it( stringlist );
399 
400  while ( it.hasNext() ) {
401  QString mapThemeID = it.next();
402 
403  QList<QStandardItem *> itemList = createMapThemeRow( mapThemeID );
404  if ( !itemList.empty() ) {
405  m_mapThemeModel.appendRow( itemList );
406  }
407  }
408 
409  foreach ( const QString &mapThemeId, stringlist ) {
410  QString celestialBodyId = mapThemeId.section( '/', 0, 0 );
411  QString celestialBodyName = Planet::name( celestialBodyId );
412 
413  QList<QStandardItem*> matchingItems = m_celestialList.findItems( celestialBodyId, Qt::MatchExactly, 1 );
414  if ( matchingItems.isEmpty() ) {
415  m_celestialList.appendRow( QList<QStandardItem*>()
416  << new QStandardItem( celestialBodyName )
417  << new QStandardItem( celestialBodyId ) );
418  }
419  }
420 }
421 
422 void MapThemeManager::Private::watchPaths()
423 {
424  QStringList const paths = pathsToWatch();
425  QStringList const files = m_fileSystemWatcher.files();
426  QStringList const directories = m_fileSystemWatcher.directories();
427  // Check each resource to add that it is not being watched already,
428  // otherwise some qWarning appears
429  foreach( const QString &resource, paths ) {
430  if ( !directories.contains( resource ) && !files.contains( resource ) ) {
431  m_fileSystemWatcher.addPath( resource );
432  }
433  }
434 }
435 
436 void MapThemeManager::Private::directoryChanged( const QString& path )
437 {
438  mDebug() << "directoryChanged:" << path;
439  watchPaths();
440 
441  mDebug() << "Emitting themesChanged()";
442  updateMapThemeModel();
443  emit q->themesChanged();
444 }
445 
446 void MapThemeManager::Private::fileChanged( const QString& path )
447 {
448  mDebug() << "fileChanged:" << path;
449 
450  // 1. if the file does not (anymore) exist, it got deleted and we
451  // have to delete the corresponding item from the model
452  // 2. if the file exists it is changed and we have to replace
453  // the item with a new one.
454 
455  QString mapThemeId = path.section( '/', -3 );
456  mDebug() << "mapThemeId:" << mapThemeId;
457  QList<QStandardItem *> matchingItems = m_mapThemeModel.findItems( mapThemeId,
458  Qt::MatchFixedString
459  | Qt::MatchCaseSensitive,
460  columnRelativePath );
461  mDebug() << "matchingItems:" << matchingItems.size();
462  Q_ASSERT( matchingItems.size() <= 1 );
463  int insertAtRow = 0;
464 
465  if ( matchingItems.size() == 1 ) {
466  const int row = matchingItems.front()->row();
467  insertAtRow = row;
468  QList<QStandardItem *> toBeDeleted = m_mapThemeModel.takeRow( row );
469  while ( !toBeDeleted.isEmpty() ) {
470  delete toBeDeleted.takeFirst();
471  }
472  }
473 
474  QFileInfo fileInfo( path );
475  if ( fileInfo.exists() ) {
476  QList<QStandardItem *> newMapThemeRow = createMapThemeRow( mapThemeId );
477  if ( !newMapThemeRow.empty() ) {
478  m_mapThemeModel.insertRow( insertAtRow, newMapThemeRow );
479  }
480  }
481 
482  emit q->themesChanged();
483 }
484 
485 //
486 // <mapPathName>/<orbDirName>/<themeDirName>
487 //
488 void MapThemeManager::Private::addMapThemePaths( const QString& mapPathName, QStringList& result )
489 {
490  QDir mapPath( mapPathName );
491  QStringList orbDirNames = mapPath.entryList( QStringList( "*" ),
492  QDir::AllDirs
493  | QDir::NoSymLinks
494  | QDir::NoDotAndDotDot );
495  QStringListIterator itOrb( orbDirNames );
496  while ( itOrb.hasNext() ) {
497  QString orbPathName = mapPathName + '/' + itOrb.next();
498  result << orbPathName;
499 
500  QDir orbPath( orbPathName );
501  QStringList themeDirNames = orbPath.entryList( QStringList( "*" ),
502  QDir::AllDirs
503  | QDir::NoSymLinks
504  | QDir::NoDotAndDotDot );
505  QStringListIterator itThemeDir( themeDirNames );
506  while ( itThemeDir.hasNext() ) {
507  QString themePathName = orbPathName + '/' + itThemeDir.next();
508  result << themePathName;
509 
510  QDir themePath( themePathName );
511  QStringList themeFileNames = themePath.entryList( QStringList( "*.dgml" ),
512  QDir::Files
513  | QDir::NoSymLinks );
514  QStringListIterator itThemeFile( themeFileNames );
515  while ( itThemeFile.hasNext() ) {
516  QString themeFilePathName = themePathName + '/' + itThemeFile.next();
517  result << themeFilePathName;
518  }
519  }
520  }
521 }
522 
523 }
524 
525 #include "MapThemeManager.moc"
GeoSceneHead.h
Marble::MapThemeManager::mapThemeModel
QStandardItemModel * mapThemeModel()
Provides a model of the locally existing themes.
Definition: MapThemeManager.cpp:319
QStandardItemModel
QPixmap::size
QSize size() const
Marble::MarbleDirs::path
static QString path(const QString &relativePath)
Definition: MarbleDirs.cpp:59
QFile::remove
bool remove()
Marble::MapThemeManager::MapThemeManager
MapThemeManager(QObject *parent=0)
Definition: MapThemeManager.cpp:122
Marble::MapThemeManager::~MapThemeManager
~MapThemeManager()
Definition: MapThemeManager.cpp:133
QList::at
const T & at(int i) const
MapThemeManager
Provides access to all map themes installed locally.
Definition: DeclarativeMapThemeManager.h:40
QStringList::contains
bool contains(const QString &str, Qt::CaseSensitivity cs) const
GeoSceneDocument.h
Marble::MarbleDirs::localPath
static QString localPath()
Definition: MarbleDirs.cpp:223
Planet.h
MarbleDebug.h
QObject::tr
QString tr(const char *sourceText, const char *disambiguation, int n)
QFile
QList::size
int size() const
QStandardItem::setData
virtual void setData(const QVariant &value, int role)
QList::empty
bool empty() const
QDir::path
QString path() const
QFileInfo::isDir
bool isDir() const
QObject
QScopedPointer
QList::isEmpty
bool isEmpty() const
MarbleDirs.h
QFileInfo::absoluteFilePath
QString absoluteFilePath() const
QString::isEmpty
bool isEmpty() const
Marble::MapThemeManager::loadMapTheme
static GeoSceneDocument * loadMapTheme(const QString &mapThemeStringID)
Returns the map theme as a GeoSceneDocument object.
Definition: MapThemeManager.cpp:155
Marble::MapThemeManager::deleteMapTheme
static void deleteMapTheme(const QString &mapThemeId)
Deletes the map theme with the specified map theme ID.
Definition: MapThemeManager.cpp:163
QList::front
T & front()
QFileInfo::dir
QDir dir() const
QPixmap::scaled
QPixmap scaled(int width, int height, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const
QString
QList
QPixmap::load
bool load(const QString &fileName, const char *format, QFlags< Qt::ImageConversionFlag > flags)
QStringList
QPixmap
QFileInfo
QPixmap::isNull
bool isNull() const
QSize
Marble::GeoSceneDocument
A container for features parsed from the DGML file.
Definition: GeoSceneDocument.h:44
QDir
QFileSystemWatcher
Marble::GeoScene_DGML
Definition: GeoSceneParser.h:35
QList::takeFirst
T takeFirst()
QDir::absolutePath
QString absolutePath() const
QDir::entryList
QStringList entryList(QFlags< QDir::Filter > filters, QFlags< QDir::SortFlag > sort) const
Marble::MapThemeManager::Private
friend class Private
Definition: MapThemeManager.h:104
QString::section
QString section(QChar sep, int start, int end, QFlags< QString::SectionFlag > flags) const
QStringList::sort
void sort()
Marble::Planet::name
QString name() const
The user visible name of the planet.
Definition: Planet.cpp:257
Marble::MarbleDirs::systemPath
static QString systemPath()
Definition: MarbleDirs.cpp:125
QStandardItem
Marble::MapThemeManager::mapThemeIds
QStringList mapThemeIds() const
Returns a list of all locally available map theme IDs.
Definition: MapThemeManager.cpp:138
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
GeoSceneIcon.h
GeoSceneParser.h
QObject::parent
QObject * parent() const
Marble::mDebug
QDebug mDebug()
a function to replace qDebug() in Marble library code
Definition: MarbleDebug.cpp:36
Marble::MapThemeManager::celestialBodiesModel
QStandardItemModel * celestialBodiesModel()
Provides a model of all installed planets.
Definition: MapThemeManager.cpp:328
MapThemeManager.h
QDir::mkpath
bool mkpath(const QString &dirPath) const
QIcon
QString::toUtf8
QByteArray toUtf8() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:13:40 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

marble

Skip menu "marble"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdeedu API Reference

Skip menu "kdeedu API Reference"
  • Analitza
  •     lib
  • kalgebra
  • kalzium
  •   libscience
  • kanagram
  • kig
  •   lib
  • klettres
  • marble
  • parley
  • rocs
  •   App
  •   RocsCore
  •   VisualEditor
  •   stepcore

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal