• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeedu API Reference
  • KDE Home
  • Contact Us
 

marble

  • sources
  • kde-4.14
  • kdeedu
  • marble
  • src
  • lib
  • marble
  • cloudsync
BookmarkSyncManager.cpp
Go to the documentation of this file.
1 //
2 // This file is part of the Marble Virtual Globe.
3 //
4 // This program is free software licensed under the GNU LGPL. You can
5 // find a copy of this license in LICENSE.txt in the top directory of
6 // the source code.
7 //
8 // Copyright 2013 Utku Aydın <utkuaydin34@gmail.com>
9 //
10 
11 #include "BookmarkSyncManager.h"
12 
13 #include "GeoWriter.h"
14 #include "MarbleMath.h"
15 #include "MarbleDirs.h"
16 #include "MarbleDebug.h"
17 #include "GeoDataParser.h"
18 #include "GeoDataFolder.h"
19 #include "GeoDataDocument.h"
20 #include "CloudSyncManager.h"
21 #include "GeoDataCoordinates.h"
22 #include "OwncloudSyncBackend.h"
23 #include "MarbleModel.h"
24 #include "BookmarkManager.h"
25 
26 #include <QFile>
27 #include <QBuffer>
28 #include <QScriptValue>
29 #include <QScriptEngine>
30 #include <QTemporaryFile>
31 #include <QNetworkAccessManager>
32 #include <QTimer>
33 
34 namespace Marble {
35 
36 class DiffItem
37 {
38 public:
39  enum Action {
40  NoAction,
41  Created,
42  Changed,
43  Deleted
44  };
45 
46  enum Status {
47  Source,
48  Destination
49  };
50 
51  QString m_path;
52  Action m_action;
53  Status m_origin;
54  GeoDataPlacemark m_placemarkA;
55  GeoDataPlacemark m_placemarkB;
56 };
57 
58 class BookmarkSyncManager::Private
59 {
60 public:
61  Private( BookmarkSyncManager* parent, CloudSyncManager *cloudSyncManager );
62 
63  BookmarkSyncManager* m_q;
64  CloudSyncManager *m_cloudSyncManager;
65 
66  QNetworkAccessManager m_network;
67  QString m_uploadEndpoint;
68  QString m_downloadEndpoint;
69  QString m_timestampEndpoint;
70 
71  QNetworkReply* m_uploadReply;
72  QNetworkReply* m_downloadReply;
73  QNetworkReply* m_timestampReply;
74 
75  QString m_cloudTimestamp;
76 
77  QString m_cachePath;
78  QString m_localBookmarksPath;
79  QString m_bookmarksTimestamp;
80 
81  QList<DiffItem> m_diffA;
82  QList<DiffItem> m_diffB;
83  QList<DiffItem> m_merged;
84  DiffItem m_conflictItem;
85 
86  BookmarkManager* m_bookmarkManager;
87  QTimer m_syncTimer;
88  bool m_bookmarkSyncEnabled;
89 
95  QUrl endpointUrl( const QString &endpoint ) const;
96 
100  void uploadBookmarks();
101 
105  void downloadBookmarks();
106 
110  void downloadTimestamp();
111 
116  bool cloudBookmarksModified( const QString &cloudTimestamp ) const;
117 
122  void clearCache();
123 
128  QString lastSyncedKmlPath() const;
129 
137  QList<DiffItem> getPlacemarks(GeoDataDocument *document, GeoDataDocument *other, DiffItem::Status diffDirection );
138 
147  QList<DiffItem> getPlacemarks( GeoDataFolder *folder, QString &path, GeoDataDocument *other, DiffItem::Status diffDirection );
148 
155  const GeoDataPlacemark* findPlacemark( GeoDataContainer* container, const GeoDataPlacemark &bookmark ) const;
156 
163  void determineDiffStatus( DiffItem &item, GeoDataDocument* document ) const;
164 
171  QList<DiffItem> diff( QString &sourcePath, QString &destinationPath );
172  QList<DiffItem> diff( QString &sourcePath, QIODevice* destination );
173  QList<DiffItem> diff( QIODevice* source, QString &destinationPath );
174  QList<DiffItem> diff( QIODevice *source, QIODevice* destination );
175 
182  void merge();
183 
190  GeoDataFolder* createFolders( GeoDataContainer *container, QStringList &pathList );
191 
197  GeoDataDocument* constructDocument( const QList<DiffItem> &mergedList );
198 
199  void saveDownloadedToCache( const QByteArray &kml );
200 
201  void parseTimestamp();
202  void copyLocalToCache();
203 
204  void continueSynchronization();
205  void completeSynchronization();
206  void completeMerge();
207  void completeUpload();
208 };
209 
210 BookmarkSyncManager::Private::Private(BookmarkSyncManager *parent, CloudSyncManager *cloudSyncManager ) :
211  m_q( parent ),
212  m_cloudSyncManager( cloudSyncManager ),
213  m_bookmarkManager( 0 ),
214  m_bookmarkSyncEnabled( false )
215 {
216  m_cachePath = QString( "%0/cloudsync/cache/bookmarks" ).arg( MarbleDirs::localPath() );
217  m_localBookmarksPath = QString( "%0/bookmarks/bookmarks.kml" ).arg( MarbleDirs::localPath() );
218  m_downloadEndpoint = "bookmarks/kml";
219  m_uploadEndpoint = "bookmarks/update";
220  m_timestampEndpoint = "bookmarks/timestamp";
221 }
222 
223 BookmarkSyncManager::BookmarkSyncManager( CloudSyncManager *cloudSyncManager ) :
224  QObject(),
225  d( new Private( this, cloudSyncManager ) )
226 {
227  d->m_syncTimer.setInterval( 60 * 60 * 1000 ); // 1 hour. TODO: Make this configurable.
228  connect( &d->m_syncTimer, SIGNAL(timeout()), this, SLOT(startBookmarkSync()) );
229 }
230 
231 BookmarkSyncManager::~BookmarkSyncManager()
232 {
233  delete d;
234 }
235 
236 QDateTime BookmarkSyncManager::lastSync() const
237 {
238  const QString last = d->lastSyncedKmlPath();
239  if (last.isEmpty())
240  return QDateTime();
241  return QFileInfo(last).created();
242 }
243 
244 bool BookmarkSyncManager::isBookmarkSyncEnabled() const
245 {
246  return d->m_bookmarkSyncEnabled;
247 }
248 
249 void BookmarkSyncManager::setBookmarkSyncEnabled( bool enabled )
250 {
251  bool const old_state = isBookmarkSyncEnabled();
252  d->m_bookmarkSyncEnabled = enabled;
253  if ( old_state != isBookmarkSyncEnabled() ) {
254  emit bookmarkSyncEnabledChanged( d->m_bookmarkSyncEnabled );
255  if ( isBookmarkSyncEnabled() ) {
256  startBookmarkSync();
257  }
258  }
259 }
260 
261 void BookmarkSyncManager::setBookmarkManager(BookmarkManager *manager)
262 {
263  d->m_bookmarkManager = manager;
264  connect( manager, SIGNAL(bookmarksChanged()), this, SLOT(startBookmarkSync()) );
265  startBookmarkSync();
266 }
267 
268 void BookmarkSyncManager::startBookmarkSync()
269 {
270  if ( !isBookmarkSyncEnabled() )
271  {
272  return;
273  }
274 
275  d->m_syncTimer.start();
276  d->downloadTimestamp();
277 }
278 
279 QUrl BookmarkSyncManager::Private::endpointUrl( const QString &endpoint ) const
280 {
281  return QUrl( QString( "%0/%1" ).arg( m_cloudSyncManager->apiUrl().toString() ).arg( endpoint ) );
282 }
283 
284 void BookmarkSyncManager::Private::uploadBookmarks()
285 {
286  QByteArray data;
287  QByteArray lineBreak = "\r\n";
288  QString word = "----MarbleCloudBoundary";
289  QString boundary = QString( "--%0" ).arg( word );
290  QNetworkRequest request( endpointUrl( m_uploadEndpoint ) );
291  request.setHeader( QNetworkRequest::ContentTypeHeader, QString( "multipart/form-data; boundary=%0" ).arg( word ) );
292 
293  data.append( QString( boundary + lineBreak ).toUtf8() );
294  data.append( "Content-Disposition: form-data; name=\"bookmarks\"; filename=\"bookmarks.kml\"" + lineBreak );
295  data.append( "Content-Type: application/vnd.google-earth.kml+xml" + lineBreak + lineBreak );
296 
297  QFile bookmarksFile( m_localBookmarksPath );
298  if( !bookmarksFile.open( QFile::ReadOnly ) ) {
299  mDebug() << "Failed to open file" << bookmarksFile.fileName()
300  << ". It is either missing or not readable.";
301  return;
302  }
303 
304  QByteArray kmlContent = bookmarksFile.readAll();
305  data.append( kmlContent + lineBreak + lineBreak );
306  data.append( QString( boundary ).toUtf8() );
307  bookmarksFile.close();
308 
309  m_uploadReply = m_network.post( request, data );
310  connect( m_uploadReply, SIGNAL(uploadProgress(qint64,qint64)),
311  m_q, SIGNAL(uploadProgress(qint64,qint64)) );
312  connect( m_uploadReply, SIGNAL(finished()),
313  m_q, SLOT(completeUpload()) );
314 }
315 
316 void BookmarkSyncManager::Private::downloadBookmarks()
317 {
318  QNetworkRequest request( endpointUrl( m_downloadEndpoint ) );
319  m_downloadReply = m_network.get( request );
320  connect( m_downloadReply, SIGNAL(finished()),
321  m_q, SLOT(completeSynchronization()) );
322  connect( m_downloadReply, SIGNAL(downloadProgress(qint64,qint64)),
323  m_q, SIGNAL(downloadProgress(qint64,qint64)) );
324 }
325 
326 void BookmarkSyncManager::Private::downloadTimestamp()
327 {
328  mDebug() << "Determining remote bookmark state.";
329  m_timestampReply = m_network.get( QNetworkRequest( endpointUrl( m_timestampEndpoint ) ) );
330  connect( m_timestampReply, SIGNAL(finished()),
331  m_q, SLOT(parseTimestamp()) );
332 }
333 
334 bool BookmarkSyncManager::Private::cloudBookmarksModified( const QString &cloudTimestamp ) const
335 {
336  QStringList entryList = QDir( m_cachePath ).entryList(
337  // TODO: replace with regex filter that only
338  // allows timestamp filenames
339  QStringList() << "*.kml",
340  QDir::NoFilter, QDir::Name );
341  if( !entryList.isEmpty() ) {
342  QString lastSynced = entryList.last();
343  lastSynced.chop( 4 );
344  return cloudTimestamp != lastSynced;
345  } else {
346  return true; // That will let cloud one get downloaded.
347  }
348 }
349 
350 void BookmarkSyncManager::Private::clearCache()
351 {
352  QDir cacheDir( m_cachePath );
353  QFileInfoList fileInfoList = cacheDir.entryInfoList(
354  QStringList() << "*.kml",
355  QDir::NoFilter, QDir::Name );
356  if( !fileInfoList.isEmpty() ) {
357  foreach ( QFileInfo fileInfo, fileInfoList ) {
358  QFile file( fileInfo.absoluteFilePath() );
359  bool removed = file.remove();
360  if( !removed ) {
361  mDebug() << "Could not delete" << file.fileName() <<
362  "Make sure you have sufficient permissions.";
363  }
364  }
365  }
366 }
367 
368 QString BookmarkSyncManager::Private::lastSyncedKmlPath() const
369 {
370  QDir cacheDir( m_cachePath );
371  QFileInfoList fileInfoList = cacheDir.entryInfoList(
372  QStringList() << "*.kml",
373  QDir::NoFilter, QDir::Name );
374  if( !fileInfoList.isEmpty() ) {
375  return fileInfoList.last().absoluteFilePath();
376  } else {
377  return QString();
378  }
379 }
380 
381 QList<DiffItem> BookmarkSyncManager::Private::getPlacemarks( GeoDataDocument *document, GeoDataDocument *other, DiffItem::Status diffDirection )
382 {
383  QList<DiffItem> diffItems;
384  foreach ( GeoDataFolder *folder, document->folderList() ) {
385  QString path = QString( "/%0" ).arg( folder->name() );
386  diffItems.append( getPlacemarks( folder, path, other, diffDirection ) );
387  }
388 
389  return diffItems;
390 }
391 
392 QList<DiffItem> BookmarkSyncManager::Private::getPlacemarks( GeoDataFolder *folder, QString &path, GeoDataDocument *other, DiffItem::Status diffDirection )
393 {
394  QList<DiffItem> diffItems;
395  foreach ( GeoDataFolder *folder, folder->folderList() ) {
396  QString newPath = QString( "%0/%1" ).arg( path, folder->name() );
397  diffItems.append( getPlacemarks( folder, newPath, other, diffDirection ) );
398  }
399 
400  foreach( GeoDataPlacemark *placemark, folder->placemarkList() ) {
401  DiffItem diffItem;
402  diffItem.m_path = path;
403  diffItem.m_placemarkA = *placemark;
404  switch ( diffDirection ) {
405  case DiffItem::Source:
406  diffItem.m_origin = DiffItem::Destination;
407  break;
408  case DiffItem::Destination:
409  diffItem.m_origin = DiffItem::Source;
410  break;
411  default:
412  break;
413  }
414 
415  determineDiffStatus( diffItem, other );
416 
417  if( !( diffItem.m_action == DiffItem::NoAction && diffItem.m_origin == DiffItem::Destination )
418  && !( diffItem.m_action == DiffItem::Changed && diffItem.m_origin == DiffItem::Source ) ) {
419  diffItems.append( diffItem );
420  }
421  }
422 
423  return diffItems;
424 }
425 
426 const GeoDataPlacemark* BookmarkSyncManager::Private::findPlacemark( GeoDataContainer* container, const GeoDataPlacemark &bookmark ) const
427 {
428  foreach( GeoDataPlacemark* placemark, container->placemarkList() ) {
429  if ( EARTH_RADIUS * distanceSphere( placemark->coordinate(), bookmark.coordinate() ) <= 1 ) {
430  return placemark;
431  }
432  }
433 
434  foreach( GeoDataFolder* folder, container->folderList() ) {
435  const GeoDataPlacemark* placemark = findPlacemark( folder, bookmark );
436  if ( placemark ) {
437  return placemark;
438  }
439  }
440 
441  return 0;
442 }
443 
444 void BookmarkSyncManager::Private::determineDiffStatus( DiffItem &item, GeoDataDocument *document ) const
445 {
446  const GeoDataPlacemark *match = findPlacemark( document, item.m_placemarkA );
447 
448  if( match != 0 ) {
449  item.m_placemarkB = *match;
450  bool nameChanged = item.m_placemarkA.name() != item.m_placemarkB.name();
451  bool descChanged = item.m_placemarkA.description() != item.m_placemarkB.description();
452  bool lookAtChanged = item.m_placemarkA.lookAt()->latitude() != item.m_placemarkB.lookAt()->latitude() ||
453  item.m_placemarkA.lookAt()->longitude() != item.m_placemarkB.lookAt()->longitude() ||
454  item.m_placemarkA.lookAt()->altitude() != item.m_placemarkB.lookAt()->altitude() ||
455  item.m_placemarkA.lookAt()->range() != item.m_placemarkB.lookAt()->range();
456  if( nameChanged || descChanged || lookAtChanged ) {
457  item.m_action = DiffItem::Changed;
458  } else {
459  item.m_action = DiffItem::NoAction;
460  }
461  } else {
462  switch( item.m_origin ) {
463  case DiffItem::Source:
464  item.m_action = DiffItem::Deleted;
465  item.m_placemarkB = item.m_placemarkA; // for conflict purposes
466  break;
467  case DiffItem::Destination:
468  item.m_action = DiffItem::Created;
469  break;
470  }
471 
472  }
473 }
474 
475 QList<DiffItem> BookmarkSyncManager::Private::diff( QString &sourcePath, QString &destinationPath )
476 {
477  QFile fileB( destinationPath );
478  if( !fileB.open( QFile::ReadOnly ) ) {
479  mDebug() << "Could not open file " << fileB.fileName();
480  }
481  return diff( sourcePath, &fileB );
482 }
483 
484 QList<DiffItem> BookmarkSyncManager::Private::diff( QString &sourcePath, QIODevice *fileB )
485 {
486  QFile fileA( sourcePath );
487  if( !fileA.open( QFile::ReadOnly ) ) {
488  mDebug() << "Could not open file " << fileA.fileName();
489  }
490 
491  return diff( &fileA, fileB );
492 }
493 
494 QList<DiffItem> BookmarkSyncManager::Private::diff( QIODevice *source, QString &destinationPath )
495 {
496  QFile fileB( destinationPath );
497  if( !fileB.open( QFile::ReadOnly ) ) {
498  mDebug() << "Could not open file " << fileB.fileName();
499  }
500 
501  return diff( source, &fileB );
502 }
503 
504 QList<DiffItem> BookmarkSyncManager::Private::diff( QIODevice *fileA, QIODevice *fileB )
505 {
506  GeoDataParser parserA( GeoData_KML );
507  parserA.read( fileA );
508  GeoDataDocument *documentA = dynamic_cast<GeoDataDocument*>( parserA.releaseDocument() );
509 
510  GeoDataParser parserB( GeoData_KML );
511  parserB.read( fileB );
512  GeoDataDocument *documentB = dynamic_cast<GeoDataDocument*>( parserB.releaseDocument() );
513 
514  QList<DiffItem> diffItems = getPlacemarks( documentA, documentB, DiffItem::Destination ); // Compare old to new
515  diffItems.append( getPlacemarks( documentB, documentA, DiffItem::Source ) ); // Compare new to old
516 
517  // Compare paths
518  for( int i = 0; i < diffItems.count(); i++ ) {
519  for( int p = i + 1; p < diffItems.count(); p++ ) {
520  if( ( diffItems[i].m_origin == DiffItem::Source )
521  && ( diffItems[i].m_action == DiffItem::NoAction )
522  && ( EARTH_RADIUS * distanceSphere( diffItems[i].m_placemarkA.coordinate(), diffItems[p].m_placemarkB.coordinate() ) <= 1 )
523  && ( EARTH_RADIUS * distanceSphere( diffItems[i].m_placemarkB.coordinate(), diffItems[p].m_placemarkA.coordinate() ) <= 1 )
524  && ( diffItems[i].m_path != diffItems[p].m_path ) ) {
525  diffItems[p].m_action = DiffItem::Changed;
526  }
527  }
528  }
529 
530  return diffItems;
531 }
532 
533 void BookmarkSyncManager::Private::merge()
534 {
535  foreach( const DiffItem &itemA, m_diffA ) {
536  if( itemA.m_action == DiffItem::NoAction ) {
537  bool deleted = false;
538  bool changed = false;
539  DiffItem other;
540 
541  foreach( const DiffItem &itemB, m_diffB ) {
542  if( EARTH_RADIUS * distanceSphere( itemA.m_placemarkA.coordinate(), itemB.m_placemarkA.coordinate() ) <= 1 ) {
543  if( itemB.m_action == DiffItem::Deleted ) {
544  deleted = true;
545  } else if( itemB.m_action == DiffItem::Changed ) {
546  changed = true;
547  other = itemB;
548  }
549  }
550  }
551  if( changed ) {
552  m_merged.append( other );
553  } else if( !deleted ) {
554  m_merged.append( itemA );
555  }
556  } else if( itemA.m_action == DiffItem::Created ) {
557  m_merged.append( itemA );
558  } else if( itemA.m_action == DiffItem::Changed || itemA.m_action == DiffItem::Deleted ) {
559  bool conflict = false;
560  DiffItem other;
561 
562  foreach( const DiffItem &itemB, m_diffB ) {
563  if( EARTH_RADIUS * distanceSphere( itemA.m_placemarkB.coordinate(), itemB.m_placemarkB.coordinate() ) <= 1 ) {
564  if( ( itemA.m_action == DiffItem::Changed && ( itemB.m_action == DiffItem::Changed || itemB.m_action == DiffItem::Deleted ) )
565  || ( itemA.m_action == DiffItem::Deleted && itemB.m_action == DiffItem::Changed ) ) {
566  conflict = true;
567  other = itemB;
568  }
569  }
570  }
571 
572  if( !conflict && itemA.m_action == DiffItem::Changed ) {
573  m_merged.append( itemA );
574  } else if ( conflict ) {
575  m_conflictItem = other;
576  MergeItem *mergeItem = new MergeItem();
577  mergeItem->setPathA( itemA.m_path );
578  mergeItem->setPathB( other.m_path );
579  mergeItem->setPlacemarkA( itemA.m_placemarkA );
580  mergeItem->setPlacemarkB( other.m_placemarkA );
581 
582  switch( itemA.m_action ) {
583  case DiffItem::Changed:
584  mergeItem->setActionA( MergeItem::Changed );
585  break;
586  case DiffItem::Deleted:
587  mergeItem->setActionA( MergeItem::Deleted );
588  break;
589  default:
590  break;
591  }
592 
593  switch( other.m_action ) {
594  case DiffItem::Changed:
595  mergeItem->setActionB( MergeItem::Changed );
596  break;
597  case DiffItem::Deleted:
598  mergeItem->setActionB( MergeItem::Deleted );
599  break;
600  default:
601  break;
602  }
603 
604  emit m_q->mergeConflict( mergeItem );
605  return;
606  }
607  }
608 
609  if( !m_diffA.isEmpty() ) {
610  m_diffA.removeFirst();
611  }
612  }
613 
614  foreach( const DiffItem &itemB, m_diffB ) {
615  if( itemB.m_action == DiffItem::Created ) {
616  m_merged.append( itemB );
617  }
618  }
619 
620  completeMerge();
621 }
622 
623 GeoDataFolder* BookmarkSyncManager::Private::createFolders( GeoDataContainer *container, QStringList &pathList )
624 {
625  GeoDataFolder *folder = 0;
626  if( pathList.count() > 0 ) {
627  QString name = pathList.takeFirst();
628 
629  foreach( GeoDataFolder *otherFolder, container->folderList() ) {
630  if( otherFolder->name() == name ) {
631  folder = otherFolder;
632  }
633  }
634 
635  if( folder == 0 ) {
636  folder = new GeoDataFolder();
637  folder->setName( name );
638  container->append( folder );
639  }
640 
641  if( pathList.count() == 0 ) {
642  return folder;
643  }
644  }
645 
646  return createFolders( folder, pathList );
647 }
648 
649 GeoDataDocument* BookmarkSyncManager::Private::constructDocument( const QList<DiffItem> &mergedList )
650 {
651  GeoDataDocument *document = new GeoDataDocument();
652  document->setName( tr( "Bookmarks" ) );
653 
654  foreach( const DiffItem &item, mergedList ) {
655  GeoDataPlacemark *placemark = new GeoDataPlacemark( item.m_placemarkA );
656  QStringList splitten = item.m_path.split( '/', QString::SkipEmptyParts );
657  GeoDataFolder *folder = createFolders( document, splitten );
658  folder->append( placemark );
659  }
660 
661  return document;
662 }
663 
664 void BookmarkSyncManager::resolveConflict( MergeItem *item )
665 {
666  DiffItem diffItem;
667 
668  switch( item->resolution() ) {
669  case MergeItem::A:
670  if( !d->m_diffA.isEmpty() ) {
671  diffItem = d->m_diffA.first();
672  break;
673  }
674  case MergeItem::B:
675  diffItem = d->m_conflictItem;
676  break;
677  default:
678  return; // It shouldn't happen.
679  }
680 
681  if( diffItem.m_action != DiffItem::Deleted ) {
682  d->m_merged.append( diffItem );
683  }
684 
685  if( !d->m_diffA.isEmpty() ) {
686  d->m_diffA.removeFirst();
687  }
688 
689  d->merge();
690 }
691 
692 void BookmarkSyncManager::Private::saveDownloadedToCache( const QByteArray &kml )
693 {
694  QString localBookmarksDir = m_localBookmarksPath;
695  QDir().mkdir( localBookmarksDir.remove( "bookmarks.kml" ) );
696  QFile bookmarksFile( m_localBookmarksPath );
697  if( !bookmarksFile.open( QFile::ReadWrite ) ) {
698  mDebug() << "Failed to open file" << bookmarksFile.fileName()
699  << ". It is either missing or not readable.";
700  return;
701  }
702 
703  bookmarksFile.write( kml );
704  bookmarksFile.close();
705  copyLocalToCache();
706 }
707 
708 void BookmarkSyncManager::Private::parseTimestamp()
709 {
710  QString response = m_timestampReply->readAll();
711  QScriptEngine engine;
712  QScriptValue parsedResponse = engine.evaluate( QString( "(%0)" ).arg( response ) );
713  QString timestamp = parsedResponse.property( "data" ).toString();
714  m_cloudTimestamp = timestamp;
715  mDebug() << "Remote bookmark timestamp is " << m_cloudTimestamp;
716  continueSynchronization();
717 }
718 void BookmarkSyncManager::Private::copyLocalToCache()
719 {
720  QDir().mkpath( m_cachePath );
721  clearCache();
722 
723  QFile bookmarksFile( m_localBookmarksPath );
724  bookmarksFile.copy( QString( "%0/%1.kml" ).arg( m_cachePath, m_cloudTimestamp ) );
726  disconnect( m_bookmarkManager, SIGNAL(bookmarksChanged()), m_q, SLOT(startBookmarkSync()) );
727  m_bookmarkManager->loadFile( "bookmarks/bookmarks.kml" );
728  connect( m_bookmarkManager, SIGNAL(bookmarksChanged()), m_q, SLOT(startBookmarkSync()) );
729 }
730 
731 // Bookmark synchronization steps
732 void BookmarkSyncManager::Private::continueSynchronization()
733 {
734  bool cloudModified = cloudBookmarksModified( m_cloudTimestamp );
735  if( cloudModified ) {
736  downloadBookmarks();
737  } else {
738  QString lastSyncedPath = lastSyncedKmlPath();
739  if( lastSyncedPath.isEmpty() ) {
740  mDebug() << "Never synced. Uploading bookmarks.";
741  uploadBookmarks();
742  } else {
743  QList<DiffItem> diffList = diff( lastSyncedPath, m_localBookmarksPath );
744  bool localModified = false;
745  foreach( const DiffItem &item, diffList ) {
746  if( item.m_action != DiffItem::NoAction ) {
747  localModified = true;
748  }
749  }
750 
751  if( localModified ) {
752  mDebug() << "Local modifications, uploading.";
753  uploadBookmarks();
754  }
755  }
756  }
757 }
758 
759 void BookmarkSyncManager::Private::completeSynchronization()
760 {
761  mDebug() << "Merging remote and local bookmark file";
762  QString lastSyncedPath = lastSyncedKmlPath();
763  QFile localBookmarksFile( m_localBookmarksPath );
764  QByteArray result = m_downloadReply->readAll();
765  QBuffer buffer( &result );
766  buffer.open( QIODevice::ReadOnly );
767 
768  if( lastSyncedPath.isEmpty() ) {
769  if( localBookmarksFile.exists() ) {
770  mDebug() << "Conflict between remote bookmarks and local ones";
771  m_diffA = diff( &buffer, m_localBookmarksPath );
772  m_diffB = diff( m_localBookmarksPath, &buffer );
773  } else {
774  saveDownloadedToCache( result );
775  return;
776  }
777  }
778  else
779  {
780  m_diffA = diff( lastSyncedPath, m_localBookmarksPath );
781  m_diffB = diff( lastSyncedPath, &buffer );
782  }
783 
784  m_merged.clear();
785  merge();
786 }
787 
788 void BookmarkSyncManager::Private::completeMerge()
789 {
790  QFile localBookmarksFile( m_localBookmarksPath );
791  GeoDataDocument *doc = constructDocument( m_merged );
792  GeoWriter writer;
793  localBookmarksFile.remove();
794  localBookmarksFile.open( QFile::ReadWrite );
795  writer.write( &localBookmarksFile, doc );
796  localBookmarksFile.close();
797  uploadBookmarks();
798 }
799 
800 void BookmarkSyncManager::Private::completeUpload()
801 {
802  QString response = m_uploadReply->readAll();
803  QScriptEngine engine;
804  QScriptValue parsedResponse = engine.evaluate( QString( "(%0)" ).arg( response ) );
805  QString timestamp = parsedResponse.property( "data" ).toString();
806  m_cloudTimestamp = timestamp;
807  mDebug() << "Uploaded bookmarks to remote server. Timestamp is " << m_cloudTimestamp;
808  copyLocalToCache();
809  emit m_q->syncComplete();
810 }
811 
812 }
813 
814 #include "BookmarkSyncManager.moc"
QIODevice
GeoDataDocument.h
Marble::BookmarkSyncManager::setBookmarkManager
void setBookmarkManager(BookmarkManager *manager)
Definition: BookmarkSyncManager.cpp:261
GeoDataCoordinates.h
Marble::MergeItem::resolution
MergeItem::Resolution resolution
Definition: MergeItem.h:41
MarbleMath.h
Marble::BookmarkSyncManager::isBookmarkSyncEnabled
bool isBookmarkSyncEnabled() const
Checks if the user enabled bookmark synchronization.
Definition: BookmarkSyncManager.cpp:244
QByteArray
QFile::remove
bool remove()
MarbleModel.h
This file contains the headers for MarbleModel.
QNetworkReply
QScriptValue
QScriptEngine::evaluate
QScriptValue evaluate(const QString &program, const QString &fileName, int lineNumber)
Marble::BookmarkSyncManager::~BookmarkSyncManager
~BookmarkSyncManager()
Definition: BookmarkSyncManager.cpp:231
QBuffer
Marble::BookmarkSyncManager::setBookmarkSyncEnabled
void setBookmarkSyncEnabled(bool enabled)
Setter for enabling/disabling bookmark synchronization.
Definition: BookmarkSyncManager.cpp:249
GeoDataParser.h
Marble::distanceSphere
qreal distanceSphere(qreal lon1, qreal lat1, qreal lon2, qreal lat2)
This method calculates the shortest distance between two points on a sphere.
Definition: MarbleMath.h:52
QString::remove
QString & remove(int position, int n)
QIODevice::open
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
QString::chop
void chop(int n)
MarbleDebug.h
QScriptValue::toString
QString toString() const
QFile
BookmarkManager.h
GeoWriter.h
Marble::GeoData_KML
Definition: GeoDataParser.h:36
Marble::MergeItem::B
Definition: MergeItem.h:46
QScriptEngine
Marble::BookmarkSyncManager::startBookmarkSync
void startBookmarkSync()
Initiates running of synchronization "method chain".
Definition: BookmarkSyncManager.cpp:268
Marble::BookmarkManager
This class is responsible for loading the book mark objects from the files and various book mark oper...
Definition: BookmarkManager.h:35
QNetworkRequest
QList::count
int count(const T &value) const
GeoCute::Status
Status
Definition: Status.h:19
QList::append
void append(const T &value)
Marble::EARTH_RADIUS
const qreal EARTH_RADIUS
Definition: MarbleGlobal.h:257
QTimer
QObject
QList::isEmpty
bool isEmpty() const
MarbleDirs.h
QFileInfo::absoluteFilePath
QString absoluteFilePath() const
QString::isEmpty
bool isEmpty() const
Marble::BookmarkSyncManager::BookmarkSyncManager
BookmarkSyncManager(CloudSyncManager *cloudSyncManager)
Definition: BookmarkSyncManager.cpp:223
Marble::MergeItem::Deleted
Definition: MergeItem.h:51
QString
QList< DiffItem >
QScriptValue::property
QScriptValue property(const QString &name, const ResolveFlags &mode) const
QStringList
Marble::MergeItem
Definition: MergeItem.h:23
QByteArray::append
QByteArray & append(char ch)
QFileInfo
Marble::MergeItem::Changed
Definition: MergeItem.h:50
QUrl
OwncloudSyncBackend.h
QDir
GeoDataFolder.h
QNetworkAccessManager
QList::takeFirst
T takeFirst()
QDir::mkdir
bool mkdir(const QString &dirName) const
QDir::entryList
QStringList entryList(QFlags< QDir::Filter > filters, QFlags< QDir::SortFlag > sort) const
Marble::BookmarkSyncManager::lastSync
QDateTime lastSync() const
Last time Marble synced everything up.
Definition: BookmarkSyncManager.cpp:236
QList::last
T & last()
Marble::BookmarkSyncManager::bookmarkSyncEnabledChanged
void bookmarkSyncEnabledChanged(bool enabled)
QFileInfo::created
QDateTime created() const
Marble::BookmarkSyncManager::resolveConflict
void resolveConflict(MergeItem *item)
Definition: BookmarkSyncManager.cpp:664
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
Marble::MergeItem::A
Definition: MergeItem.h:45
QObject::parent
QObject * parent() const
Marble::CloudSyncManager
Definition: CloudSyncManager.h:24
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
CloudSyncManager.h
Marble::mDebug
QDebug mDebug()
a function to replace qDebug() in Marble library code
Definition: MarbleDebug.cpp:36
BookmarkSyncManager.h
QDir::mkpath
bool mkpath(const QString &dirPath) const
QDateTime
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:13:38 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

marble

Skip menu "marble"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdeedu API Reference

Skip menu "kdeedu API Reference"
  • Analitza
  •     lib
  • kalgebra
  • kalzium
  •   libscience
  • kanagram
  • kig
  •   lib
  • klettres
  • marble
  • parley
  • rocs
  •   App
  •   RocsCore
  •   VisualEditor
  •   stepcore

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal