1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2010 Gaurav Gupta <1989.gaurav@googlemail.com>
4 // SPDX-FileCopyrightText: 2012 Thibaut Gridel <tgridel@free.fr>
5 //
6
7 #include "BookmarkManager.h"
8 #include "BookmarkManager_p.h"
9 #include "GeoDataParser.h"
10 #include "GeoDataContainer.h"
11 #include "GeoDataDocument.h"
12 #include "GeoDataFolder.h"
13 #include "GeoDataPlacemark.h"
14 #include "GeoDataTreeModel.h"
15 #include "GeoDataDocumentWriter.h"
16 #include "GeoDataIconStyle.h"
17 #include "KmlElementDictionary.h"
18 #include "MarbleDebug.h"
19 #include "MarbleDirs.h"
20 #include "StyleBuilder.h"
21 #include <QFile>
22
23 namespace Marble
24 {
25
BookmarkManagerPrivate(GeoDataTreeModel * treeModel)26 BookmarkManagerPrivate::BookmarkManagerPrivate( GeoDataTreeModel *treeModel ) :
27 m_treeModel( treeModel ),
28 m_bookmarkDocument( nullptr ),
29 m_bookmarkFileRelativePath( "bookmarks/bookmarks.kml" ),
30 m_styleBuilder(nullptr)
31 {
32 resetBookmarkDocument();
33 }
34
~BookmarkManagerPrivate()35 BookmarkManagerPrivate::~BookmarkManagerPrivate()
36 {
37 Q_ASSERT( m_bookmarkDocument && "BookmarkManagerPrivate::m_bookmarkDocument is 0. Please report a Marble bug at https://bugs.kde.org" );
38 if ( m_bookmarkDocument )
39 {
40 m_treeModel->removeDocument( m_bookmarkDocument );
41 }
42 delete m_bookmarkDocument;
43 }
44
resetBookmarkDocument()45 void BookmarkManagerPrivate::resetBookmarkDocument()
46 {
47 if ( m_bookmarkDocument ) {
48 m_treeModel->removeDocument( m_bookmarkDocument );
49 delete m_bookmarkDocument;
50 }
51
52 GeoDataFolder* folder = new GeoDataFolder;
53 folder->setName( QObject::tr( "Default" ) );
54
55 m_bookmarkDocument = new GeoDataDocument;
56 m_bookmarkDocument->setDocumentRole( BookmarkDocument );
57 m_bookmarkDocument->setName( QObject::tr("Bookmarks") );
58 m_bookmarkDocument->append( folder );
59 m_treeModel->addDocument( m_bookmarkDocument );
60 }
61
setVisualCategory(GeoDataContainer * container)62 void BookmarkManagerPrivate::setVisualCategory( GeoDataContainer *container ) {
63 for( GeoDataFolder* folder: container->folderList() ) {
64 setVisualCategory( folder );
65 }
66 for( GeoDataPlacemark* placemark: container->placemarkList() ) {
67 placemark->setVisualCategory(GeoDataPlacemark::Bookmark);
68 placemark->setZoomLevel( 1 );
69 }
70
71 }
72
BookmarkManager(GeoDataTreeModel * treeModel,QObject * parent)73 BookmarkManager::BookmarkManager( GeoDataTreeModel *treeModel, QObject *parent ) :
74 QObject( parent ),
75 d( new BookmarkManagerPrivate( treeModel ) )
76 {
77 }
78
~BookmarkManager()79 BookmarkManager::~BookmarkManager()
80 {
81 delete d;
82 }
83
bookmarkFile() const84 QString BookmarkManager::bookmarkFile() const
85 {
86 return MarbleDirs::path( d->m_bookmarkFileRelativePath );
87 }
88
loadFile(const QString & relativeFilePath)89 bool BookmarkManager::loadFile( const QString &relativeFilePath )
90 {
91 d->m_bookmarkFileRelativePath = relativeFilePath;
92 QString absoluteFilePath = bookmarkFile();
93
94 mDebug() << Q_FUNC_INFO << "Loading Bookmark File:" << absoluteFilePath;
95
96 if (absoluteFilePath.isEmpty())
97 return false;
98
99 if ( relativeFilePath.isNull() )
100 return false;
101
102 GeoDataDocument *document = openFile( absoluteFilePath );
103 bool recover = false;
104 if ( !document ) {
105 mDebug() << "Could not parse file" << absoluteFilePath;
106 mDebug() << "This could be caused by a previous broken bookmark file. Trying to recover.";
107 /** @todo: Remove this workaround and return false around Marble 1.4 */
108 recover = true;
109 // return false;
110 }
111
112 d->m_treeModel->removeDocument( d->m_bookmarkDocument );
113 delete d->m_bookmarkDocument;
114 d->m_bookmarkDocument = document;
115
116 if ( recover ) {
117 d->resetBookmarkDocument();
118 updateBookmarkFile();
119 } else {
120 Q_ASSERT( d->m_bookmarkDocument && "d->m_bookmarkDocument is 0 but must not be. Please report a bug at https://bugs.kde.org" );
121 d->m_treeModel->addDocument( d->m_bookmarkDocument );
122 }
123 ensureDefaultFolder();
124
125 emit bookmarksChanged();
126 return true;
127 }
128
addBookmark(GeoDataContainer * container,const GeoDataPlacemark & placemark)129 void BookmarkManager::addBookmark( GeoDataContainer *container, const GeoDataPlacemark &placemark )
130 {
131 GeoDataPlacemark *bookmark = new GeoDataPlacemark( placemark );
132 bookmark->setVisualCategory(GeoDataPlacemark::Bookmark);
133 bookmark->setZoomLevel( 1 );
134 if (bookmark->name().isEmpty()) {
135 bookmark->setName(bookmark->coordinate().toString(GeoDataCoordinates::Decimal).trimmed());
136 }
137 if (d->m_styleBuilder && bookmark->style()->iconStyle().iconPath().isEmpty()) {
138 StyleParameters style;
139 style.placemark = bookmark;
140 bookmark->setStyle(GeoDataStyle::Ptr(new GeoDataStyle(*d->m_styleBuilder->createStyle(style))));
141 }
142 d->m_treeModel->addFeature( container, bookmark );
143
144 updateBookmarkFile();
145 }
146
updateBookmark(GeoDataPlacemark * bookmark)147 void BookmarkManager::updateBookmark( GeoDataPlacemark *bookmark )
148 {
149 d->m_treeModel->updateFeature( bookmark );
150 }
151
removeBookmark(GeoDataPlacemark * bookmark)152 void BookmarkManager::removeBookmark( GeoDataPlacemark *bookmark )
153 {
154 d->m_treeModel->removeFeature( bookmark );
155 delete bookmark;
156 updateBookmarkFile();
157 }
158
bookmarkAt(GeoDataContainer * container,const GeoDataCoordinates & coordinate)159 GeoDataPlacemark* BookmarkManager::bookmarkAt(GeoDataContainer *container, const GeoDataCoordinates &coordinate)
160 {
161 for ( GeoDataFolder *folder: container->folderList() ) {
162 GeoDataPlacemark *placemark = bookmarkAt(folder, coordinate);
163 if ( placemark )
164 return placemark;
165 }
166
167 for ( GeoDataPlacemark *placemark: container->placemarkList() ) {
168 if ( placemark->coordinate() == coordinate )
169 return placemark;
170 }
171
172 return Q_NULLPTR;
173 }
174
document()175 GeoDataDocument * BookmarkManager::document()
176 {
177 return d->m_bookmarkDocument;
178 }
179
document() const180 const GeoDataDocument * BookmarkManager::document() const
181 {
182 return d->m_bookmarkDocument;
183 }
184
showBookmarks() const185 bool BookmarkManager::showBookmarks() const
186 {
187 return d->m_bookmarkDocument->isVisible();
188 }
189
setShowBookmarks(bool visible)190 void BookmarkManager::setShowBookmarks( bool visible )
191 {
192 d->m_bookmarkDocument->setVisible( visible );
193 d->m_treeModel->updateFeature( d->m_bookmarkDocument );
194 }
195
folders() const196 QVector<GeoDataFolder*> BookmarkManager::folders() const
197 {
198 return d->m_bookmarkDocument->folderList();
199 }
200
addNewBookmarkFolder(GeoDataContainer * container,const QString & name)201 GeoDataFolder* BookmarkManager::addNewBookmarkFolder( GeoDataContainer *container, const QString &name )
202 {
203 //If name is empty string
204 if ( name.isEmpty() ) {
205 mDebug() << "Folder with empty name is not acceptable, please give it another name" ;
206 return Q_NULLPTR;
207 }
208
209 //If folder with same name already exist
210 QVector<GeoDataFolder*> folderList = container->folderList();
211
212 QVector<GeoDataFolder*>::const_iterator i = folderList.constBegin();
213 QVector<GeoDataFolder*>::const_iterator end = folderList.constEnd();
214 for ( ; i != end; ++i ) {
215 if ( name == ( *i )->name() ) {
216 mDebug() << "Folder with same name already exist, please give it another name";
217 return *i;
218 }
219 }
220
221 GeoDataFolder *bookmarkFolder = new GeoDataFolder();
222 bookmarkFolder->setName( name );
223
224 d->m_treeModel->addFeature( container, bookmarkFolder );
225 updateBookmarkFile();
226
227 return bookmarkFolder;
228 }
229
renameBookmarkFolder(GeoDataFolder * folder,const QString & name)230 void BookmarkManager::renameBookmarkFolder( GeoDataFolder *folder, const QString &name )
231 {
232 folder->setName( name );
233 d->m_treeModel->updateFeature( folder );
234 }
235
removeBookmarkFolder(GeoDataFolder * folder)236 void BookmarkManager::removeBookmarkFolder( GeoDataFolder *folder )
237 {
238 d->m_treeModel->removeFeature( folder );
239 delete folder;
240 }
241
ensureDefaultFolder()242 void BookmarkManager::ensureDefaultFolder()
243 {
244 if ( d->m_bookmarkDocument->size() == 0 ) {
245 addNewBookmarkFolder( d->m_bookmarkDocument, tr("Default") );
246 }
247 }
248
removeAllBookmarks()249 void BookmarkManager::removeAllBookmarks()
250 {
251 d->resetBookmarkDocument();
252 updateBookmarkFile();
253 }
254
setStyleBuilder(const StyleBuilder * styleBuilder)255 void BookmarkManager::setStyleBuilder(const StyleBuilder *styleBuilder)
256 {
257 d->m_styleBuilder = styleBuilder;
258 }
259
updateBookmarkFile()260 bool BookmarkManager::updateBookmarkFile()
261 {
262 const QString absoluteLocalFilePath = MarbleDirs::localPath() + QLatin1Char('/') + d->m_bookmarkFileRelativePath;
263
264 if ( ! d->m_bookmarkFileRelativePath.isNull() ) {
265 QFile file( absoluteLocalFilePath );
266 if ( !file.exists() ) {
267 // Extracting directory of file : for bookmarks it will be MarbleDirs::localPath()+/bookmarks/
268 QFileInfo fileInfo( absoluteLocalFilePath );
269 QString directoryPath = fileInfo.path();
270
271 //Creating all directories, which doesn't exist
272 QDir directory( MarbleDirs::localPath() );
273 directory.mkpath( directoryPath );
274 }
275
276 if (!GeoDataDocumentWriter::write(absoluteLocalFilePath, *d->m_bookmarkDocument)) {
277 mDebug() << "Could not write the bookmarks file" << absoluteLocalFilePath;
278 file.close();
279 return false;
280 }
281 emit bookmarksChanged();
282 file.close();
283 return true;
284 }
285 return false;
286 }
287
openFile(const QString & fileName)288 GeoDataDocument* BookmarkManager::openFile( const QString &fileName )
289 {
290 GeoDataParser parser( GeoData_KML );
291 QFile file( fileName );
292
293 if ( !file.exists() ) {
294 return nullptr;
295 }
296
297 if ( !file.open( QIODevice::ReadOnly ) || !parser.read( &file ) ) {
298 mDebug() << "Could not open/parse file" << fileName;
299 return nullptr;
300 }
301
302 GeoDataDocument *result = dynamic_cast<GeoDataDocument*>( parser.releaseDocument() );
303 if ( !result ) {
304 return nullptr;
305 }
306
307 result->setDocumentRole( BookmarkDocument );
308 for( GeoDataFolder* folder: result->folderList() ) {
309 BookmarkManagerPrivate::setVisualCategory( folder );
310 }
311
312 return result;
313 }
314
315 }
316
317 #include "moc_BookmarkManager.cpp"
318