diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index b68e5fd9287e4..20ed138bb6ed4 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -33,6 +33,9 @@ endif() configure_file(${CMAKE_SOURCE_DIR}/theme.qrc.in ${CMAKE_SOURCE_DIR}/theme.qrc) set(theme_dir ${CMAKE_SOURCE_DIR}/theme) +#NMC customization: needed to find the ui file in a different location than the header file +set(CMAKE_AUTOUIC_SEARCH_PATHS "${CMAKE_SOURCE_DIR}/src/gui") + set(client_UI_SRCS advancedsettings.ui accountsettings.ui @@ -248,6 +251,10 @@ set(client_SRCS integration/fileactionsmodel.cpp ) +file(GLOB NMC_FILES "nmcgui/*") +set(NMC_SRCS ${NMC_FILES}) +list(APPEND client_SRCS ${NMC_SRCS}) + if (NOT DISABLE_ACCOUNT_MIGRATION) list(APPEND client_SRCS legacyaccountselectiondialog.h diff --git a/src/gui/generalsettings.h b/src/gui/generalsettings.h index 9b69b94e59d99..ece7afe50d16b 100644 --- a/src/gui/generalsettings.h +++ b/src/gui/generalsettings.h @@ -28,6 +28,12 @@ class GeneralSettings : public QWidget ~GeneralSettings() override; [[nodiscard]] QSize sizeHint() const override; +protected: + Ui::GeneralSettings *getUi() const + { + return _ui; + } + public slots: void slotStyleChanged(); diff --git a/src/gui/ignorelisteditor.ui b/src/gui/ignorelisteditor.ui index f61e6119c4500..500af406fb463 100644 --- a/src/gui/ignorelisteditor.ui +++ b/src/gui/ignorelisteditor.ui @@ -37,7 +37,7 @@ - Global Ignore Settings + @@ -109,7 +109,7 @@ - Files Ignored by Patterns + diff --git a/src/gui/nmcgui/nmcgeneralsettings.cpp b/src/gui/nmcgui/nmcgeneralsettings.cpp new file mode 100644 index 0000000000000..f12dded9aede3 --- /dev/null +++ b/src/gui/nmcgui/nmcgeneralsettings.cpp @@ -0,0 +1,346 @@ +/* + * Copyright (C) by Mauro Mura + * + * 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. + */ + +#include "nmcgeneralsettings.h" +#include "generalsettings.h" +#include "configfile.h" +#include "ignorelisteditor.h" +#include "nmclibsync/nmcconfigfile.h" +#include "settingspanelstyle.h" +#include "theme.h" +#include "ui_generalsettings.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_OS_WIN +#define BACKGROUND_PALETTE "alternate-base" +#else +#define BACKGROUND_PALETTE "light" +#endif + +namespace OCC { + +namespace { + +void applyNMCBoxStyle(QGroupBox *box, const QString &objectName) +{ + box->setObjectName(objectName); + box->setAttribute(Qt::WA_StyledBackground, true); + box->setTitle({}); + box->setStyleSheet(QStringLiteral( + "#%1 {" + " background: palette(" BACKGROUND_PALETTE ");" + " border-radius: 4px;" + " border: none;" + "}" + ).arg(objectName)); +} + +QLabel *createSectionLabel(const QString &text, QWidget *parent) +{ + auto *label = new QLabel(text, parent); + label->setStyleSheet(QStringLiteral("font-size: 12px; font-weight: bold;")); + return label; +} + +QLabel *createLinkLabel(const QString &text, const QString &url, QWidget *parent) +{ + auto *label = new QLabel(parent); + label->setText(QStringLiteral("%2").arg(url, text)); + label->setTextFormat(Qt::RichText); + label->setTextInteractionFlags(Qt::TextBrowserInteraction); + label->setOpenExternalLinks(true); + label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + label->setStyleSheet(QStringLiteral("font-size: 13px")); + return label; +} + +} // namespace + +NMCGeneralSettings::NMCGeneralSettings(QWidget *parent) + : GeneralSettings(parent) +{ + setDefaultSettings(); + setNMCLayout(); +} + +void NMCGeneralSettings::setDefaultSettings() +{ + // These options are still present in the new upstream UI, but should not be shown in NMC. + getUi()->monoIconsCheckBox->setVisible(false); + getUi()->monoIconsLabel->setVisible(false); + getUi()->monoIconsRowWidget->setVisible(false); + getUi()->startupSeparator->setVisible(false); + + getUi()->chatNotificationsCheckBox->setVisible(false); + getUi()->chatNotificationsLabel->setVisible(false); + getUi()->chatNotificationsSeparator->setVisible(false); + + getUi()->callNotificationsCheckBox->setVisible(false); + getUi()->callNotificationsLabel->setVisible(false); + getUi()->callNotificationsSeparator->setVisible(false); + + getUi()->quotaWarningNotificationsCheckBox->setVisible(false); + getUi()->quotaWarningNotificationsLabel->setVisible(false); +} + +void NMCGeneralSettings::setNMCLayout() +{ + SettingsPanelStyle::apply(this); + + /* + * General settings + */ + auto *generalSettingsLabel = createSectionLabel( + QCoreApplication::translate("", "GENERAL_SETTINGS"), + this); + + getUi()->generalGroupBox->setTitle({}); + getUi()->generalGroupBox->setObjectName(QStringLiteral("nmcGeneralSettingsBox")); + getUi()->generalGroupBox->setAttribute(Qt::WA_StyledBackground, true); + getUi()->generalGroupBox->setStyleSheet(QStringLiteral( + "#nmcGeneralSettingsBox {" + " background: palette(" BACKGROUND_PALETTE ");" + " border-radius: 4px;" + " border: none;" + "}" + )); + + auto *generalLayout = qobject_cast(getUi()->generalGroupBox->layout()); + if (generalLayout) { + generalLayout->insertWidget(0, generalSettingsLabel); + generalLayout->setContentsMargins(16, 16, 16, 16); + generalLayout->setSpacing(8); + } + + getUi()->autostartCheckBox->setFocusPolicy(Qt::NoFocus); + getUi()->serverNotificationsCheckBox->setFocusPolicy(Qt::NoFocus); + + /* + * Hide notification group if only hidden options would remain. + * Server notifications are moved/kept in the new notification group. + */ + getUi()->notificationsGroupBox->setObjectName(QStringLiteral("nmcNotificationsSettingsBox")); + getUi()->notificationsGroupBox->setAttribute(Qt::WA_StyledBackground, true); + getUi()->notificationsGroupBox->setStyleSheet(QStringLiteral( + "#nmcNotificationsSettingsBox {" + " background: palette(" BACKGROUND_PALETTE ");" + " border-radius: 4px;" + " border: none;" + "}" + )); + + if (auto *notificationsLayout = qobject_cast(getUi()->notificationsGroupBox->layout())) { + notificationsLayout->setContentsMargins(16, 16, 16, 16); + notificationsLayout->setSpacing(8); + } + + /* + * Advanced settings + * These widgets no longer exist in upstream generalsettings.ui, so we create them ourselves. + */ + auto *advancedSettingsBox = new QGroupBox(this); + applyNMCBoxStyle(advancedSettingsBox, QStringLiteral("nmcAdvancedSettingsBox")); + + auto *advancedLayout = new QVBoxLayout(advancedSettingsBox); + advancedLayout->setContentsMargins(16, 16, 16, 16); + advancedLayout->setSpacing(8); + + auto *advancedSettingsLabel = createSectionLabel( + QCoreApplication::translate("", "ADVANCED_SETTINGS"), + advancedSettingsBox); + + ConfigFile cfgFile; + + auto *newFolderLimitCheckBox = new QCheckBox( + tr("Ask for confirmation before synchronizing new folders larger than"), + advancedSettingsBox); + newFolderLimitCheckBox->setFocusPolicy(Qt::NoFocus); + + auto *newFolderLimitSpinBox = new QSpinBox(advancedSettingsBox); + newFolderLimitSpinBox->setMaximum(999999); + newFolderLimitSpinBox->setFocusPolicy(Qt::ClickFocus); + newFolderLimitSpinBox->setKeyboardTracking(true); + + auto *newFolderLimitLabel = new QLabel(tr("MB"), advancedSettingsBox); + + const auto newFolderLimit = cfgFile.newBigFolderSizeLimit(); + newFolderLimitCheckBox->setChecked(newFolderLimit.first); + newFolderLimitSpinBox->setValue(newFolderLimit.second); + newFolderLimitSpinBox->setEnabled(newFolderLimit.first); + + auto *newFolderLimitWidget = new QWidget(advancedSettingsBox); + auto *newFolderLimitLayout = new QHBoxLayout(newFolderLimitWidget); + newFolderLimitLayout->setContentsMargins(0, 0, 0, 0); + newFolderLimitLayout->setSpacing(8); + newFolderLimitLayout->addWidget(newFolderLimitCheckBox); + newFolderLimitLayout->addWidget(newFolderLimitSpinBox); + newFolderLimitLayout->addWidget(newFolderLimitLabel); + newFolderLimitLayout->addStretch(); + + connect(newFolderLimitCheckBox, &QAbstractButton::toggled, + newFolderLimitSpinBox, &QWidget::setEnabled); + + connect(newFolderLimitCheckBox, &QAbstractButton::toggled, this, + [newFolderLimitSpinBox](bool enabled) { + ConfigFile().setNewBigFolderSizeLimit(enabled, newFolderLimitSpinBox->value()); + }); + + connect(newFolderLimitSpinBox, &QSpinBox::valueChanged, this, + [newFolderLimitCheckBox](int value) { + ConfigFile().setNewBigFolderSizeLimit(newFolderLimitCheckBox->isChecked(), value); + }); + + auto *moveFilesToTrashCheckBox = new QCheckBox( + tr("Move removed files to trash"), + advancedSettingsBox); + moveFilesToTrashCheckBox->setFocusPolicy(Qt::NoFocus); + moveFilesToTrashCheckBox->setChecked(cfgFile.moveToTrash()); + + connect(moveFilesToTrashCheckBox, &QAbstractButton::toggled, this, + [](bool enabled) { + ConfigFile().setMoveToTrash(enabled); + }); + +#ifdef Q_OS_WIN + auto *showInExplorerNavigationPaneCheckBox = new QCheckBox( + tr("Show sync folders in &Explorer's navigation pane"), + advancedSettingsBox); + showInExplorerNavigationPaneCheckBox->setFocusPolicy(Qt::NoFocus); + showInExplorerNavigationPaneCheckBox->setChecked(cfgFile.showInExplorerNavigationPane()); + + connect(showInExplorerNavigationPaneCheckBox, &QAbstractButton::toggled, this, + [](bool enabled) { + ConfigFile().setShowInExplorerNavigationPane(enabled); + }); +#endif + + auto *ignoredFilesButton = new QPushButton( + tr("Edit &Ignored Files"), + advancedSettingsBox); + ignoredFilesButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + ignoredFilesButton->setFocusPolicy(Qt::NoFocus); + ignoredFilesButton->setStyleSheet(QStringLiteral( + "QPushButton {" + " min-height: 32px;" + " min-width: 200px;" + " border: 1px solid black;" + " color: black;" + " background-color: #ededed;" + " font-size: 13px;" + " border-radius: 4px;" + "}" + "QPushButton:hover {" + " background-color: white;" + "}" + )); + + connect(ignoredFilesButton, &QAbstractButton::clicked, this, [this]() { + auto *ignoreEditor = new IgnoreListEditor(this); + ignoreEditor->setAttribute(Qt::WA_DeleteOnClose, true); + ignoreEditor->open(); + }); + + advancedLayout->addWidget(advancedSettingsLabel); + advancedLayout->addWidget(newFolderLimitWidget); +#ifdef Q_OS_WIN + advancedLayout->addWidget(showInExplorerNavigationPaneCheckBox); +#endif + advancedLayout->addWidget(moveFilesToTrashCheckBox); + advancedLayout->addItem(new QSpacerItem(1, 8, QSizePolicy::Fixed, QSizePolicy::Fixed)); + advancedLayout->addWidget(ignoredFilesButton); + + /* + * Updates, data protection and info + */ + auto *dataProtectionBox = new QGroupBox(this); + applyNMCBoxStyle(dataProtectionBox, QStringLiteral("nmcUpdatesInfoBox")); + + auto *dataProtectionLayout = new QVBoxLayout(dataProtectionBox); + dataProtectionLayout->setContentsMargins(16, 16, 16, 16); + dataProtectionLayout->setSpacing(8); + + auto *updatesLabel = createSectionLabel( + QCoreApplication::translate("", "UPDATES_SETTINGS"), + dataProtectionBox); + + auto *dataAnalysisCheckBox = new QCheckBox(dataProtectionBox); + dataAnalysisCheckBox->setText(QCoreApplication::translate("", "DATA_ANALYSIS")); + dataAnalysisCheckBox->setFocusPolicy(Qt::NoFocus); + + NMCConfigFile nmcCfgFile; + dataAnalysisCheckBox->setChecked(nmcCfgFile.transferUsageData()); + + connect(dataAnalysisCheckBox, &QAbstractButton::toggled, this, [](bool enabled) { + NMCConfigFile cfgFile; + cfgFile.setTransferUsageData(enabled, QString()); + }); + + dataProtectionLayout->addWidget(updatesLabel); + dataProtectionLayout->addWidget(dataAnalysisCheckBox); + dataProtectionLayout->addItem(new QSpacerItem(1, 8, QSizePolicy::Fixed, QSizePolicy::Fixed)); + + dataProtectionLayout->addWidget(createLinkLabel( + QCoreApplication::translate("", "IMPRESSUM"), + QStringLiteral("https://www.telekom.de/impressum/"), + dataProtectionBox)); + + dataProtectionLayout->addWidget(createLinkLabel( + QCoreApplication::translate("", "DATA_PROTECTION"), + QStringLiteral("https://static.magentacloud.de/privacy/datenschutzhinweise_software.pdf"), + dataProtectionBox)); + + dataProtectionLayout->addWidget(createLinkLabel( + QCoreApplication::translate("", "LICENCE"), + QStringLiteral("https://static.magentacloud.de/licences/windowsdesktop.html"), + dataProtectionBox)); + + dataProtectionLayout->addWidget(createLinkLabel( + QCoreApplication::translate("", "FURTHER_INFO"), + QStringLiteral("https://cloud.telekom-dienste.de/hilfe"), + dataProtectionBox)); + + dataProtectionLayout->addItem(new QSpacerItem(1, 8, QSizePolicy::Fixed, QSizePolicy::Fixed)); + + auto *currentVersion = new QLabel(dataProtectionBox); + currentVersion->setText(Theme::instance()->about()); + currentVersion->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextBrowserInteraction); + currentVersion->setOpenExternalLinks(true); + currentVersion->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + dataProtectionLayout->addWidget(currentVersion); + + /* + * Insert custom boxes into the new upstream layout. + * New layout structure: + * pageLayout + * - generalGroupBox + * - notificationsGroupBox + * - verticalSpacer + */ + auto *pageLayout = getUi()->pageLayout; + const auto insertIndex = qMax(0, pageLayout->count() - 1); + + pageLayout->insertWidget(insertIndex, advancedSettingsBox); + pageLayout->insertWidget(insertIndex + 1, dataProtectionBox); +} + +} // namespace OCC diff --git a/src/gui/nmcgui/nmcgeneralsettings.h b/src/gui/nmcgui/nmcgeneralsettings.h new file mode 100644 index 0000000000000..a5df915984b54 --- /dev/null +++ b/src/gui/nmcgui/nmcgeneralsettings.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) by Mauro Mura + * + * 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 MIRALL_GENERALSETTINGSMAGENTA_H +#define MIRALL_GENERALSETTINGSMAGENTA_H + +#include "generalsettings.h" + +namespace OCC { + +class NMCGeneralSettings : public GeneralSettings +{ + Q_OBJECT + +public: + explicit NMCGeneralSettings(QWidget *parent = nullptr); + ~NMCGeneralSettings() override = default; + +private: + void setDefaultSettings(); + void setNMCLayout(); +}; + +} // namespace OCC + +#endif // MIRALL_GENERALSETTINGSMAGENTA_H \ No newline at end of file diff --git a/src/gui/settingsdialog.cpp b/src/gui/settingsdialog.cpp index fb66182fab055..93d85283fa3ac 100644 --- a/src/gui/settingsdialog.cpp +++ b/src/gui/settingsdialog.cpp @@ -10,6 +10,7 @@ #include "folderman.h" #include "theme.h" #include "generalsettings.h" +#include "nmcgui/nmcgeneralsettings.h" #include "infosettings.h" #include "networksettings.h" #include "accountsettings.h" @@ -180,7 +181,7 @@ SettingsDialog::SettingsDialog(ownCloudGui *gui, QWidget *parent) accountSpacer->setFixedHeight(16); _firstNonAccountAction = _toolBar->addWidget(accountSpacer); - addSettingsPage(QLatin1String(":/client/theme/settings.svg"), tr("General"), new GeneralSettings(this)); + addSettingsPage(QLatin1String(":/client/theme/settings.svg"), tr("General"), new NMCGeneralSettings(this)); addSettingsPage(QLatin1String(":/client/theme/advanced.svg"), tr("Advanced"), new AdvancedSettings(this)); addSettingsPage(QLatin1String(":/client/theme/info.svg"), tr("Info"), new InfoSettings(this), true); diff --git a/src/libsync/CMakeLists.txt b/src/libsync/CMakeLists.txt index be060e8ce275e..49279f0cce004 100644 --- a/src/libsync/CMakeLists.txt +++ b/src/libsync/CMakeLists.txt @@ -168,6 +168,10 @@ set(libsync_SRCS caseclashconflictsolver.cpp ) +file(GLOB NMC_FILES "nmclibsync/*") +set(NMC_SRCS ${NMC_FILES}) +list(APPEND libsync_SRCS ${NMC_SRCS}) + if (WIN32) # to fix warnings from ntstatus.h add_definitions(-DUMDF_USING_NTSTATUS) diff --git a/src/libsync/configfile.cpp b/src/libsync/configfile.cpp index fd31f0264e09b..1d087482171c9 100644 --- a/src/libsync/configfile.cpp +++ b/src/libsync/configfile.cpp @@ -172,7 +172,7 @@ bool ConfigFile::setConfDir(const QString &value) bool ConfigFile::optionalServerNotifications() const { QSettings settings(configFile(), QSettings::IniFormat); - return settings.value(optionalServerNotificationsC, true).toBool(); + return settings.value(optionalServerNotificationsC, false).toBool(); } bool ConfigFile::showChatNotifications() const diff --git a/src/libsync/configfile.h b/src/libsync/configfile.h index 14a5968970e11..b1509d4531585 100644 --- a/src/libsync/configfile.h +++ b/src/libsync/configfile.h @@ -321,10 +321,10 @@ class OWNCLOUDSYNC_EXPORT ConfigFile [[nodiscard]] QVariant retrieveData(const QString &group, const QString &key) const; void removeData(const QString &group, const QString &key); [[nodiscard]] bool dataExists(const QString &group, const QString &key) const; - -private: [[nodiscard]] QVariant getValue(const QString ¶m, const QString &group = QString(), const QVariant &defaultValue = QVariant()) const; + +private: void setValue(const QString &key, const QVariant &value); [[nodiscard]] QString keychainProxyPasswordKey() const; diff --git a/src/libsync/nmclibsync/nmcconfigfile.cpp b/src/libsync/nmclibsync/nmcconfigfile.cpp new file mode 100644 index 0000000000000..f88f672fbbb28 --- /dev/null +++ b/src/libsync/nmclibsync/nmcconfigfile.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) by Eugen Fischer + * + * 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 "nmcconfigfile.h" +#include "theme.h" +#include + +namespace OCC { + +const QString NMCConfigFile::m_transferUsageData = + QStringLiteral("TransferUsageData"); + +bool NMCConfigFile::transferUsageData(const QString &connection) const +{ + const QString group = connection.isEmpty() + ? Theme::instance()->appName() + : connection; + + QVariant fallback = getValue(m_transferUsageData, QString(), false); + fallback = getValue(m_transferUsageData, group, fallback); + + const QVariant value = getPolicySetting(m_transferUsageData, fallback); + return value.toBool(); +} + +void NMCConfigFile::setTransferUsageData(bool usageData, const QString &connection) +{ + const QString group = + connection.isEmpty() + ? Theme::instance()->appName() + : connection; + + QSettings settings(configFile(), QSettings::IniFormat); + settings.beginGroup(group); + + settings.setValue(m_transferUsageData, usageData); + settings.sync(); +} + +} // namespace OCC diff --git a/src/libsync/nmclibsync/nmcconfigfile.h b/src/libsync/nmclibsync/nmcconfigfile.h new file mode 100644 index 0000000000000..bd47e1418fca8 --- /dev/null +++ b/src/libsync/nmclibsync/nmcconfigfile.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) by Eugen Fischer + * + * 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 MIRALL_NMCCONFIGFILE_H +#define MIRALL_NMCCONFIGFILE_H + +#include "configfile.h" +#include + +namespace OCC { + +/** + * @brief The NMCConfigFile class. + * @ingroup lib + * + * Subclass of ConfigFile representing the configuration file for + * NMC (MagentaCustomization) in the OwnCloud Sync library. + */ +class OWNCLOUDSYNC_EXPORT NMCConfigFile : public ConfigFile +{ +public: + NMCConfigFile() = default; + ~NMCConfigFile() = default; + + /** + * @brief Check if transferring usage data is enabled. + * + * @param connection Optional parameter specifying the connection. + * @return True if transferring usage data is enabled, false otherwise. + */ + [[nodiscard]] bool transferUsageData(const QString &connection = QString()) const; + + /** + * @brief Set the status of transferring usage data. + * + * @param usageData True to enable transferring usage data, false otherwise. + * @param connection Optional parameter specifying the connection. + */ + void setTransferUsageData(bool usageData, const QString &connection = QString()); + +private: + static const QString m_transferUsageData; +}; + +} // namespace OCC + +#endif // MIRALL_NMCCONFIGFILE_H diff --git a/translations/client_de.ts b/translations/client_de.ts index 6d3b231dff68a..9b197e37cea43 100644 --- a/translations/client_de.ts +++ b/translations/client_de.ts @@ -3700,7 +3700,6 @@ Ein Downgrade von Versionen ist nicht sofort möglich: Der Wechsel von Beta auf Items where deletion is allowed will be deleted if they prevent a directory from being removed. This is useful for meta data. Dateien oder Ordner, die diesem Muster entsprechen, werden nicht synchronisiert. - Objekte, bei denen Löschen erlaubt ist, werden gelöscht, wenn diese das Entfernen eines Ordners verhindern würden. Dies ist für Metadaten nützlich.