diff --git src/gui/generalsettings.cpp src/gui/generalsettings.cpp index dd8037d..7aed285 100644 --- src/gui/generalsettings.cpp +++ src/gui/generalsettings.cpp @@ -69,6 +69,7 @@ GeneralSettings::GeneralSettings(QWidget *parent) : connect(_ui->newFolderLimitCheckBox, SIGNAL(toggled(bool)), SLOT(saveMiscSettings())); connect(_ui->newFolderLimitSpinBox, SIGNAL(valueChanged(int)), SLOT(saveMiscSettings())); connect(_ui->newExternalStorage, SIGNAL(toggled(bool)), SLOT(saveMiscSettings())); + connect(_ui->moveToTrashCheckBox, SIGNAL(toggled(bool)), SLOT(saveMiscSettings())); #ifndef WITH_CRASHREPORTER _ui->crashreporterCheckBox->setVisible(false); @@ -119,6 +120,7 @@ void GeneralSettings::loadMiscSettings() _ui->newFolderLimitCheckBox->setChecked(newFolderLimit.first); _ui->newFolderLimitSpinBox->setValue(newFolderLimit.second); _ui->newExternalStorage->setChecked(cfgFile.confirmExternalStorage()); + _ui->moveToTrashCheckBox->setChecked(cfgFile.moveToTrash()); _ui->monoIconsCheckBox->setChecked(cfgFile.monoIcons()); } @@ -155,6 +157,7 @@ void GeneralSettings::saveMiscSettings() cfgFile.setNewBigFolderSizeLimit(_ui->newFolderLimitCheckBox->isChecked(), _ui->newFolderLimitSpinBox->value()); cfgFile.setConfirmExternalStorage(_ui->newExternalStorage->isChecked()); + cfgFile.setMoveToTrash(_ui->moveToTrashCheckBox->isChecked()); } void GeneralSettings::slotToggleLaunchOnStartup(bool enable) diff --git src/gui/generalsettings.ui src/gui/generalsettings.ui index 20f2c86..d2fcd66 100644 --- src/gui/generalsettings.ui +++ src/gui/generalsettings.ui @@ -129,6 +129,13 @@ + + + Move deleted files to trash + + + + diff --git src/libsync/configfile.cpp src/libsync/configfile.cpp index f7350ce..5821011 100644 --- src/libsync/configfile.cpp +++ src/libsync/configfile.cpp @@ -69,6 +69,7 @@ static const char downloadLimitC[] = "BWLimit/downloadLimit"; static const char newBigFolderSizeLimitC[] = "newBigFolderSizeLimit"; static const char useNewBigFolderSizeLimitC[] = "useNewBigFolderSizeLimit"; static const char confirmExternalStorageC[] = "confirmExternalStorage"; +static const char moveToTrashC[] = "moveToTrash"; static const char maxLogLinesC[] = "Logging/maxLogLines"; @@ -608,6 +609,16 @@ void ConfigFile::setConfirmExternalStorage(bool isChecked) setValue(confirmExternalStorageC, isChecked); } +bool ConfigFile::moveToTrash() const +{ + return getValue(moveToTrashC, QString(), true).toBool(); +} + +void ConfigFile::setMoveToTrash(bool isChecked) +{ + setValue(moveToTrashC, isChecked); +} + bool ConfigFile::promptDeleteFiles() const { QSettings settings(configFile(), QSettings::IniFormat); diff --git src/libsync/configfile.h src/libsync/configfile.h index 0fe3b3c..174b745 100644 --- src/libsync/configfile.h +++ src/libsync/configfile.h @@ -107,6 +107,8 @@ public: void setNewBigFolderSizeLimit(bool isChecked, quint64 mbytes); bool confirmExternalStorage() const; void setConfirmExternalStorage(bool); + bool moveToTrash() const; + void setMoveToTrash(bool); static bool setConfDir(const QString &value); diff --git src/libsync/filesystem.cpp src/libsync/filesystem.cpp index be63fec..5d2a302 100644 --- src/libsync/filesystem.cpp +++ src/libsync/filesystem.cpp @@ -14,7 +14,9 @@ #include "filesystem.h" +#include "configfile.h" #include "utility.h" +#include #include #include #include @@ -588,15 +590,79 @@ bool FileSystem::remove(const QString &fileName, QString *errorString) setFileReadOnly(fileName, false); } #endif - QFile f(fileName); - if (!f.remove()) { - if (errorString) { - *errorString = f.errorString(); +#ifdef Q_OS_UNIX + int _moveToTrash = -1; + ConfigFile cfgFile; + _moveToTrash = cfgFile.moveToTrash() ? 1 : 0; + + if(_moveToTrash == 1){ + Q_UNUSED(errorString); + qDebug() << "moving" << fileName << "to trash"; + if (!moveToTrash(fileName)) { + return false; } + } + if(_moveToTrash == 0) { +#endif + QFile f(fileName); + if (!f.remove()) { + if (errorString) { + *errorString = f.errorString(); + } + return false; + } +#ifdef Q_OS_UNIX + } +#endif + return true; +} + +#ifdef Q_OS_UNIX +bool FileSystem::moveToTrash(const QString &fileName) +{ + QString trashPath, trashFilePath, trashInfoPath; + QString xdgDataHome = QFile::decodeName(qgetenv("XDG_DATA_HOME")); + if (xdgDataHome.isEmpty()) { + trashPath=QDir::homePath()+"/.local/share/Trash/"; // trash path that should exist + } else { + trashPath=xdgDataHome+"/Trash/"; + } + + trashFilePath=trashPath+"files/"; // trash file path contain delete files + trashInfoPath=trashPath+"info/"; // trash info path contain delete files information + + if (!(QDir().mkpath(trashFilePath) && QDir().mkpath(trashInfoPath))) + return false; //mkpath will return true if path exists + + // create file format for trash info file----- START + QFileInfo f(fileName); + QFile infoFile(trashInfoPath+f.fileName()+".trashinfo"); //filename+.trashinfo // create file information file in /.local/share/Trash/info/ folder + + infoFile.open(QIODevice::ReadWrite); + + QTextStream stream(&infoFile); // for write data on open file + + QByteArray info = "[Trash Info]\n"; + info += "Path="; + info += QUrl::toPercentEncoding(f.absoluteFilePath(),"~_-./"); + info += '\n'; + info += "DeletionDate="; + info += QDateTime::currentDateTime().toString(Qt::ISODate).toLatin1(); + info += '\n'; + + stream << info; + + infoFile.close(); + + // create info file format of trash file----- END + + QDir file; + if (!file.rename(f.absoluteFilePath(),trashFilePath+f.fileName())){ // rename(file old path, file trash path) return false; } return true; } +#endif bool FileSystem::isFileLocked(const QString& fileName) { diff --git src/libsync/filesystem.h src/libsync/filesystem.h index 36ac8d5..599b6a6 100644 --- src/libsync/filesystem.h +++ src/libsync/filesystem.h @@ -162,6 +162,9 @@ bool uncheckedRenameReplace(const QString &originFileName, */ bool OWNCLOUDSYNC_EXPORT remove(const QString &fileName, QString *errorString = 0); +#ifdef Q_OS_UNIX +bool moveToTrash(const QString &filename); +#endif /** * Replacement for QFile::open(ReadOnly) followed by a seek(). * This version sets a more permissive sharing mode on Windows. diff --git src/libsync/propagatorjobs.cpp src/libsync/propagatorjobs.cpp index 771b282..f8eeaf2 100644 --- src/libsync/propagatorjobs.cpp +++ src/libsync/propagatorjobs.cpp @@ -13,6 +13,7 @@ * for more details. */ +#include "configfile.h" #include "propagatorjobs.h" #include "owncloudpropagator_p.h" #include "propagateremotemove.h" @@ -50,6 +51,13 @@ namespace OCC { */ bool PropagateLocalRemove::removeRecursively(const QString& path) { +#ifdef Q_OS_UNIX + if (_moveToTrash == -1){ + ConfigFile cfgFile; + _moveToTrash = cfgFile.moveToTrash() ? 1 : 0; + } +#endif + bool success = true; QString absolute = propagator()->_localDir + _item->_file + path; QDirIterator di(absolute, QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot); @@ -59,21 +67,27 @@ bool PropagateLocalRemove::removeRecursively(const QString& path) while (di.hasNext()) { di.next(); const QFileInfo& fi = di.fileInfo(); - bool ok; + bool ok = true; // The use of isSymLink here is okay: // we never want to go into this branch for .lnk files bool isDir = fi.isDir() && !fi.isSymLink(); - if (isDir) { - ok = removeRecursively(path + QLatin1Char('/') + di.fileName()); // recursive - } else { - QString removeError; - ok = FileSystem::remove(di.filePath(), &removeError); - if (!ok) { - _error += PropagateLocalRemove::tr("Error removing '%1': %2;"). - arg(QDir::toNativeSeparators(di.filePath()), removeError) + " "; - qDebug() << "Error removing " << di.filePath() << ':' << removeError; +#ifdef Q_OS_UNIX + if (_moveToTrash == 0) { +#endif + if (isDir) { + ok = removeRecursively(path + QLatin1Char('/') + di.fileName()); // recursive + } else { + QString removeError; + ok = FileSystem::remove(di.filePath(), &removeError); + if (!ok) { + _error += PropagateLocalRemove::tr("Error removing '%1': %2;"). + arg(QDir::toNativeSeparators(di.filePath()), removeError) + " "; + qDebug() << "Error removing " << di.filePath() << ':' << removeError; + } } +#ifdef Q_OS_UNIX } +#endif if (success && !ok) { // We need to delete the entries from the database now from the deleted vector foreach(const auto &it, deleted) { @@ -93,7 +107,16 @@ bool PropagateLocalRemove::removeRecursively(const QString& path) } } if (success) { - success = QDir().rmdir(absolute); +#ifdef Q_OS_UNIX + if (_moveToTrash == 0) { +#endif + success = QDir().rmdir(absolute); +#ifdef Q_OS_UNIX + } + if (_moveToTrash == 1) { + success = FileSystem::remove(absolute); + } +#endif if (!success) { _error += PropagateLocalRemove::tr("Could not remove folder '%1'") .arg(QDir::toNativeSeparators(absolute)) + " "; diff --git src/libsync/propagatorjobs.h src/libsync/propagatorjobs.h index c3898db..8df73f6 100644 --- src/libsync/propagatorjobs.h +++ src/libsync/propagatorjobs.h @@ -40,11 +40,12 @@ static const char checkSumAdlerC[] = "Adler32"; class PropagateLocalRemove : public PropagateItemJob { Q_OBJECT public: - PropagateLocalRemove (OwncloudPropagator* propagator,const SyncFileItemPtr& item) : PropagateItemJob(propagator, item) {} + PropagateLocalRemove (OwncloudPropagator* propagator,const SyncFileItemPtr& item) : PropagateItemJob(propagator, item), _moveToTrash(-1) {} void start() Q_DECL_OVERRIDE; private: bool removeRecursively(const QString &path); QString _error; + int _moveToTrash; }; /**