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 "GeoDataParser.h"
9 #include "MarbleDirs.h"
10 #include "MarbleDebug.h"
11 #include "GeoDataFolder.h"
12 #include "GeoDataDocument.h"
13 #include "GeoDataPlacemark.h"
14 #include "CloudRouteModel.h"
15 #include "CloudRoutesDialog.h"
16 #include "CloudSyncManager.h"
17 #include "OwncloudSyncBackend.h"
18 #include "RouteItem.h"
19 #include "RoutingManager.h"
20
21 #include <QDir>
22 #include <QUrl>
23 #include <QFile>
24 #include <QIcon>
25 #include <QPointer>
26
27 namespace Marble
28 {
29
30 /**
31 * Private class for RouteSyncManager.
32 */
33 class Q_DECL_HIDDEN RouteSyncManager::Private {
34 public:
35 Private( CloudSyncManager *cloudSyncManager );
36 ~Private();
37
38 bool m_routeSyncEnabled;
39 CloudSyncManager *m_cloudSyncManager;
40 RoutingManager *m_routingManager;
41 CloudRouteModel *m_model;
42
43 QDir m_cacheDir;
44 OwncloudSyncBackend m_owncloudBackend;
45 QVector<RouteItem> m_routeList;
46 };
47
Private(CloudSyncManager * cloudSyncManager)48 RouteSyncManager::Private::Private( CloudSyncManager *cloudSyncManager ) :
49 m_routeSyncEnabled( false ),
50 m_cloudSyncManager( cloudSyncManager ),
51 m_routingManager( nullptr ),
52 m_model( new CloudRouteModel() ),
53 m_owncloudBackend( cloudSyncManager )
54 {
55 m_cacheDir = QDir(MarbleDirs::localPath() + QLatin1String("/cloudsync/cache/routes/"));
56 }
57
~Private()58 RouteSyncManager::Private::~Private()
59 {
60 delete m_model;
61 }
62
RouteSyncManager(CloudSyncManager * cloudSyncManager)63 RouteSyncManager::RouteSyncManager(CloudSyncManager *cloudSyncManager) :
64 d( new Private( cloudSyncManager ) )
65 {
66 connect( &d->m_owncloudBackend, SIGNAL(routeUploadProgress(qint64,qint64)), this, SLOT(updateUploadProgressbar(qint64,qint64)) );
67 connect( &d->m_owncloudBackend, SIGNAL(routeListDownloaded(QVector<RouteItem>)), this, SLOT(setRouteModelItems(QVector<RouteItem>)) );
68 connect( &d->m_owncloudBackend, SIGNAL(routeListDownloadProgress(qint64,qint64)), this, SIGNAL(routeListDownloadProgress(qint64,qint64)) );
69 connect( &d->m_owncloudBackend, SIGNAL(routeDownloadProgress(qint64,qint64)), d->m_model, SLOT(updateProgress(qint64,qint64)) );
70 connect( &d->m_owncloudBackend, SIGNAL(routeDownloaded()), this, SLOT(prepareRouteList()) );
71 connect( &d->m_owncloudBackend, SIGNAL(routeDeleted()), this, SLOT(prepareRouteList()) );
72 connect( &d->m_owncloudBackend, SIGNAL(removedFromCache(QString)), this, SLOT(prepareRouteList()) );
73 }
74
~RouteSyncManager()75 RouteSyncManager::~RouteSyncManager()
76 {
77 delete d;
78 }
79
setRoutingManager(RoutingManager * routingManager)80 void RouteSyncManager::setRoutingManager(RoutingManager *routingManager)
81 {
82 d->m_routingManager = routingManager;
83 }
84
isRouteSyncEnabled() const85 bool RouteSyncManager::isRouteSyncEnabled() const
86 {
87 return d->m_routeSyncEnabled && d->m_cloudSyncManager && d->m_cloudSyncManager->isSyncEnabled();
88 }
89
setRouteSyncEnabled(bool enabled)90 void RouteSyncManager::setRouteSyncEnabled( bool enabled )
91 {
92 if ( d->m_routeSyncEnabled != enabled ) {
93 d->m_routeSyncEnabled = enabled;
94 emit routeSyncEnabledChanged( d->m_routeSyncEnabled );
95 }
96 }
97
model()98 CloudRouteModel* RouteSyncManager::model()
99 {
100 return d->m_model;
101 }
102
generateTimestamp() const103 QString RouteSyncManager::generateTimestamp() const
104 {
105 qint64 timestamp = QDateTime::currentMSecsSinceEpoch();
106 return QString::number( timestamp );
107 }
108
saveDisplayedToCache() const109 QString RouteSyncManager::saveDisplayedToCache() const
110 {
111 if ( !d->m_routingManager ) {
112 qWarning() << "RoutingManager instance not set in RouteSyncManager. Cannot save current route.";
113 return QString();
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 + QLatin1String(".kml");
120 d->m_routingManager->saveRoute( filename );
121 return timestamp;
122 }
123
uploadRoute()124 void RouteSyncManager::uploadRoute()
125 {
126 if( !d->m_cloudSyncManager->workOffline() ) {
127 d->m_owncloudBackend.uploadRoute( saveDisplayedToCache() );
128 }
129 }
130
cachedRouteList() const131 QVector<RouteItem> RouteSyncManager::cachedRouteList() const
132 {
133 QVector<RouteItem> routeList;
134 QStringList cachedRoutes = d->m_cacheDir.entryList( QStringList() << "*.kml", QDir::Files );
135 for ( const QString &routeFilename: 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() << QLatin1String("Could not read ") + routeFilename;
142 }
143
144 file.close();
145
146 QString routeName;
147 GeoDocument *geoDoc = parser.releaseDocument();
148 GeoDataDocument *container = dynamic_cast<GeoDataDocument*>( geoDoc );
149 if ( container && container->size() > 0 ) {
150 GeoDataFolder *folder = container->folderList().at( 0 );
151 for ( GeoDataPlacemark *placemark: folder->placemarkList() ) {
152 routeName += placemark->name() + QLatin1String(" - ");
153 }
154 }
155
156 routeName = routeName.left( routeName.length() - 3 );
157 QString timestamp = routeFilename.left( routeFilename.length() - 4 );
158 QString distance(QLatin1Char('0'));
159 QString duration(QLatin1Char('0'));
160
161 QString previewPath = QString( "%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( QString( "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
uploadRoute(const QString & timestamp)185 void RouteSyncManager::uploadRoute( const QString ×tamp )
186 {
187 if( !d->m_cloudSyncManager->workOffline() ) {
188 d->m_owncloudBackend.uploadRoute( timestamp );
189 }
190 }
191
prepareRouteList()192 void RouteSyncManager::prepareRouteList()
193 {
194 d->m_routeList.clear();
195
196 QVector<RouteItem> cachedRoutes = cachedRouteList();
197 for( const RouteItem &item: 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
downloadRoute(const QString & timestamp)210 void RouteSyncManager::downloadRoute( const QString ×tamp )
211 {
212 d->m_owncloudBackend.downloadRoute( timestamp );
213 }
214
openRoute(const QString & timestamp)215 void RouteSyncManager::openRoute(const QString ×tamp )
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( QString( "%0/%1.kml" )
223 .arg( d->m_cacheDir.absolutePath() )
224 .arg( timestamp ) );
225 }
226
deleteRoute(const QString & timestamp)227 void RouteSyncManager::deleteRoute(const QString ×tamp )
228 {
229 d->m_owncloudBackend.deleteRoute( timestamp );
230 }
231
removeRouteFromCache(const QString & timestamp)232 void RouteSyncManager::removeRouteFromCache( const QString ×tamp )
233 {
234 d->m_owncloudBackend.removeFromCache( d->m_cacheDir, timestamp );
235 }
236
updateUploadProgressbar(qint64 sent,qint64 total)237 void RouteSyncManager::updateUploadProgressbar( qint64 sent, qint64 total )
238 {
239 emit routeUploadProgress( sent, total );
240 if( sent == total ) {
241 prepareRouteList();
242 }
243 }
244
setRouteModelItems(const QVector<RouteItem> & routeList)245 void RouteSyncManager::setRouteModelItems( const QVector<RouteItem> &routeList )
246 {
247 if( d->m_routeList.count() > 0 ) {
248 QStringList cloudRoutes;
249 for( const RouteItem &item: routeList ) {
250 cloudRoutes.append( item.identifier() );
251 }
252
253 for( int position = 0; position < d->m_routeList.count(); position++ ) {
254 if( cloudRoutes.contains( d->m_routeList.at( position ).identifier() ) ) {
255 d->m_routeList[ position ].setOnCloud( true );
256 }
257 }
258
259 QStringList cachedRoutes;
260 for( const RouteItem &item: d->m_routeList ) {
261 cachedRoutes.append( item.identifier() );
262 }
263
264 for( const RouteItem &item: routeList ) {
265 if( !cachedRoutes.contains( item.identifier() ) ) {
266 d->m_routeList.append( item );
267 }
268 }
269 } else {
270 for( const RouteItem &item: routeList ) {
271 d->m_routeList.append( item );
272 }
273 }
274
275 d->m_model->setItems( d->m_routeList );
276 }
277
278 }
279
280 #include "moc_RouteSyncManager.cpp"
281