From: Kevin Ottens Date: Wed, 7 Oct 2020 15:51:18 +0000 (+0200) Subject: Add a conflict dialog to help the user solve them X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~12^2~22^2~95^2~5 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=49c478cd2aaef1533d0c19981f0968e6f8c49385;p=nextcloud-desktop.git Add a conflict dialog to help the user solve them Signed-off-by: Kevin Ottens --- diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 7ae36a983..000d00752 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -21,6 +21,7 @@ endif() set(client_UI_SRCS accountsettings.ui + conflictdialog.ui folderwizardsourcepage.ui folderwizardtargetpage.ui generalsettings.ui @@ -54,6 +55,7 @@ set(client_SRCS accountmanager.cpp accountsettings.cpp application.cpp + conflictdialog.cpp conflictsolver.cpp connectionvalidator.cpp folder.cpp diff --git a/src/gui/conflictdialog.cpp b/src/gui/conflictdialog.cpp new file mode 100644 index 000000000..bad4e7c2d --- /dev/null +++ b/src/gui/conflictdialog.cpp @@ -0,0 +1,181 @@ +/* + * 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 "conflictdialog.h" +#include "ui_conflictdialog.h" + +#include "conflictsolver.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace { +void forceHeaderFont(QWidget *widget) +{ + auto font = widget->font(); + font.setPointSizeF(font.pointSizeF() * 1.5); + widget->setFont(font); +} + +void setBoldFont(QWidget *widget, bool bold) +{ + auto font = widget->font(); + font.setBold(bold); + widget->setFont(font); +} +} + +namespace OCC { + +ConflictDialog::ConflictDialog(QWidget *parent) + : QDialog(parent) + , _ui(new Ui::ConflictDialog) + , _solver(new ConflictSolver(this)) +{ + _ui->setupUi(this); + forceHeaderFont(_ui->conflictMessage); + _ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + _ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Keep selected version")); + + connect(_ui->localVersionRadio, &QCheckBox::toggled, this, &ConflictDialog::updateButtonStates); + connect(_ui->localVersionButton, &QToolButton::clicked, this, [=] { + QDesktopServices::openUrl(QUrl::fromLocalFile(_solver->localVersionFilename())); + }); + + connect(_ui->remoteVersionRadio, &QCheckBox::toggled, this, &ConflictDialog::updateButtonStates); + connect(_ui->remoteVersionButton, &QToolButton::clicked, this, [=] { + QDesktopServices::openUrl(QUrl::fromLocalFile(_solver->remoteVersionFilename())); + }); + + connect(_solver, &ConflictSolver::localVersionFilenameChanged, this, &ConflictDialog::updateWidgets); + connect(_solver, &ConflictSolver::remoteVersionFilenameChanged, this, &ConflictDialog::updateWidgets); +} + +QString ConflictDialog::baseFilename() const +{ + return _baseFilename; +} + +ConflictDialog::~ConflictDialog() = default; + +QString ConflictDialog::localVersionFilename() const +{ + return _solver->localVersionFilename(); +} + +QString ConflictDialog::remoteVersionFilename() const +{ + return _solver->remoteVersionFilename(); +} + +void ConflictDialog::setBaseFilename(const QString &baseFilename) +{ + if (_baseFilename == baseFilename) { + return; + } + + _baseFilename = baseFilename; + _ui->conflictMessage->setText(tr("Conflicting versions of %1.").arg(_baseFilename)); +} + +void ConflictDialog::setLocalVersionFilename(const QString &localVersionFilename) +{ + _solver->setLocalVersionFilename(localVersionFilename); +} + +void ConflictDialog::setRemoteVersionFilename(const QString &remoteVersionFilename) +{ + _solver->setRemoteVersionFilename(remoteVersionFilename); +} + +void ConflictDialog::accept() +{ + const auto isLocalPicked = _ui->localVersionRadio->isChecked(); + const auto isRemotePicked = _ui->remoteVersionRadio->isChecked(); + + Q_ASSERT(isLocalPicked || isRemotePicked); + if (!isLocalPicked && !isRemotePicked) { + return; + } + + const auto solution = isLocalPicked && isRemotePicked ? ConflictSolver::KeepBothVersions + : isLocalPicked ? ConflictSolver::KeepLocalVersion + : ConflictSolver::KeepRemoteVersion; + if (_solver->exec(solution)) { + QDialog::accept(); + } +} + +void ConflictDialog::updateWidgets() +{ + QMimeDatabase mimeDb; + + const auto updateGroup = [this, &mimeDb](const QString &filename, QLabel *linkLabel, const QString &linkText, QLabel *mtimeLabel, QLabel *sizeLabel, QToolButton *button) { + const auto fileUrl = QUrl::fromLocalFile(filename).toString(); + linkLabel->setText(QStringLiteral("%2").arg(fileUrl).arg(linkText)); + + const auto info = QFileInfo(filename); + mtimeLabel->setText(info.lastModified().toString()); + sizeLabel->setText(locale().formattedDataSize(info.size())); + + const auto mime = mimeDb.mimeTypeForFile(filename); + if (QIcon::hasThemeIcon(mime.iconName())) { + button->setIcon(QIcon::fromTheme(mime.iconName())); + } else { + button->setIcon(QIcon(":/qt-project.org/styles/commonstyle/images/file-128.png")); + } + }; + + const auto localVersion = _solver->localVersionFilename(); + updateGroup(localVersion, + _ui->localVersionLink, + tr("Open local version"), + _ui->localVersionMtime, + _ui->localVersionSize, + _ui->localVersionButton); + + const auto remoteVersion = _solver->remoteVersionFilename(); + updateGroup(remoteVersion, + _ui->remoteVersionLink, + tr("Open remote version"), + _ui->remoteVersionMtime, + _ui->remoteVersionSize, + _ui->remoteVersionButton); + + const auto localMtime = QFileInfo(localVersion).lastModified(); + const auto remoteMtime = QFileInfo(remoteVersion).lastModified(); + + setBoldFont(_ui->localVersionMtime, localMtime > remoteMtime); + setBoldFont(_ui->remoteVersionMtime, remoteMtime > localMtime); +} + +void ConflictDialog::updateButtonStates() +{ + const auto isLocalPicked = _ui->localVersionRadio->isChecked(); + const auto isRemotePicked = _ui->remoteVersionRadio->isChecked(); + _ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(isLocalPicked || isRemotePicked); + + const auto text = isLocalPicked && isRemotePicked ? tr("Keep both versions") + : isLocalPicked ? tr("Keep local version") + : isRemotePicked ? tr("Keep server version") + : tr("Keep selected version"); + _ui->buttonBox->button(QDialogButtonBox::Ok)->setText(text); +} + +} // namespace OCC diff --git a/src/gui/conflictdialog.h b/src/gui/conflictdialog.h new file mode 100644 index 000000000..5c5b763b4 --- /dev/null +++ b/src/gui/conflictdialog.h @@ -0,0 +1,57 @@ +/* + * 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 CONFLICTDIALOG_H +#define CONFLICTDIALOG_H + +#include + +namespace OCC { + +class ConflictSolver; + +namespace Ui { + class ConflictDialog; +} + +class ConflictDialog : public QDialog +{ + Q_OBJECT +public: + explicit ConflictDialog(QWidget *parent = nullptr); + ~ConflictDialog() override; + + QString baseFilename() const; + QString localVersionFilename() const; + QString remoteVersionFilename() const; + +public slots: + void setBaseFilename(const QString &baseFilename); + void setLocalVersionFilename(const QString &localVersionFilename); + void setRemoteVersionFilename(const QString &remoteVersionFilename); + + void accept() override; + +private: + void updateWidgets(); + void updateButtonStates(); + + QString _baseFilename; + QScopedPointer _ui; + ConflictSolver *_solver; +}; + +} // namespace OCC + +#endif // CONFLICTDIALOG_H diff --git a/src/gui/conflictdialog.ui b/src/gui/conflictdialog.ui new file mode 100644 index 000000000..bd69c60e8 --- /dev/null +++ b/src/gui/conflictdialog.ui @@ -0,0 +1,305 @@ + + + OCC::ConflictDialog + + + + 0 + 0 + 504 + 407 + + + + Sync Conflict + + + + + + Conflicting versions of %1. + + + + + + + 16 + + + + + Which version of the file do you want to keep?<br/>If you select both versions, the local file will have a number added to its name. + + + + + + + 16 + + + + + + + Local version + + + + + + + + + + + Click to open the file + + + + + + + 64 + 64 + + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + 0 + + + + + today + + + + + + + 0 byte + + + + + + + <a href="%1">Open local version</a> + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + Server version + + + + + + + + + + + Click to open the file + + + + + + + 64 + 64 + + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + 0 + + + + + today + + + + + + + 0 byte + + + + + + + <a href="%1">Open server version</a> + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + OCC::ConflictDialog + accept() + + + 123 + 218 + + + 148 + 248 + + + + + buttonBox + rejected() + OCC::ConflictDialog + reject() + + + 181 + 215 + + + 240 + 254 + + + + +