File indexing completed on 2024-04-21 03:49:30

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2010 Bastian Holst <bastianholst@gmx.de>
0004 //
0005 
0006 // Self
0007 #include "DataMigration.h"
0008 
0009 // Marble
0010 #include "MarbleDebug.h"
0011 #include "MarbleDirs.h"
0012 #include "ui_DataMigrationWidget.h"
0013 
0014 // Qt
0015 #include <QDebug>
0016 #include <QDir>
0017 #include <QDirIterator>
0018 #include <QPointer>
0019 #include <QStack>
0020 #include <QDialog>
0021 #include <QProgressDialog>
0022 
0023 // std
0024 #include <limits>
0025 
0026 namespace Marble
0027 {
0028 
0029 DataMigration::DataMigration( QObject *parent )
0030     : QObject( parent )
0031 {
0032 }
0033 
0034 DataMigration::~DataMigration()
0035 {
0036 }
0037 
0038 void DataMigration::exec()
0039 {
0040     QStringList oldLocalPaths = MarbleDirs::oldLocalPaths();
0041 
0042     if( oldLocalPaths.isEmpty() ) {
0043         return;
0044     }
0045 
0046     QString currentLocalPath = MarbleDirs::localPath();
0047     QDir currentLocalDir( currentLocalPath );
0048     if( currentLocalDir.entryList( QDir::AllEntries | QDir::NoDotAndDotDot ).size() != 0 ) {
0049         return;
0050     }
0051 
0052     for( const QString& oldLocalPath: oldLocalPaths ) {
0053         QDir oldLocalDir( oldLocalPath );
0054 
0055         if( oldLocalDir.entryList( QDir::AllEntries | QDir::NoDotAndDotDot ).size() == 0 ) {
0056             continue;
0057         }
0058 
0059         QPointer<QDialog> dialog = new QDialog();
0060         Ui::DataMigrationWidget dataMigrationWidget;
0061 
0062         dataMigrationWidget.setupUi( dialog );
0063         if( dialog->exec() == QDialog::Accepted ) {
0064             DataMigration::moveFiles( oldLocalPath, currentLocalPath );
0065         }
0066         delete dialog;
0067 
0068         return;
0069     }
0070 }
0071 
0072 void DataMigration::moveFiles( const QString& source, const QString& target )
0073 {
0074     if( !QDir().rmdir( target ) ) {
0075         mDebug() << "Removing of the target directory failed";
0076     }
0077 
0078     // Trying to simply rename the directory. This is the fastest method, but it is not always
0079     // possible. For example when the directories are on different file systems.
0080     // If the renaming of the directory is not successful, we have to copy and delete each
0081     // file separately.
0082     mDebug() << "Rename" << source << "to" << target;
0083     if( !QDir().rename( source, target ) ) {
0084         mDebug() << "Simple renaming of the data directory failed. Moving single files";
0085 
0086         QProgressDialog progressDialog;
0087         progressDialog.setWindowModality( Qt::WindowModal );
0088         progressDialog.setMinimum( 0 );
0089         progressDialog.setMaximum( std::numeric_limits<int>::max() );
0090         progressDialog.setAutoReset( false );
0091         progressDialog.setAutoClose( false );
0092         progressDialog.setWindowTitle( tr( "Marble data conversion" ) );
0093         progressDialog.setLabelText( tr( "Converting data ..." ) );
0094 
0095         QDir().mkpath( target );
0096         QString sourcePath = QDir( source ).canonicalPath();
0097         int sourcePathLength = sourcePath.length();
0098 
0099         // Running through all files recursively
0100         QStack<QString> dirs;
0101         dirs.push( sourcePath );
0102 
0103         QStack<int> progressSliceSizeStack;
0104         progressSliceSizeStack.push( progressDialog.maximum() );
0105         int progress = 0;
0106 
0107         while( !dirs.isEmpty() ) {
0108             if( progressDialog.wasCanceled() ) {
0109                 return;
0110             }
0111 
0112             QString sourceDirPath = dirs.top();
0113             mDebug() << "DataMigration: Current source dir path ="
0114                      << sourceDirPath;
0115             mDebug() << "SliceSize =" << progressSliceSizeStack.top();
0116 
0117             if( !sourceDirPath.startsWith( sourcePath ) ) {
0118                 dirs.pop();
0119                 progress += progressSliceSizeStack.pop();
0120                 progressDialog.setValue( progress );
0121                 continue;
0122             }
0123 
0124             QDir sourceDir( sourceDirPath );
0125             // Creating child file/dir lists.
0126             QStringList files = sourceDir.entryList( QDir::Files
0127                                                      | QDir::NoSymLinks
0128                                                      | QDir::NoDotAndDotDot );
0129             QStringList childDirs = sourceDir.entryList( QDir::Dirs
0130                                                          | QDir::NoSymLinks
0131                                                          | QDir::NoDotAndDotDot );
0132             int childSliceSize = 0;
0133             if( !childDirs.isEmpty() ) {
0134                 childSliceSize = progressSliceSizeStack.pop() / childDirs.size();
0135                 progressSliceSizeStack.push( 0 );
0136             }
0137 
0138             if( files.isEmpty() && childDirs.isEmpty() )
0139             {
0140                 // Remove empty directory
0141                 mDebug() << "DataMigration:" << dirs.top()
0142                          << "finished";
0143                 QDir().rmdir( dirs.pop() );
0144                 progress += progressSliceSizeStack.pop();
0145                 progressDialog.setValue( progress );
0146             }
0147             else {
0148                 // Add child directories to the stack
0149                 for( const QString& childDir: childDirs ) {
0150                     dirs.push(sourceDirPath + QLatin1Char('/') + childDir);
0151                     progressSliceSizeStack.push( childSliceSize );
0152                 }
0153 
0154                 // Creating target dir
0155                 QString targetDirPath = sourceDirPath;
0156                 targetDirPath.remove( 0, sourcePathLength );
0157                 targetDirPath.prepend( target );
0158                 QDir().mkpath( targetDirPath );
0159 
0160                 // Copying contents
0161                 for( const QString& file: files ) {
0162                     if( progressDialog.wasCanceled() ) {
0163                         return;
0164                     }
0165 
0166                     const QString sourceFilePath = sourceDirPath + QLatin1Char('/') + file;
0167 
0168                     if( !sourceFilePath.startsWith( sourcePath ) ) {
0169                         continue;
0170                     }
0171 
0172                     QString targetFilePath = sourceFilePath;
0173                     targetFilePath.remove( 0, sourcePathLength );
0174                     targetFilePath.prepend( target );
0175 
0176                     QFile::copy( sourceFilePath, targetFilePath );
0177                     QFile::remove( sourceFilePath );
0178                 }
0179             }
0180         }
0181     }
0182 }
0183 
0184 }
0185 
0186 #include "moc_DataMigration.cpp"