Marble

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

KDE's Doxygen guidelines are available online.