1 /*
2 * Copyright (C) by Kevin Ottens <kevin.ottens@nextcloud.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 */
14
15 #include "conflictsolver.h"
16
17 #include <QFileDialog>
18 #include <QMessageBox>
19
20 #include "common/utility.h"
21 #include "filesystem.h"
22
23 namespace OCC {
24
25 Q_LOGGING_CATEGORY(lcConflict, "nextcloud.gui.conflictsolver", QtInfoMsg)
26
ConflictSolver(QWidget * parent)27 ConflictSolver::ConflictSolver(QWidget *parent)
28 : QObject(parent)
29 , _parentWidget(parent)
30 {
31 }
32
localVersionFilename() const33 QString ConflictSolver::localVersionFilename() const
34 {
35 return _localVersionFilename;
36 }
37
remoteVersionFilename() const38 QString ConflictSolver::remoteVersionFilename() const
39 {
40 return _remoteVersionFilename;
41 }
42
exec(ConflictSolver::Solution solution)43 bool ConflictSolver::exec(ConflictSolver::Solution solution)
44 {
45 switch (solution) {
46 case KeepLocalVersion:
47 return overwriteRemoteVersion();
48 case KeepRemoteVersion:
49 return deleteLocalVersion();
50 case KeepBothVersions:
51 return renameLocalVersion();
52 }
53 Q_UNREACHABLE();
54 return false;
55 }
56
setLocalVersionFilename(const QString & localVersionFilename)57 void ConflictSolver::setLocalVersionFilename(const QString &localVersionFilename)
58 {
59 if (_localVersionFilename == localVersionFilename) {
60 return;
61 }
62
63 _localVersionFilename = localVersionFilename;
64 emit localVersionFilenameChanged();
65 }
66
setRemoteVersionFilename(const QString & remoteVersionFilename)67 void ConflictSolver::setRemoteVersionFilename(const QString &remoteVersionFilename)
68 {
69 if (_remoteVersionFilename == remoteVersionFilename) {
70 return;
71 }
72
73 _remoteVersionFilename = remoteVersionFilename;
74 emit remoteVersionFilenameChanged();
75 }
76
deleteLocalVersion()77 bool ConflictSolver::deleteLocalVersion()
78 {
79 if (_localVersionFilename.isEmpty()) {
80 return false;
81 }
82
83 QFileInfo info(_localVersionFilename);
84 if (!info.exists()) {
85 return false;
86 }
87
88 const auto message = info.isDir() ? tr("Do you want to delete the directory <i>%1</i> and all its contents permanently?").arg(info.dir().dirName())
89 : tr("Do you want to delete the file <i>%1</i> permanently?").arg(info.fileName());
90 const auto result = QMessageBox::question(_parentWidget, tr("Confirm deletion"), message, QMessageBox::Yes, QMessageBox::No);
91 if (result != QMessageBox::Yes)
92 return false;
93
94 if (info.isDir()) {
95 return FileSystem::removeRecursively(_localVersionFilename);
96 } else {
97 return QFile(_localVersionFilename).remove();
98 }
99 }
100
renameLocalVersion()101 bool ConflictSolver::renameLocalVersion()
102 {
103 if (_localVersionFilename.isEmpty()) {
104 return false;
105 }
106
107 QFileInfo info(_localVersionFilename);
108 if (!info.exists()) {
109 return false;
110 }
111
112 const auto renamePattern = [=] {
113 auto result = QString::fromUtf8(OCC::Utility::conflictFileBaseNameFromPattern(_localVersionFilename.toUtf8()));
114 const auto dotIndex = result.lastIndexOf('.');
115 return QString(result.left(dotIndex) + "_%1" + result.mid(dotIndex));
116 }();
117
118 const auto targetFilename = [=] {
119 uint i = 1;
120 auto result = renamePattern.arg(i);
121 while (QFileInfo::exists(result)) {
122 Q_ASSERT(i > 0);
123 i++;
124 result = renamePattern.arg(i);
125 }
126 return result;
127 }();
128
129 QString error;
130 if (FileSystem::uncheckedRenameReplace(_localVersionFilename, targetFilename, &error)) {
131 return true;
132 } else {
133 qCWarning(lcConflict) << "Rename error:" << error;
134 QMessageBox::warning(_parentWidget, tr("Error"), tr("Moving file failed:\n\n%1").arg(error));
135 return false;
136 }
137 }
138
overwriteRemoteVersion()139 bool ConflictSolver::overwriteRemoteVersion()
140 {
141 if (_localVersionFilename.isEmpty()) {
142 return false;
143 }
144
145 if (_remoteVersionFilename.isEmpty()) {
146 return false;
147 }
148
149 QFileInfo info(_localVersionFilename);
150 if (!info.exists()) {
151 return false;
152 }
153
154 QString error;
155 if (FileSystem::uncheckedRenameReplace(_localVersionFilename, _remoteVersionFilename, &error)) {
156 return true;
157 } else {
158 qCWarning(lcConflict) << "Rename error:" << error;
159 QMessageBox::warning(_parentWidget, tr("Error"), tr("Moving file failed:\n\n%1").arg(error));
160 return false;
161 }
162 }
163
164 } // namespace OCC
165