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 //
6 
7 #include "FileManager.h"
8 
9 #include <QFileInfo>
10 #include <QElapsedTimer>
11 
12 #include "FileLoader.h"
13 #include "MarbleDebug.h"
14 #include "MarbleModel.h"
15 #include "GeoDataTreeModel.h"
16 
17 #include "GeoDataLatLonAltBox.h"
18 #include "GeoDataStyle.h"
19 
20 
21 using namespace Marble;
22 
23 namespace Marble
24 {
25 class FileManagerPrivate
26 {
27 public:
FileManagerPrivate(GeoDataTreeModel * treeModel,const PluginManager * pluginManager,FileManager * parent)28     FileManagerPrivate( GeoDataTreeModel *treeModel, const PluginManager *pluginManager, FileManager* parent ) :
29         q( parent ),
30         m_treeModel( treeModel ),
31         m_pluginManager( pluginManager )
32     {
33     }
34 
~FileManagerPrivate()35     ~FileManagerPrivate()
36     {
37         for ( FileLoader *loader: m_loaderList ) {
38             if ( loader ) {
39                 loader->wait();
40             }
41         }
42     }
43 
44     void appendLoader( FileLoader *loader );
45     void closeFile( const QString &key );
46     void cleanupLoader( FileLoader *loader );
47 
48     FileManager *const q;
49     GeoDataTreeModel *const m_treeModel;
50     const PluginManager *const m_pluginManager;
51 
52     QList<FileLoader*> m_loaderList;
53     QHash < QString, GeoDataDocument* > m_fileItemHash;
54     GeoDataLatLonBox m_latLonBox;
55     QElapsedTimer m_timer;
56 };
57 }
58 
FileManager(GeoDataTreeModel * treeModel,const PluginManager * pluginManager,QObject * parent)59 FileManager::FileManager( GeoDataTreeModel *treeModel, const PluginManager *pluginManager, QObject *parent )
60     : QObject( parent )
61     , d( new FileManagerPrivate( treeModel, pluginManager, this ) )
62 {
63 }
64 
65 
~FileManager()66 FileManager::~FileManager()
67 {
68     delete d;
69 }
70 
addFile(const QString & filepath,const QString & property,const GeoDataStyle::Ptr & style,DocumentRole role,int renderOrder,bool recenter)71 void FileManager::addFile( const QString& filepath, const QString& property, const GeoDataStyle::Ptr &style, DocumentRole role, int renderOrder, bool recenter )
72 {
73     if( d->m_fileItemHash.contains( filepath ) ) {
74             return;  // already loaded
75     }
76 
77     for ( const FileLoader *loader: d->m_loaderList ) {
78         if ( loader->path() == filepath )
79             return;  // currently loading
80     }
81 
82     mDebug() << "adding container:" << filepath;
83     mDebug() << "Starting placemark loading timer";
84     d->m_timer.start();
85     FileLoader* loader = new FileLoader( this, d->m_pluginManager, recenter, filepath, property, style, role, renderOrder );
86     d->appendLoader( loader );
87 }
88 
addData(const QString & name,const QString & data,DocumentRole role)89 void FileManager::addData( const QString &name, const QString &data, DocumentRole role )
90 {
91     FileLoader* loader = new FileLoader( this, d->m_pluginManager, data, name, role );
92     d->appendLoader( loader );
93 }
94 
appendLoader(FileLoader * loader)95 void FileManagerPrivate::appendLoader( FileLoader *loader )
96 {
97     QObject::connect( loader, SIGNAL(loaderFinished(FileLoader*)),
98              q, SLOT(cleanupLoader(FileLoader*)) );
99 
100     m_loaderList.append( loader );
101     loader->start();
102 }
103 
removeFile(const QString & key)104 void FileManager::removeFile( const QString& key )
105 {
106     for ( FileLoader *loader: d->m_loaderList ) {
107         if ( loader->path() == key ) {
108             disconnect( loader, nullptr, this, nullptr );
109             loader->wait();
110             d->m_loaderList.removeAll( loader );
111             delete loader->document();
112             return;
113         }
114     }
115 
116     if( d->m_fileItemHash.contains( key ) ) {
117         d->closeFile( key );
118     }
119 
120     mDebug() << "could not identify " << key;
121 }
122 
closeFile(const QString & key)123 void FileManagerPrivate::closeFile( const QString& key )
124 {
125     mDebug() << "FileManager::closeFile " << key;
126     if( m_fileItemHash.contains( key ) ) {
127         GeoDataDocument *doc = m_fileItemHash.value( key );
128         m_treeModel->removeDocument( doc );
129         emit q->fileRemoved( key );
130         delete doc;
131         m_fileItemHash.remove( key );
132     }
133 }
134 
closeFile(const GeoDataDocument * document)135 void FileManager::closeFile( const GeoDataDocument *document )
136 {
137     QHash < QString, GeoDataDocument* >::iterator itpoint = d->m_fileItemHash.begin();
138     QHash < QString, GeoDataDocument* >::iterator const endpoint = d->m_fileItemHash.end();
139     for (; itpoint != endpoint; ++itpoint ) {
140         if( d->m_fileItemHash.value( itpoint.key() ) == document ) {
141             d->closeFile( itpoint.key() );
142             return;
143         }
144     }
145 }
146 
size() const147 int FileManager::size() const
148 {
149     return d->m_fileItemHash.size();
150 }
151 
at(const QString & key)152 GeoDataDocument * FileManager::at( const QString &key )
153 {
154     if ( d->m_fileItemHash.contains( key ) ) {
155         return d->m_fileItemHash.value( key );
156     }
157     return nullptr;
158 }
159 
pendingFiles() const160 int FileManager::pendingFiles() const
161 {
162     return d->m_loaderList.size();
163 }
164 
cleanupLoader(FileLoader * loader)165 void FileManagerPrivate::cleanupLoader( FileLoader* loader )
166 {
167     GeoDataDocument *doc = loader->document();
168     m_loaderList.removeAll( loader );
169     if ( loader->isFinished() ) {
170         if ( doc ) {
171             if ( doc->name().isEmpty() && !doc->fileName().isEmpty() )
172             {
173                 QFileInfo file( doc->fileName() );
174                 doc->setName( file.baseName() );
175             }
176             m_treeModel->addDocument( doc );
177             m_fileItemHash.insert( loader->path(), doc );
178             emit q->fileAdded( loader->path() );
179             if( loader->recenter() ) {
180                 m_latLonBox |= doc->latLonAltBox();
181             }
182         }
183         if ( !loader->error().isEmpty() ) {
184             qWarning() << "Failed to parse" << loader->path() << loader->error();
185             emit q->fileError(loader->path(), loader->error());
186         }
187         delete loader;
188     }
189     if ( m_loaderList.isEmpty()  )
190     {
191         mDebug() << "Finished loading all placemarks " << m_timer.elapsed();
192 
193         if ( !m_latLonBox.isEmpty() ) {
194             emit q->centeredDocument( m_latLonBox );
195         }
196         m_latLonBox.clear();
197     }
198 }
199 
200 #include "moc_FileManager.cpp"
201