File indexing completed on 2024-05-05 03:49:16
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2013 Utku Aydın <utkuaydin34@gmail.com> 0004 // 0005 0006 #include "RouteSyncManager.h" 0007 0008 #include "GeoDataParser.h" 0009 #include "MarbleDirs.h" 0010 #include "MarbleDebug.h" 0011 #include "GeoDataFolder.h" 0012 #include "GeoDataDocument.h" 0013 #include "GeoDataPlacemark.h" 0014 #include "CloudRouteModel.h" 0015 #include "CloudRoutesDialog.h" 0016 #include "CloudSyncManager.h" 0017 #include "OwncloudSyncBackend.h" 0018 #include "RouteItem.h" 0019 #include "RoutingManager.h" 0020 0021 #include <QDir> 0022 #include <QUrl> 0023 #include <QFile> 0024 #include <QIcon> 0025 #include <QPointer> 0026 0027 namespace Marble 0028 { 0029 0030 /** 0031 * Private class for RouteSyncManager. 0032 */ 0033 class Q_DECL_HIDDEN RouteSyncManager::Private { 0034 public: 0035 Private( CloudSyncManager *cloudSyncManager ); 0036 ~Private(); 0037 0038 bool m_routeSyncEnabled; 0039 CloudSyncManager *m_cloudSyncManager; 0040 RoutingManager *m_routingManager; 0041 CloudRouteModel *m_model; 0042 0043 QDir m_cacheDir; 0044 OwncloudSyncBackend m_owncloudBackend; 0045 QVector<RouteItem> m_routeList; 0046 }; 0047 0048 RouteSyncManager::Private::Private( CloudSyncManager *cloudSyncManager ) : 0049 m_routeSyncEnabled( false ), 0050 m_cloudSyncManager( cloudSyncManager ), 0051 m_routingManager( nullptr ), 0052 m_model( new CloudRouteModel() ), 0053 m_owncloudBackend( cloudSyncManager ) 0054 { 0055 m_cacheDir = QDir(MarbleDirs::localPath() + QLatin1String("/cloudsync/cache/routes/")); 0056 } 0057 0058 RouteSyncManager::Private::~Private() 0059 { 0060 delete m_model; 0061 } 0062 0063 RouteSyncManager::RouteSyncManager(CloudSyncManager *cloudSyncManager) : 0064 d( new Private( cloudSyncManager ) ) 0065 { 0066 connect( &d->m_owncloudBackend, SIGNAL(routeUploadProgress(qint64,qint64)), this, SLOT(updateUploadProgressbar(qint64,qint64)) ); 0067 connect( &d->m_owncloudBackend, SIGNAL(routeListDownloaded(QVector<RouteItem>)), this, SLOT(setRouteModelItems(QVector<RouteItem>)) ); 0068 connect( &d->m_owncloudBackend, SIGNAL(routeListDownloadProgress(qint64,qint64)), this, SIGNAL(routeListDownloadProgress(qint64,qint64)) ); 0069 connect( &d->m_owncloudBackend, SIGNAL(routeDownloadProgress(qint64,qint64)), d->m_model, SLOT(updateProgress(qint64,qint64)) ); 0070 connect( &d->m_owncloudBackend, SIGNAL(routeDownloaded()), this, SLOT(prepareRouteList()) ); 0071 connect( &d->m_owncloudBackend, SIGNAL(routeDeleted()), this, SLOT(prepareRouteList()) ); 0072 connect( &d->m_owncloudBackend, SIGNAL(removedFromCache(QString)), this, SLOT(prepareRouteList()) ); 0073 } 0074 0075 RouteSyncManager::~RouteSyncManager() 0076 { 0077 delete d; 0078 } 0079 0080 void RouteSyncManager::setRoutingManager(RoutingManager *routingManager) 0081 { 0082 d->m_routingManager = routingManager; 0083 } 0084 0085 bool RouteSyncManager::isRouteSyncEnabled() const 0086 { 0087 return d->m_routeSyncEnabled && d->m_cloudSyncManager && d->m_cloudSyncManager->isSyncEnabled(); 0088 } 0089 0090 void RouteSyncManager::setRouteSyncEnabled( bool enabled ) 0091 { 0092 if ( d->m_routeSyncEnabled != enabled ) { 0093 d->m_routeSyncEnabled = enabled; 0094 emit routeSyncEnabledChanged( d->m_routeSyncEnabled ); 0095 } 0096 } 0097 0098 CloudRouteModel* RouteSyncManager::model() 0099 { 0100 return d->m_model; 0101 } 0102 0103 QString RouteSyncManager::generateTimestamp() const 0104 { 0105 qint64 timestamp = QDateTime::currentMSecsSinceEpoch(); 0106 return QString::number( timestamp ); 0107 } 0108 0109 QString RouteSyncManager::saveDisplayedToCache() const 0110 { 0111 if ( !d->m_routingManager ) { 0112 qWarning() << "RoutingManager instance not set in RouteSyncManager. Cannot save current route."; 0113 return QString(); 0114 } 0115 0116 d->m_cacheDir.mkpath( d->m_cacheDir.absolutePath() ); 0117 0118 const QString timestamp = generateTimestamp(); 0119 const QString filename = d->m_cacheDir.absolutePath() + QLatin1Char('/') + timestamp + QLatin1String(".kml"); 0120 d->m_routingManager->saveRoute( filename ); 0121 return timestamp; 0122 } 0123 0124 void RouteSyncManager::uploadRoute() 0125 { 0126 if( !d->m_cloudSyncManager->workOffline() ) { 0127 d->m_owncloudBackend.uploadRoute( saveDisplayedToCache() ); 0128 } 0129 } 0130 0131 QVector<RouteItem> RouteSyncManager::cachedRouteList() const 0132 { 0133 QVector<RouteItem> routeList; 0134 QStringList cachedRoutes = d->m_cacheDir.entryList( QStringList() << "*.kml", QDir::Files ); 0135 for ( const QString &routeFilename: cachedRoutes ) { 0136 QFile file(d->m_cacheDir.absolutePath() + QLatin1Char('/') + routeFilename); 0137 file.open( QFile::ReadOnly ); 0138 0139 GeoDataParser parser( GeoData_KML ); 0140 if( !parser.read( &file ) ) { 0141 mDebug() << QLatin1String("Could not read ") + routeFilename; 0142 } 0143 0144 file.close(); 0145 0146 QString routeName; 0147 GeoDocument *geoDoc = parser.releaseDocument(); 0148 GeoDataDocument *container = dynamic_cast<GeoDataDocument*>( geoDoc ); 0149 if ( container && container->size() > 0 ) { 0150 GeoDataFolder *folder = container->folderList().at( 0 ); 0151 for ( GeoDataPlacemark *placemark: folder->placemarkList() ) { 0152 routeName += placemark->name() + QLatin1String(" - "); 0153 } 0154 } 0155 0156 routeName = routeName.left( routeName.length() - 3 ); 0157 QString timestamp = routeFilename.left( routeFilename.length() - 4 ); 0158 QString distance(QLatin1Char('0')); 0159 QString duration(QLatin1Char('0')); 0160 0161 QString previewPath = QString( "%0/preview/%1.jpg" ).arg( d->m_cacheDir.absolutePath(), timestamp ); 0162 QIcon preview; 0163 0164 if( QFile( previewPath ).exists() ) { 0165 preview = QIcon( previewPath ); 0166 } 0167 0168 // Would that work on Windows? 0169 QUrl previewUrl( QString( "file://%0" ).arg( previewPath ) ); 0170 0171 RouteItem item; 0172 item.setIdentifier( timestamp ); 0173 item.setName( routeName ); 0174 item.setDistance( distance ); 0175 item.setDistance( duration ); 0176 item.setPreview( preview ); 0177 item.setPreviewUrl( previewUrl ); 0178 item.setOnCloud( false ); 0179 routeList.append( item ); 0180 } 0181 0182 return routeList; 0183 } 0184 0185 void RouteSyncManager::uploadRoute( const QString ×tamp ) 0186 { 0187 if( !d->m_cloudSyncManager->workOffline() ) { 0188 d->m_owncloudBackend.uploadRoute( timestamp ); 0189 } 0190 } 0191 0192 void RouteSyncManager::prepareRouteList() 0193 { 0194 d->m_routeList.clear(); 0195 0196 QVector<RouteItem> cachedRoutes = cachedRouteList(); 0197 for( const RouteItem &item: cachedRoutes ) { 0198 d->m_routeList.append( item ); 0199 } 0200 0201 if( !d->m_cloudSyncManager->workOffline() ) { 0202 d->m_owncloudBackend.downloadRouteList(); 0203 } else { 0204 // If not offline, setRouteModelItems() does this after 0205 // appending downloaded items to the list. 0206 d->m_model->setItems( d->m_routeList ); 0207 } 0208 } 0209 0210 void RouteSyncManager::downloadRoute( const QString ×tamp ) 0211 { 0212 d->m_owncloudBackend.downloadRoute( timestamp ); 0213 } 0214 0215 void RouteSyncManager::openRoute(const QString ×tamp ) 0216 { 0217 if ( !d->m_routingManager ) { 0218 qWarning() << "RoutingManager instance not set in RouteSyncManager. Cannot open route " << timestamp; 0219 return; 0220 } 0221 0222 d->m_routingManager->loadRoute( QString( "%0/%1.kml" ) 0223 .arg( d->m_cacheDir.absolutePath() ) 0224 .arg( timestamp ) ); 0225 } 0226 0227 void RouteSyncManager::deleteRoute(const QString ×tamp ) 0228 { 0229 d->m_owncloudBackend.deleteRoute( timestamp ); 0230 } 0231 0232 void RouteSyncManager::removeRouteFromCache( const QString ×tamp ) 0233 { 0234 d->m_owncloudBackend.removeFromCache( d->m_cacheDir, timestamp ); 0235 } 0236 0237 void RouteSyncManager::updateUploadProgressbar( qint64 sent, qint64 total ) 0238 { 0239 emit routeUploadProgress( sent, total ); 0240 if( sent == total ) { 0241 prepareRouteList(); 0242 } 0243 } 0244 0245 void RouteSyncManager::setRouteModelItems( const QVector<RouteItem> &routeList ) 0246 { 0247 if( d->m_routeList.count() > 0 ) { 0248 QStringList cloudRoutes; 0249 for( const RouteItem &item: routeList ) { 0250 cloudRoutes.append( item.identifier() ); 0251 } 0252 0253 for( int position = 0; position < d->m_routeList.count(); position++ ) { 0254 if( cloudRoutes.contains( d->m_routeList.at( position ).identifier() ) ) { 0255 d->m_routeList[ position ].setOnCloud( true ); 0256 } 0257 } 0258 0259 QStringList cachedRoutes; 0260 for( const RouteItem &item: d->m_routeList ) { 0261 cachedRoutes.append( item.identifier() ); 0262 } 0263 0264 for( const RouteItem &item: routeList ) { 0265 if( !cachedRoutes.contains( item.identifier() ) ) { 0266 d->m_routeList.append( item ); 0267 } 0268 } 0269 } else { 0270 for( const RouteItem &item: routeList ) { 0271 d->m_routeList.append( item ); 0272 } 0273 } 0274 0275 d->m_model->setItems( d->m_routeList ); 0276 } 0277 0278 } 0279 0280 #include "moc_RouteSyncManager.cpp"