Skip to content

Commit

Permalink
Merge pull request #390 from Infomaniak/KDESKTOP-963-Error-Handling-f…
Browse files Browse the repository at this point in the history
…or-Move-to-Trash-Operation-on-Windows

Fix MoveToTrashFailed behaviour
  • Loading branch information
ChristopheLarchier authored Dec 23, 2024
2 parents da6d653 + 298a03f commit 9717ce3
Show file tree
Hide file tree
Showing 12 changed files with 139 additions and 60 deletions.
1 change: 1 addition & 0 deletions config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@

#cmakedefine LEARNMORE_LITESYNC_URL "@LEARNMORE_LITESYNC_URL@"
#cmakedefine LEARNMORE_LITESYNC_COMPATIBILITY_URL "@LEARNMORE_LITESYNC_COMPATIBILITY_URL@"
#cmakedefine LEARNMORE_MOVE_TO_TRASH_URL "@LEARNMORE_MOVE_TO_TRASH_URL@"

#cmakedefine CMAKE_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@"
#cmakedefine BIN_INSTALL_DIR "@BIN_INSTALL_DIR@"
Expand Down
3 changes: 2 additions & 1 deletion infomaniak/kDrive.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,15 @@ set( APPLICATION_LICENSE "${KDRIVE_THEME_DIR}/license.txt" )

set( DEBUGREPORTER_SUBMIT_URL "https://www.infomaniak.com/report/drive/logs" CACHE STRING "URL for debug reporter" )

set( LEARNMORE_MOVE_TO_TRASH_URL "https://faq.infomaniak.com/2383#desktop" CACHE STRING "URL for move to trash exception FAQ" )

if( APPLE )
set( LEARNMORE_LITESYNC_URL "https://faq.infomaniak.com/2608" CACHE STRING "URL for Lite Sync FAQ" )
set( LEARNMORE_LITESYNC_COMPATIBILITY_URL "https://faq.infomaniak.com/2608" CACHE STRING "URL for Lite Sync compatibility FAQ" )
else()
set( LEARNMORE_LITESYNC_URL "https://faq.infomaniak.com/2562" CACHE STRING "URL for Lite Sync FAQ" )
set( LEARNMORE_LITESYNC_COMPATIBILITY_URL "https://faq.infomaniak.com/2523" CACHE STRING "URL for Lite Sync compatibility FAQ" )
endif()

# Sentry
set( SENTRY_SERVER_DSN "https://af2cd6793efb2b73683ff24abebed911@sentry-desktop.infomaniak.com/2" )
set( SENTRY_CLIENT_DSN "https://1435053ba7740a09682093f424dfaf79@sentry-desktop.infomaniak.com/3" )
Expand Down
85 changes: 61 additions & 24 deletions src/gui/fixconflictingfilesdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
#include "customtoolbutton.h"
#include "guirequests.h"
#include "libcommon/theme/theme.h"

#include "libcommon/utility/utility.h"
#include "guiutility.h"
#include "config.h"
#include <algorithm>

#include <QDesktopServices>
Expand Down Expand Up @@ -60,6 +62,12 @@ void FixConflictingFilesDialog::onLinkActivated(const QString &link) {
QMessageBox::Ok, this);
msgBox.exec();
}
} else {
if (!QDesktopServices::openUrl(QUrl(link))) {
CustomMessageBox msgBox(QMessageBox::Warning, tr("Unable to open link %1.").arg(link),
QMessageBox::Ok, this);
msgBox.exec();
}
}
}

Expand Down Expand Up @@ -87,22 +95,26 @@ void FixConflictingFilesDialog::onValidate() {
accept();
}

void FixConflictingFilesDialog::onKeepRemoteButtonToggled(bool checked) {
_keepRemoteDisclaimerWidget->setVisible(checked);
}

