Marble

RouteSyncManager.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2013 Utku Aydın <utkuaydin34@gmail.com>
4//
5
6#include "RouteSyncManager.h"
7
8#include "CloudRouteModel.h"
9#include "CloudRoutesDialog.h"
10#include "CloudSyncManager.h"
11#include "GeoDataDocument.h"
12#include "GeoDataFolder.h"
13#include "GeoDataParser.h"
14#include "GeoDataPlacemark.h"
15#include "MarbleDebug.h"
16#include "MarbleDirs.h"
17#include "OwncloudSyncBackend.h"
18#include "RouteItem.h"
19#include "RoutingManager.h"
20
21#include <QDir>
22#include <QFile>
23#include <QIcon>
24#include <QPointer>
25#include <QUrl>
26
27namespace Marble
28{
29
30/**
31 * Private class for RouteSyncManager.
32 */
33class Q_DECL_HIDDEN RouteSyncManager::Private
34{
35public:
36 Private(CloudSyncManager *cloudSyncManager);
37 ~Private();
38
39 bool m_routeSyncEnabled;
40 CloudSyncManager *const m_cloudSyncManager;
41 RoutingManager *m_routingManager = nullptr;
42 CloudRouteModel *const m_model;
43
44 QDir m_cacheDir;
45 OwncloudSyncBackend m_owncloudBackend;
46 QList<RouteItem> m_routeList;
47};
48
49RouteSyncManager::Private::Private(CloudSyncManager *cloudSyncManager)
50 : m_routeSyncEnabled(false)
51 , m_cloudSyncManager(cloudSyncManager)
52 , m_model(new CloudRouteModel())
53 , m_owncloudBackend(cloudSyncManager)
54{
55 m_cacheDir = QDir(MarbleDirs::localPath() + QLatin1StringView("/cloudsync/cache/routes/"));
56}
57
58RouteSyncManager::Private::~Private()
59{
60 delete m_model;
61}
62
63RouteSyncManager::RouteSyncManager(CloudSyncManager *cloudSyncManager)
64 : d(new Private(cloudSyncManager))
65{
66 connect(&d->m_owncloudBackend, &OwncloudSyncBackend::routeUploadProgress, this, &RouteSyncManager::updateUploadProgressbar);
67 connect(&d->m_owncloudBackend, &OwncloudSyncBackend::routeListDownloaded, this, &RouteSyncManager::setRouteModelItems);
68 connect(&d->m_owncloudBackend, &OwncloudSyncBackend::routeListDownloadProgress, this, &RouteSyncManager::routeListDownloadProgress);
69 connect(&d->m_owncloudBackend, &OwncloudSyncBackend::routeDownloadProgress, d->m_model, &CloudRouteModel::updateProgress);
70 connect(&d->m_owncloudBackend, &OwncloudSyncBackend::routeDownloaded, this, &RouteSyncManager::prepareRouteList);
71 connect(&d->m_owncloudBackend, &OwncloudSyncBackend::routeDeleted, this, &RouteSyncManager::prepareRouteList);
72 connect(&d->m_owncloudBackend, &OwncloudSyncBackend::removedFromCache, this, &RouteSyncManager::prepareRouteList);
73}
74
75RouteSyncManager::~RouteSyncManager()
76{
77 delete d;
78}
79
80void RouteSyncManager::setRoutingManager(RoutingManager *routingManager)
81{
82 d->m_routingManager = routingManager;
83}
84
85bool RouteSyncManager::isRouteSyncEnabled() const
86{
87 return d->m_routeSyncEnabled && d->m_cloudSyncManager && d->m_cloudSyncManager->isSyncEnabled();
88}
89
90void RouteSyncManager::setRouteSyncEnabled(bool enabled)
91{
92 if (d->m_routeSyncEnabled != enabled) {
93 d->m_routeSyncEnabled = enabled;
94 Q_EMIT routeSyncEnabledChanged(d->m_routeSyncEnabled);
95 }
96}
97
98CloudRouteModel *RouteSyncManager::model()
99{
100 return d->m_model;
101}
102
103QString RouteSyncManager::generateTimestamp() const
104{
105 qint64 timestamp = QDateTime::currentMSecsSinceEpoch();
106 return QString::number(timestamp);
107}
108
109QString RouteSyncManager::saveDisplayedToCache() const
110{
111 if (!d->m_routingManager) {
112 qWarning() << "RoutingManager instance not set in RouteSyncManager. Cannot save current route.";
113 return {};
114 }
115
116 d->m_cacheDir.mkpath(d->m_cacheDir.absolutePath());
117
118 const QString timestamp = generateTimestamp();
119 const QString filename = d->m_cacheDir.absolutePath() + QLatin1Char('/') + timestamp + QLatin1StringView(".kml");
120 d->m_routingManager->saveRoute(filename);
121 return timestamp;
122}
123
124void RouteSyncManager::uploadRoute()
125{
126 if (!d->m_cloudSyncManager->workOffline()) {
127 d->m_owncloudBackend.uploadRoute(saveDisplayedToCache());
128 }
129}
130
131QList<RouteItem> RouteSyncManager::cachedRouteList() const
132{
133 QList<RouteItem> routeList;
134 QStringList cachedRoutes = d->m_cacheDir.entryList(QStringList() << QStringLiteral("*.kml"), QDir::Files);
135 for (const QString &routeFilename : std::as_const(cachedRoutes)) {
136 QFile file(d->m_cacheDir.absolutePath() + QLatin1Char('/') + routeFilename);
137 file.open(QFile::ReadOnly);
138
139 GeoDataParser parser(GeoData_KML);
140 if (!parser.read(&file)) {
141 mDebug() << QLatin1StringView("Could not read ") + routeFilename;
142 }
143
144 file.close();
145
146 QString routeName;
147 GeoDocument *geoDoc = parser.releaseDocument();
148 auto container = dynamic_cast<GeoDataDocument *>(geoDoc);
149 if (container && !container->isEmpty()) {
150 GeoDataFolder *folder = container->folderList().at(0);
151 for (GeoDataPlacemark *placemark : folder->placemarkList()) {
152 routeName += placemark->name() + QLatin1StringView(" - ");
153 }
154 }
155
156 routeName = routeName.left(routeName.length() - 3);
157 QString timestamp = routeFilename.left(routeFilename.length() - 4);
159 QString duration(QLatin1Char('0'));
160
161 QString previewPath = QStringLiteral("%0/preview/%1.jpg").arg(d->m_cacheDir.absolutePath(), timestamp);
162 QIcon preview;
163
164 if (QFile(previewPath).exists()) {
165 preview = QIcon(previewPath);
166 }
167
168 // Would that work on Windows?
169 QUrl previewUrl(QStringLiteral("file://%0").arg(previewPath));
170
171 RouteItem item;
172 item.setIdentifier(timestamp);
173 item.setName(routeName);
174 item.setDistance(distance);
175 item.setDistance(duration);
176 item.setPreview(preview);
177 item.setPreviewUrl(previewUrl);
178 item.setOnCloud(false);
179 routeList.append(item);
180 }
181
182 return routeList;
183}
184
185void RouteSyncManager::uploadRoute(const QString &timestamp)
186{
187 if (!d->m_cloudSyncManager->workOffline()) {
188 d->m_owncloudBackend.uploadRoute(timestamp);
189 }
190}
191
192void RouteSyncManager::prepareRouteList()
193{
194 d->m_routeList.clear();
195
196 QList<RouteItem> cachedRoutes = cachedRouteList();
197 for (const RouteItem &item : std::as_const(cachedRoutes)) {
198 d->m_routeList.append(item);
199 }
200
201 if (!d->m_cloudSyncManager->workOffline()) {
202 d->m_owncloudBackend.downloadRouteList();
203 } else {
204 // If not offline, setRouteModelItems() does this after
205 // appending downloaded items to the list.
206 d->m_model->setItems(d->m_routeList);
207 }
208}
209
210void RouteSyncManager::downloadRoute(const QString &timestamp)
211{
212 d->m_owncloudBackend.downloadRoute(timestamp);
213}
214
215void RouteSyncManager::openRoute(const QString &timestamp)
216{
217 if (!d->m_routingManager) {
218 qWarning() << "RoutingManager instance not set in RouteSyncManager. Cannot open route " << timestamp;
219 return;
220 }
221
222 d->m_routingManager->loadRoute(QStringLiteral("%0/%1.kml").arg(d->m_cacheDir.absolutePath()).arg(timestamp));
223}
224
225void RouteSyncManager::deleteRoute(const QString &timestamp)
226{
227 d->m_owncloudBackend.deleteRoute(timestamp);
228}
229
230void RouteSyncManager::removeRouteFromCache(const QString &timestamp)
231{
232 d->m_owncloudBackend.removeFromCache(d->m_cacheDir, timestamp);
233}
234
235void RouteSyncManager::updateUploadProgressbar(qint64 sent, qint64 total)
236{
237 Q_EMIT routeUploadProgress(sent, total);
238 if (sent == total) {
239 prepareRouteList();
240 }
241}
242
243void RouteSyncManager::setRouteModelItems(const QList<RouteItem> &routeList)
244{
245 if (d->m_routeList.count() > 0) {
246 QStringList cloudRoutes;
247 for (const RouteItem &item : routeList) {
248 cloudRoutes.append(item.identifier());
249 }
250
251 for (int position = 0; position < d->m_routeList.count(); position++) {
252 if (cloudRoutes.contains(d->m_routeList.at(position).identifier())) {
253 d->m_routeList[position].setOnCloud(true);
254 }
255 }
256
257 QStringList cachedRoutes;
258 for (const RouteItem &item : std::as_const(d->m_routeList)) {
259 cachedRoutes.append(item.identifier());
260 }
261
262 for (const RouteItem &item : routeList) {
263 if (!cachedRoutes.contains(item.identifier())) {
264 d->m_routeList.append(item);
265 }
266 }
267 } else {
268 for (const RouteItem &item : routeList) {
269 d->m_routeList.append(item);
270 }
271 }
272
273 d->m_model->setItems(d->m_routeList);
274}
275
276}
277
278#include "moc_RouteSyncManager.cpp"
Binds a QML item to a specific geodetic location in screen coordinates.
KOSM_EXPORT double distance(const std::vector< const OSM::Node * > &path, Coordinate coord)
qint64 currentMSecsSinceEpoch()
void append(QList< T > &&value)
void clear()
QString arg(Args &&... args) const const
QString left(qsizetype n) const const
qsizetype length() const const
QString number(double n, char format, int precision)
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 4 2024 16:37:02 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.