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 &timestamp )
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 &timestamp )
0211 {
0212     d->m_owncloudBackend.downloadRoute( timestamp );
0213 }
0214 
0215 void RouteSyncManager::openRoute(const QString &timestamp )
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 &timestamp )
0228 {
0229     d->m_owncloudBackend.deleteRoute( timestamp );
0230 }
0231 
0232 void RouteSyncManager::removeRouteFromCache( const QString &timestamp )
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"