From: Kevin Ottens Date: Wed, 7 Oct 2020 14:30:43 +0000 (+0200) Subject: Move some of the SocketApi conflict handling in a ConflictSolver class X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~12^2~22^2~95^2~7 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=4fdb203cdb39ead4ab6fc16a9323f7fad65cb53d;p=nextcloud-desktop.git Move some of the SocketApi conflict handling in a ConflictSolver class The socket api move and delete commands are not strictly about conflicts since they also deal with files which couldn't be uploaded for some other reason. Still the new ConflictSolver could be used in those cases. This opens the door at reusing that logic in other places. Signed-off-by: Kevin Ottens --- diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 97a3c19af..7ae36a983 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -54,6 +54,7 @@ set(client_SRCS accountmanager.cpp accountsettings.cpp application.cpp + conflictsolver.cpp connectionvalidator.cpp folder.cpp folderman.cpp diff --git a/src/gui/conflictsolver.cpp b/src/gui/conflictsolver.cpp new file mode 100644 index 000000000..578d15a54 --- /dev/null +++ b/src/gui/conflictsolver.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (C) by Kevin Ottens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "conflictsolver.h" + +#include +#include + +#include "filesystem.h" + +namespace OCC { + +Q_LOGGING_CATEGORY(lcConflict, "nextcloud.gui.conflictsolver", QtInfoMsg) + +ConflictSolver::ConflictSolver(QWidget *parent) + : QObject(parent) + , _parentWidget(parent) +{ +} + +QString ConflictSolver::localVersionFilename() const +{ + return _localVersionFilename; +} + +QString ConflictSolver::remoteVersionFilename() const +{ + return _remoteVersionFilename; +} + +bool ConflictSolver::exec(ConflictSolver::Solution solution) +{ + switch (solution) { + case KeepLocalVersion: + return overwriteRemoteVersion(); + case KeepRemoteVersion: + return deleteLocalVersion(); + } + Q_UNREACHABLE(); + return false; +} + +void ConflictSolver::setLocalVersionFilename(const QString &localVersionFilename) +{ + if (_localVersionFilename == localVersionFilename) { + return; + } + + _localVersionFilename = localVersionFilename; + emit localVersionFilenameChanged(); +} + +void ConflictSolver::setRemoteVersionFilename(const QString &remoteVersionFilename) +{ + if (_remoteVersionFilename == remoteVersionFilename) { + return; + } + + _remoteVersionFilename = remoteVersionFilename; + emit remoteVersionFilenameChanged(); +} + +bool ConflictSolver::deleteLocalVersion() +{ + if (_localVersionFilename.isEmpty()) { + return false; + } + + QFileInfo info(_localVersionFilename); + if (!info.exists()) { + return false; + } + + const auto message = info.isDir() ? tr("Do you want to delete the directory %1 and all its contents permanently?").arg(info.dir().dirName()) + : tr("Do you want to delete the file %1 permanently?").arg(info.fileName()); + const auto result = QMessageBox::question(_parentWidget, tr("Confirm deletion"), message, QMessageBox::Yes, QMessageBox::No); + if (result != QMessageBox::Yes) + return false; + + if (info.isDir()) { + return FileSystem::removeRecursively(_localVersionFilename); + } else { + return QFile(_localVersionFilename).remove(); + } +} + +bool ConflictSolver::overwriteRemoteVersion() +{ + if (_localVersionFilename.isEmpty()) { + return false; + } + + if (_remoteVersionFilename.isEmpty()) { + return false; + } + + QFileInfo info(_localVersionFilename); + if (!info.exists()) { + return false; + } + + QString error; + if (FileSystem::uncheckedRenameReplace(_localVersionFilename, _remoteVersionFilename, &error)) { + return true; + } else { + qCWarning(lcConflict) << "Rename error:" << error; + QMessageBox::warning(_parentWidget, tr("Error"), tr("Moving file failed:\n\n%1").arg(error)); + return false; + } +} + +} // namespace OCC diff --git a/src/gui/conflictsolver.h b/src/gui/conflictsolver.h new file mode 100644 index 000000000..e31e6eb0a --- /dev/null +++ b/src/gui/conflictsolver.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) by Kevin Ottens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#ifndef CONFLICTSOLVER_H +#define CONFLICTSOLVER_H + +#include + +class QWidget; + +namespace OCC { + +class ConflictSolver : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString localVersionFilename READ localVersionFilename WRITE setLocalVersionFilename NOTIFY localVersionFilenameChanged) + Q_PROPERTY(QString remoteVersionFilename READ remoteVersionFilename WRITE setRemoteVersionFilename NOTIFY remoteVersionFilenameChanged) +public: + enum Solution { + KeepLocalVersion, + KeepRemoteVersion + }; + + explicit ConflictSolver(QWidget *parent = nullptr); + + QString localVersionFilename() const; + QString remoteVersionFilename() const; + + bool exec(Solution solution); + +public slots: + void setLocalVersionFilename(const QString &localVersionFilename); + void setRemoteVersionFilename(const QString &remoteVersionFilename); + +signals: + void localVersionFilenameChanged(); + void remoteVersionFilenameChanged(); + +private: + bool deleteLocalVersion(); + bool overwriteRemoteVersion(); + + QWidget *_parentWidget; + QString _localVersionFilename; + QString _remoteVersionFilename; +}; + +} // namespace OCC + +#endif // CONFLICTSOLVER_H diff --git a/src/gui/socketapi.cpp b/src/gui/socketapi.cpp index e7bb0fa47..3fa216919 100644 --- a/src/gui/socketapi.cpp +++ b/src/gui/socketapi.cpp @@ -16,6 +16,7 @@ #include "socketapi.h" +#include "conflictsolver.h" #include "config.h" #include "configfile.h" #include "folderman.h" @@ -691,22 +692,9 @@ void SocketApi::copyUrlToClipboard(const QString &link) void SocketApi::command_DELETE_ITEM(const QString &localFile, SocketListener *) { - QFileInfo info(localFile); - - auto result = QMessageBox::question( - nullptr, tr("Confirm deletion"), - info.isDir() - ? tr("Do you want to delete the directory %1 and all its contents permanently?").arg(info.dir().dirName()) - : tr("Do you want to delete the file %1 permanently?").arg(info.fileName()), - QMessageBox::Yes, QMessageBox::No); - if (result != QMessageBox::Yes) - return; - - if (info.isDir()) { - FileSystem::removeRecursively(localFile); - } else { - QFile(localFile).remove(); - } + ConflictSolver solver; + solver.setLocalVersionFilename(localFile); + solver.exec(ConflictSolver::KeepRemoteVersion); } void SocketApi::command_MOVE_ITEM(const QString &localFile, SocketListener *) @@ -742,13 +730,9 @@ void SocketApi::command_MOVE_ITEM(const QString &localFile, SocketListener *) if (target.isEmpty()) return; - QString error; - if (!FileSystem::uncheckedRenameReplace(localFile, target, &error)) { - qCWarning(lcSocketApi) << "Rename error:" << error; - QMessageBox::warning( - nullptr, tr("Error"), - tr("Moving file failed:\n\n%1").arg(error)); - } + ConflictSolver solver; + solver.setLocalVersionFilename(localFile); + solver.setRemoteVersionFilename(target); } void SocketApi::emailPrivateLink(const QString &link) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 40a22090c..864a99bb4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -63,6 +63,7 @@ nextcloud_add_benchmark(LargeSync "syncenginetestutils.h") SET(FolderMan_SRC ../src/gui/folderman.cpp) list(APPEND FolderMan_SRC ../src/gui/folder.cpp ) +list(APPEND FolderMan_SRC ../src/gui/conflictsolver.cpp ) list(APPEND FolderMan_SRC ../src/gui/socketapi.cpp ) list(APPEND FolderMan_SRC ../src/gui/syncrunfilelog.cpp ) list(APPEND FolderMan_SRC ../src/gui/lockwatcher.cpp ) @@ -85,6 +86,7 @@ list(APPEND RemoteWipe_SRC ../src/gui/connectionvalidator.cpp ) list(APPEND RemoteWipe_SRC ../src/gui/ocsjob.cpp ) list(APPEND RemoteWipe_SRC ../src/gui/ocsnavigationappsjob.cpp ) list(APPEND RemoteWipe_SRC ../src/gui/accountstate.cpp ) +list(APPEND RemoteWipe_SRC ../src/gui/conflictsolver.cpp ) list(APPEND RemoteWipe_SRC ../src/gui/socketapi.cpp ) list(APPEND RemoteWipe_SRC ../src/gui/folder.cpp ) list(APPEND RemoteWipe_SRC ../src/gui/syncrunfilelog.cpp )