void FixConflictingFilesDialog::initUi() {
setObjectName("ResolveConflictsDialog");

QVBoxLayout *mainLayout = this->mainLayout();
mainLayout->setContentsMargins(boxHMargin, 0, boxHMargin, boxVMargin);

// Title
auto titleLabel = new QLabel(this);
const auto titleLabel = new QLabel(this);
titleLabel->setObjectName("titleLabel");
titleLabel->setText(tr("Solve conflict(s)"));

mainLayout->addWidget(titleLabel);
mainLayout->addSpacing(titleBoxVMargin);

// Description
auto textLabel = new QLabel(this);
const auto textLabel = new QLabel(this);
textLabel->setObjectName("textLabel");
textLabel->setWordWrap(true);
textLabel->setText(descriptionText());
Expand All @@ -112,32 +124,58 @@ void FixConflictingFilesDialog::initUi() {
mainLayout->addWidget(textLabel);

// Selection buttons
auto selectionLabel = new QLabel(this);
const auto selectionLabel = new QLabel(this);
selectionLabel->setObjectName("descriptionLabel");
selectionLabel->setText(tr("<b>What do you want to do with the %1 conflicted item(s) that is(are) not synced in kDrive?</b>")
.arg(_conflictList.length()));
selectionLabel->setText(tr("<b>What do you want to do with the %1 conflicted item(s)?</b>").arg(_conflictList.length()));

_keepLocalButton = new CustomRadioButton(this);
_keepLocalButton->setText(tr("Synchronize the local version of my item(s) in kDrive."));
_keepLocalButton->setText(tr("Save my changes and replace other users' versions."));
_keepLocalButton->setChecked(true);

_keepRemoteButton = new CustomRadioButton(this);
_keepRemoteButton->setText(tr("Undo my changes and keep other users' versions."));
connect(_keepRemoteButton, &CustomRadioButton::toggled, this, &FixConflictingFilesDialog::onKeepRemoteButtonToggled);

_keepRemoteDisclaimerWidget = new QWidget();
_keepRemoteDisclaimerWidget->setStyleSheet("background-color: #F4F6FD; border-radius: 5px;");
const auto keepLocalDisclaimerLayout = new QHBoxLayout(_keepRemoteDisclaimerWidget);
const auto warningIconLabel = new QLabel();
warningIconLabel->setPixmap(
KDC::GuiUtility::getIconWithColor(":/client/resources/icons/actions/warning.svg", QColor(255, 140, 0))
.pixmap(20, 20));
warningIconLabel->setContentsMargins(0, 0, boxHMargin / 4, 0);
keepLocalDisclaimerLayout->addWidget(warningIconLabel);

const auto keepRemoteDisclaimerLabel = new QLabel();
keepRemoteDisclaimerLabel->setWordWrap(true);
keepLocalDisclaimerLayout->addWidget(keepRemoteDisclaimerLabel);


if (ParametersCache::instance()->parametersInfo().moveToTrash()) {
_keepRemoteButton->setText(tr("Move the local version of my item(s) to the computer's trash."));
const auto keepRemoteDisclaimerLearnMoreLabel = new QLabel();
connect(keepRemoteDisclaimerLearnMoreLabel, &QLabel::linkActivated, this, &FixConflictingFilesDialog::onLinkActivated);
keepRemoteDisclaimerLabel->setText(
tr("Your changes may be permanently deleted. They cannot be restored from the kDrive web application."));
keepRemoteDisclaimerLearnMoreLabel->setText(
tr("<a style=%1 href=\"%2\">Learn more</a>").arg(CommonUtility::linkStyle, LEARNMORE_MOVE_TO_TRASH_URL));
keepLocalDisclaimerLayout->addWidget(keepRemoteDisclaimerLearnMoreLabel);
} else {
_keepRemoteButton->setText(tr("Permanently delete the local version of my item(s)."));
keepRemoteDisclaimerLabel->setText(
tr("Your changes will be permanently deleted. They cannot be restored from the kDrive web application."));
}

keepLocalDisclaimerLayout->setStretchFactor(keepRemoteDisclaimerLabel, 1);
_keepRemoteDisclaimerWidget->hide();
auto selectionLayout = new QVBoxLayout(this);
selectionLayout->setContentsMargins(0, 4 * boxVMargin, 0, boxVMargin);
selectionLayout->setSpacing(boxHSpacing);
selectionLayout->addWidget(selectionLabel);
selectionLayout->addWidget(_keepLocalButton);
selectionLayout->addWidget(_keepRemoteButton);
selectionLayout->addWidget(_keepRemoteDisclaimerWidget);
mainLayout->addLayout(selectionLayout);

// Details
auto detailsLabel = new QLabel(this);
const auto detailsLabel = new QLabel(this);
detailsLabel->setObjectName("descriptionLabel");
detailsLabel->setText(tr("Show item(s)"));

Expand All @@ -146,7 +184,7 @@ void FixConflictingFilesDialog::initUi() {
_expandButton->setIconPath(":/client/resources/icons/actions/chevron-down.svg");
connect(_expandButton, &CustomToolButton::clicked, this, &FixConflictingFilesDialog::onExpandButtonClicked);

auto detailsLabelLayout = new QHBoxLayout(this);
const auto detailsLabelLayout = new QHBoxLayout(this);
detailsLabelLayout->addWidget(detailsLabel);
detailsLabelLayout->addSpacing(5);
detailsLabelLayout->addWidget(_expandButton);
Expand All @@ -161,31 +199,31 @@ void FixConflictingFilesDialog::initUi() {

_stackedWidget = new QStackedWidget(this);

auto dummyWidget = new QWidget(this);
const auto dummyWidget = new QWidget(this);
dummyWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
_stackedWidget->insertWidget(0, dummyWidget);
_stackedWidget->insertWidget(1, _fileListWidget);

auto detailsLayout = new QVBoxLayout(this);
const auto detailsLayout = new QVBoxLayout(this);
detailsLayout->setContentsMargins(0, 2 * boxVMargin, 0, boxVMargin);
detailsLayout->addLayout(detailsLabelLayout);
detailsLayout->addWidget(_stackedWidget);
mainLayout->addLayout(detailsLayout);

// Validation buttons
auto validateButton = new QPushButton(this);
const auto validateButton = new QPushButton(this);
validateButton->setObjectName("defaultbutton");
validateButton->setFlat(true);
validateButton->setText(tr("VALIDATE"));
connect(validateButton, &QPushButton::clicked, this, &FixConflictingFilesDialog::onValidate);

auto cancelButton = new QPushButton(this);
const auto cancelButton = new QPushButton(this);
cancelButton->setObjectName("nondefaultbutton");
cancelButton->setFlat(true);
cancelButton->setText(tr("CANCEL"));
connect(cancelButton, &QPushButton::clicked, this, &FixConflictingFilesDialog::reject);

auto buttonsLayout = new QHBoxLayout();
const auto buttonsLayout = new QHBoxLayout();
buttonsLayout->setContentsMargins(0, 0, 0, boxVMargin);
buttonsLayout->setSpacing(boxHSpacing);
buttonsLayout->addWidget(validateButton);
Expand All @@ -198,10 +236,9 @@ void FixConflictingFilesDialog::initUi() {

QString FixConflictingFilesDialog::descriptionText() const {
QString str;
str = tr(
"When an item has been modified on both the computer and the kDrive or when an item has been created on the computer "
"with a name that already exists on the kDrive, "
"kDrive renames your local item and downloads kDrive's version on your computer so as not to lose any data.<br>");
str =
tr("Modifications have been made to these files by several users in several places (online on kDrive, a computer or "
"a mobile). Folders containing these files may also have been deleted.<br>");
str += tr("The local version of your item <b>is not synced</b> with kDrive. <a style=\"color: #489EF3\" href=\"%1\">Learn "
"more</a>")
.arg(learnMoreLink);
Expand All @@ -210,11 +247,11 @@ QString FixConflictingFilesDialog::descriptionText() const {
}

void FixConflictingFilesDialog::insertFileItems(const int nbItems) {
int max = std::min(_fileListWidget->count() + nbItems, static_cast<int>(_conflictList.size()));
int max = (std::min)(_fileListWidget->count() + nbItems, static_cast<int>(_conflictList.size()));
for (auto i = _fileListWidget->count(); i < max; i++) {
auto w = new FileItemWidget(_conflictList[i].destinationPath(), _conflictList[i].nodeType(), this);
const auto w = new FileItemWidget(_conflictList[i].destinationPath(), _conflictList[i].nodeType(), this);

auto listWidgetItem = new QListWidgetItem();
const auto listWidgetItem = new QListWidgetItem();
listWidgetItem->setFlags(Qt::NoItemFlags);
listWidgetItem->setForeground(Qt::transparent);
_fileListWidget->insertItem(i, listWidgetItem);
Expand Down
2 changes: 2 additions & 0 deletions src/gui/fixconflictingfilesdialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class FixConflictingFilesDialog : public CustomDialog {
void onExpandButtonClicked();
void onScrollBarValueChanged();
void onValidate();
void onKeepRemoteButtonToggled(bool checked);

private:
void initUi();
Expand All @@ -57,6 +58,7 @@ class FixConflictingFilesDialog : public CustomDialog {
QStackedWidget *_stackedWidget = nullptr;
CustomRadioButton *_keepLocalButton = nullptr;
CustomRadioButton *_keepRemoteButton = nullptr;
QWidget *_keepRemoteDisclaimerWidget = nullptr;
CustomToolButton *_expandButton = nullptr;
QListWidget *_fileListWidget = nullptr;
};
Expand Down
4 changes: 0 additions & 4 deletions src/gui/parametersdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -826,10 +826,6 @@ QString ParametersDialog::getErrorLevelNodeText(const ErrorInfo &errorInfo) cons
"Can't access item.<br>"
"Please fix the read and write permissions.");
}

if (errorInfo.exitCause() == ExitCause::MoveToTrashFailed) {
return tr("Move to trash failed.");
}
return tr("System error.");
}
case ExitCode::BackError: {
Expand Down
57 changes: 46 additions & 11 deletions src/gui/preferenceswidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ static constexpr int textHSpacing = 10;
static constexpr int amountLineEditWidth = 85;

static const QString debuggingFolderLink = "debuggingFolderLink";
static const QString moveToTrashFAQLink = "https://faq.infomaniak.com/2383#desktop";

static const QString englishCode = "en";
static const QString frenchCode = "fr";
Expand Down Expand Up @@ -115,6 +116,7 @@ void LargeFolderConfirmation::setAmountLineEditEnabled(bool enabled) {
PreferencesWidget::PreferencesWidget(std::shared_ptr<ClientGui> gui, QWidget *parent) :
LargeWidgetWithCustomToolTip(parent), _gui(gui), _languageSelectorComboBox{new CustomComboBox()}, _generalLabel{new QLabel()},
_monochromeLabel{new QLabel()}, _launchAtStartupLabel{new QLabel()}, _moveToTrashLabel{new QLabel()},
_moveToTrashTipsLabel{new QLabel()}, _moveToTrashDisclaimerLabel{new QLabel()}, _moveToTrashKnowMoreLabel{new QLabel()},
_languageSelectorLabel{new QLabel()}, _advancedLabel{new QLabel()}, _debuggingLabel{new QLabel()},
_debuggingFolderLabel{new QLabel()}, _filesToExcludeLabel{new QLabel()}, _proxyServerLabel{new QLabel()},
_displayErrorsWidget{new ActionWidget(":/client/resources/icons/actions/warning.svg", "")} {
Expand Down Expand Up @@ -170,7 +172,7 @@ PreferencesWidget::PreferencesWidget(std::shared_ptr<ClientGui> gui, QWidget *pa
* _versionWidget->_updateButton
*/

auto *vBox = new QVBoxLayout();
const auto vBox = new QVBoxLayout();
vBox->setContentsMargins(boxHMargin, boxVMargin, boxHMargin, boxVMargin);
vBox->setSpacing(boxSpacing);
setLayout(vBox);
Expand All @@ -188,7 +190,7 @@ PreferencesWidget::PreferencesWidget(std::shared_ptr<ClientGui> gui, QWidget *pa
_generalLabel->setObjectName("blocLabel");
vBox->addWidget(_generalLabel);

auto generalBloc = new PreferencesBlocWidget();
const auto generalBloc = new PreferencesBlocWidget();
vBox->addWidget(generalBloc);

// Synchronization confirmation for large folders
Expand Down Expand Up @@ -220,7 +222,7 @@ PreferencesWidget::PreferencesWidget(std::shared_ptr<ClientGui> gui, QWidget *pa
monochromeIconsBox->addWidget(_monochromeLabel);
monochromeIconsBox->addStretch();

auto monochromeSwitch = new CustomSwitch();
const auto monochromeSwitch = new CustomSwitch();
monochromeSwitch->setLayoutDirection(Qt::RightToLeft);
monochromeSwitch->setAttribute(Qt::WA_MacShowFocusRect, false);
monochromeSwitch->setCheckState(ParametersCache::instance()->parametersInfo().monoIcons() ? Qt::Checked : Qt::Unchecked);
Expand All @@ -233,7 +235,7 @@ PreferencesWidget::PreferencesWidget(std::shared_ptr<ClientGui> gui, QWidget *pa
launchAtStartupBox->addWidget(_launchAtStartupLabel);
launchAtStartupBox->addStretch();

auto launchAtStartupSwitch = new CustomSwitch();
const auto launchAtStartupSwitch = new CustomSwitch();
launchAtStartupSwitch->setLayoutDirection(Qt::RightToLeft);
launchAtStartupSwitch->setAttribute(Qt::WA_MacShowFocusRect, false);
bool hasSystemLauchAtStartup = false;
Expand All @@ -257,20 +259,48 @@ PreferencesWidget::PreferencesWidget(std::shared_ptr<ClientGui> gui, QWidget *pa
generalBloc->addSeparator();

// Move file to trash
QBoxLayout *moveToTrashBox = generalBloc->addLayout(QBoxLayout::Direction::LeftToRight);

moveToTrashBox->addWidget(_moveToTrashLabel);
moveToTrashBox->addStretch();
const auto moveToTrashBox = generalBloc->addLayout(QBoxLayout::Direction::LeftToRight, true);
moveToTrashBox->setContentsMargins(boxHMargin, boxVMargin, boxHMargin, boxVMargin / 2);
const auto moveToTrashTitleBox = new QVBoxLayout();
moveToTrashTitleBox->setContentsMargins(0, 0, 0, 0);
_moveToTrashTipsLabel->setWordWrap(true);
_moveToTrashTipsLabel->setObjectName("description");
moveToTrashTitleBox->addWidget(_moveToTrashLabel);
moveToTrashTitleBox->addWidget(_moveToTrashTipsLabel);
moveToTrashBox->addLayout(moveToTrashTitleBox);

const auto moveToTrashSwitch = new CustomSwitch();
moveToTrashSwitch->setLayoutDirection(Qt::RightToLeft);
moveToTrashSwitch->setAttribute(Qt::WA_MacShowFocusRect, false);
moveToTrashSwitch->setCheckState(ParametersCache::instance()->parametersInfo().moveToTrash() ? Qt::Checked : Qt::Unchecked);
moveToTrashSwitch->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
moveToTrashBox->addWidget(moveToTrashSwitch);

// Move file to trash disclaimer
_moveTotrashDisclaimerWidget = new QWidget();
_moveTotrashDisclaimerWidget->setStyleSheet("background-color: #F4F6FD; border-radius: 5px;");
_moveTotrashDisclaimerWidget->setVisible(moveToTrashSwitch->isChecked());
const auto moveToTrashDisclaimerHBox = new QHBoxLayout(_moveTotrashDisclaimerWidget);
moveToTrashDisclaimerHBox->setContentsMargins(boxHMargin, boxVMargin, boxHMargin, boxVMargin);

const auto warningIconLabel = new QLabel();
warningIconLabel->setPixmap(
KDC::GuiUtility::getIconWithColor(":/client/resources/icons/actions/warning.svg", QColor(255, 140, 0))
.pixmap(20, 20));
warningIconLabel->setContentsMargins(0, 0, textHSpacing, 0);
moveToTrashDisclaimerHBox->addWidget(warningIconLabel);
_moveToTrashDisclaimerLabel->setWordWrap(true);
moveToTrashDisclaimerHBox->addWidget(_moveToTrashDisclaimerLabel);
moveToTrashDisclaimerHBox->addStretch();
moveToTrashDisclaimerHBox->addWidget(_moveToTrashKnowMoreLabel);
moveToTrashDisclaimerHBox->setStretchFactor(_moveToTrashDisclaimerLabel, 1);
const auto moveToTrashDisclaimerBox = generalBloc->addLayout(QBoxLayout::Direction::LeftToRight, true);
moveToTrashDisclaimerBox->setContentsMargins(boxHMargin, 0, boxHMargin, boxVMargin / 2);
moveToTrashDisclaimerBox->addWidget(_moveTotrashDisclaimerWidget);
generalBloc->addSeparator();

// Languages
QBoxLayout *languageSelectorBox = generalBloc->addLayout(QBoxLayout::Direction::LeftToRight);
const auto languageSelectorBox = generalBloc->addLayout(QBoxLayout::Direction::LeftToRight);

languageSelectorBox->addWidget(_languageSelectorLabel);
languageSelectorBox->addStretch();
Expand Down Expand Up @@ -367,6 +397,7 @@ PreferencesWidget::PreferencesWidget(std::shared_ptr<ClientGui> gui, QWidget *pa
connect(launchAtStartupSwitch, &CustomSwitch::clicked, this, &PreferencesWidget::onLaunchAtStartupSwitchClicked);
connect(_languageSelectorComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onLanguageChange()));
connect(moveToTrashSwitch, &CustomSwitch::clicked, this, &PreferencesWidget::onMoveToTrashSwitchClicked);
connect(_moveToTrashKnowMoreLabel, &QLabel::linkActivated, this, &PreferencesWidget::onLinkActivated);
#ifdef Q_OS_WIN
connect(shortcutsSwitch, &CustomSwitch::clicked, this, &PreferencesWidget::onShortcutsSwitchClicked);
#endif
Expand Down Expand Up @@ -478,6 +509,7 @@ void PreferencesWidget::onMoveToTrashSwitchClicked(bool checked) {
if (!ParametersCache::instance()->saveParametersInfo()) {
return;
}
_moveTotrashDisclaimerWidget->setVisible(checked);
}

#ifdef Q_OS_WIN
Expand Down Expand Up @@ -564,8 +596,11 @@ void PreferencesWidget::retranslateUi() const {
_monochromeLabel->setText(tr("Activate monochrome icons"));
_launchAtStartupLabel->setText(tr("Launch kDrive at startup"));
_languageSelectorLabel->setText(tr("Language"));
_moveToTrashLabel->setText(tr("Move deleted files to trash"));

_moveToTrashLabel->setText(tr("Move deleted files to my computer's trash"));
_moveToTrashDisclaimerLabel->setText(tr("Some files or folders may not be moved to the computer's trash."));
_moveToTrashTipsLabel->setText(tr("You can always retrieve already synced files from the kDrive web application trash."));
_moveToTrashKnowMoreLabel->setText(
tr(R"(<a style="%1" href="%2">Learn more</a>)").arg(CommonUtility::linkStyle, LEARNMORE_MOVE_TO_TRASH_URL));
_languageSelectorComboBox->blockSignals(true); // To avoid triggering more LanguageChange events
_languageSelectorComboBox->clear();
_languageSelectorComboBox->addItem(tr("Default"), toInt(Language::Default));
Expand Down
Loading

0 comments on commit 9717ce3

Please sign in to comment.