From e33f73d08ec422429af3f2763e3551a820f9c172 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sun, 24 Jul 2022 12:46:19 +0800 Subject: [PATCH 1/3] Avoid performance impact over network or removable drives --- src/gui/torrentcontentmodel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/torrentcontentmodel.cpp b/src/gui/torrentcontentmodel.cpp index 0c8e5475e..664b73256 100644 --- a/src/gui/torrentcontentmodel.cpp +++ b/src/gui/torrentcontentmodel.cpp @@ -199,6 +199,7 @@ TorrentContentModel::TorrentContentModel(QObject *parent) , m_fileIconProvider {doesQFileIconProviderWork() ? new QFileIconProvider : new MimeFileIconProvider} #endif { + m_fileIconProvider->setOptions(QFileIconProvider::DontUseCustomDirectoryIcons); } TorrentContentModel::~TorrentContentModel() From 243d130667009d9f6e93c5e067468f583a0cb744 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sun, 24 Jul 2022 18:07:52 +0800 Subject: [PATCH 2/3] Clean up code --- src/gui/fspathedit.cpp | 38 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/src/gui/fspathedit.cpp b/src/gui/fspathedit.cpp index 33fb58ffc..de46bfe05 100644 --- a/src/gui/fspathedit.cpp +++ b/src/gui/fspathedit.cpp @@ -70,6 +70,7 @@ class FileSystemPathEdit::FileSystemPathEditPrivate Q_DECLARE_PUBLIC(FileSystemPathEdit) Q_DISABLE_COPY_MOVE(FileSystemPathEditPrivate) +private: FileSystemPathEditPrivate(FileSystemPathEdit *q, Private::IFileEditorWithCompletion *editor); void modeChanged(); @@ -81,7 +82,7 @@ class FileSystemPathEdit::FileSystemPathEditPrivate QAction *m_browseAction = nullptr; QToolButton *m_browseBtn = nullptr; QString m_fileNameFilter; - Mode m_mode; + Mode m_mode = FileSystemPathEdit::Mode::FileOpen; Path m_lastSignaledPath; QString m_dialogCaption; Private::FileSystemPathValidator *m_validator = nullptr; @@ -91,20 +92,22 @@ FileSystemPathEdit::FileSystemPathEditPrivate::FileSystemPathEditPrivate( FileSystemPathEdit *q, Private::IFileEditorWithCompletion *editor) : q_ptr {q} , m_editor {editor} - , m_browseAction {new QAction(q)} + , m_browseAction {new QAction(QApplication::style()->standardIcon(QStyle::SP_DirOpenIcon), browseButtonFullText.tr(), q)} , m_browseBtn {new QToolButton(q)} - , m_mode {FileSystemPathEdit::Mode::FileOpen} + , m_fileNameFilter {tr("Any file") + u" (*)"} , m_validator {new Private::FileSystemPathValidator(q)} { m_browseAction->setIconText(browseButtonBriefText.tr()); - m_browseAction->setText(browseButtonFullText.tr()); - m_browseAction->setToolTip(browseButtonFullText.tr().remove(u'&')); m_browseAction->setShortcut(Qt::CTRL + Qt::Key_B); + m_browseAction->setToolTip(browseButtonFullText.tr().remove(u'&')); + m_browseBtn->setDefaultAction(m_browseAction); - m_fileNameFilter = tr("Any file") + u" (*)"; - m_editor->setBrowseAction(m_browseAction); + m_validator->setStrictMode(false); + + m_editor->setBrowseAction(m_browseAction); m_editor->setValidator(m_validator); + modeChanged(); } @@ -160,22 +163,7 @@ QString FileSystemPathEdit::FileSystemPathEditPrivate::dialogCaptionOrDefault() void FileSystemPathEdit::FileSystemPathEditPrivate::modeChanged() { - bool showDirsOnly = false; - switch (m_mode) - { - case FileSystemPathEdit::Mode::FileOpen: - case FileSystemPathEdit::Mode::FileSave: - showDirsOnly = false; - break; - case FileSystemPathEdit::Mode::DirectoryOpen: - case FileSystemPathEdit::Mode::DirectorySave: - showDirsOnly = true; - break; - default: - throw std::logic_error("Unknown FileSystemPathEdit mode"); - } - m_browseAction->setIcon(QApplication::style()->standardIcon(QStyle::SP_DirOpenIcon)); - m_editor->completeDirectoriesOnly(showDirsOnly); + m_editor->completeDirectoriesOnly((m_mode == FileSystemPathEdit::Mode::DirectoryOpen) || (m_mode == FileSystemPathEdit::Mode::DirectorySave)); m_validator->setExistingOnly(m_mode != FileSystemPathEdit::Mode::FileSave); m_validator->setDirectoriesOnly((m_mode == FileSystemPathEdit::Mode::DirectoryOpen) || (m_mode == FileSystemPathEdit::Mode::DirectorySave)); @@ -297,10 +285,10 @@ FileSystemPathEdit::Mode FileSystemPathEdit::mode() const return d->m_mode; } -void FileSystemPathEdit::setMode(FileSystemPathEdit::Mode theMode) +void FileSystemPathEdit::setMode(const Mode mode) { Q_D(FileSystemPathEdit); - d->m_mode = theMode; + d->m_mode = mode; d->modeChanged(); } From 27a07e20f555ab0437e48e867ed4d9d8f76bf79a Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sun, 24 Jul 2022 18:07:59 +0800 Subject: [PATCH 3/3] Split code to smaller functions --- src/gui/optionsdialog.cpp | 1711 +++++++++++++++++++------------------ src/gui/optionsdialog.h | 36 +- 2 files changed, 933 insertions(+), 814 deletions(-) diff --git a/src/gui/optionsdialog.cpp b/src/gui/optionsdialog.cpp index 278d36ca6..a025838d0 100644 --- a/src/gui/optionsdialog.cpp +++ b/src/gui/optionsdialog.cpp @@ -44,7 +44,6 @@ #include "base/bittorrent/session.h" #include "base/exceptions.h" #include "base/global.h" -#include "base/net/dnsupdater.h" #include "base/net/portforwarder.h" #include "base/net/proxyconfigurationmanager.h" #include "base/path.h" @@ -70,6 +69,10 @@ #include "watchedfolderoptionsdialog.h" #include "watchedfoldersmodel.h" +#ifndef DISABLE_WEBUI +#include "base/net/dnsupdater.h" +#endif + #define SETTINGS_KEY(name) u"OptionsDialog/" name namespace @@ -160,19 +163,24 @@ namespace return lang; } } -} - -class WheelEventEater final : public QObject -{ -public: - using QObject::QObject; -private: - bool eventFilter(QObject *, QEvent *event) override + class WheelEventEater final : public QObject { - return (event->type() == QEvent::Wheel); - } -}; + public: + using QObject::QObject; + + private: + bool eventFilter(QObject *, QEvent *event) override + { + return (event->type() == QEvent::Wheel); + } + }; + + // Shortcuts for frequently used signals that have more than one overload. They would require + // type casts and that is why we declare required member pointer here instead. + void (QComboBox::*qComboBoxCurrentIndexChanged)(int) = &QComboBox::currentIndexChanged; + void (QSpinBox::*qSpinBoxValueChanged)(int) = &QSpinBox::valueChanged; +} // Constructor OptionsDialog::OptionsDialog(IGUIApplication *app, QWidget *parent) @@ -183,24 +191,27 @@ OptionsDialog::OptionsDialog(IGUIApplication *app, QWidget *parent) , m_storeHSplitterSize {SETTINGS_KEY(u"HorizontalSplitterSizes"_qs)} , m_storeLastViewedPage {SETTINGS_KEY(u"LastViewedPage"_qs)} { - qDebug("-> Constructing Options"); m_ui->setupUi(this); + m_applyButton = m_ui->buttonBox->button(QDialogButtonBox::Apply); -#if (defined(Q_OS_UNIX)) +#ifdef Q_OS_UNIX setWindowTitle(tr("Preferences")); #endif - // Icons + m_ui->hsplitter->setCollapsible(0, false); + m_ui->hsplitter->setCollapsible(1, false); + + // Main icons m_ui->tabSelection->item(TAB_UI)->setIcon(UIThemeManager::instance()->getIcon(u"preferences-desktop"_qs)); m_ui->tabSelection->item(TAB_BITTORRENT)->setIcon(UIThemeManager::instance()->getIcon(u"preferences-system-network"_qs)); m_ui->tabSelection->item(TAB_CONNECTION)->setIcon(UIThemeManager::instance()->getIcon(u"network-connect"_qs)); m_ui->tabSelection->item(TAB_DOWNLOADS)->setIcon(UIThemeManager::instance()->getIcon(u"kt-set-max-download-speed"_qs)); m_ui->tabSelection->item(TAB_SPEED)->setIcon(UIThemeManager::instance()->getIcon(u"speedometer"_qs)); m_ui->tabSelection->item(TAB_RSS)->setIcon(UIThemeManager::instance()->getIcon(u"application-rss+xml"_qs)); -#ifndef DISABLE_WEBUI - m_ui->tabSelection->item(TAB_WEBUI)->setIcon(UIThemeManager::instance()->getIcon(u"webui"_qs)); -#else +#ifdef DISABLE_WEBUI m_ui->tabSelection->item(TAB_WEBUI)->setHidden(true); +#else + m_ui->tabSelection->item(TAB_WEBUI)->setIcon(UIThemeManager::instance()->getIcon(u"webui"_qs)); #endif m_ui->tabSelection->item(TAB_ADVANCED)->setIcon(UIThemeManager::instance()->getIcon(u"preferences-other"_qs)); @@ -214,42 +225,63 @@ OptionsDialog::OptionsDialog(IGUIApplication *app, QWidget *parent) m_ui->tabSelection->item(i)->setSizeHint(size); } - m_ui->IpFilterRefreshBtn->setIcon(UIThemeManager::instance()->getIcon(u"view-refresh"_qs)); + connect(m_ui->tabSelection, &QListWidget::currentItemChanged, this, &ThisType::changePage); - m_ui->labelGlobalRate->setPixmap(Utils::Gui::scaledPixmapSvg(UIThemeManager::instance()->getIconPath(u"slow_off"_qs), this, Utils::Gui::mediumIconSize(this).height())); - m_ui->labelAltRate->setPixmap(Utils::Gui::scaledPixmapSvg(UIThemeManager::instance()->getIconPath(u"slow"_qs), this, Utils::Gui::mediumIconSize(this).height())); + // Load options + loadBehaviorTabOptions(); + loadDownloadsTabOptions(); + loadConnectionTabOptions(); + loadSpeedTabOptions(); + loadBittorrentTabOptions(); + loadRSSTabOptions(); +#ifndef DISABLE_WEBUI + loadWebUITabOptions(); +#endif - m_ui->deleteTorrentWarningIcon->setPixmap(QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical).pixmap(16, 16)); - m_ui->deleteTorrentWarningIcon->hide(); - m_ui->deleteTorrentWarningLabel->hide(); - m_ui->deleteTorrentWarningLabel->setToolTip(u"

" + - tr("By enabling these options, you can irrevocably lose your .torrent files!") + - u"

" + - tr("When these options are enabled, qBittorrent will delete .torrent files " - "after they were successfully (the first option) or not (the second option) added to its " - "download queue. This will be applied not only to the files opened via " - "“Add torrent” menu action but to those opened via file type association as well") + - u"

" + - tr("If you enable the second option (“Also when addition is cancelled”) the " - ".torrent file will be deleted even if you press “Cancel” in " - "the “Add torrent” dialog") + - u"

"); + // Load Advanced settings + m_advancedSettings = new AdvancedSettings(app, m_ui->tabAdvancedPage); + m_ui->advPageLayout->addWidget(m_advancedSettings); + connect(m_advancedSettings, &AdvancedSettings::settingsChanged, this, &ThisType::enableApplyButton); - m_ui->hsplitter->setCollapsible(0, false); - m_ui->hsplitter->setCollapsible(1, false); - // Get apply button in button box - m_applyButton = m_ui->buttonBox->button(QDialogButtonBox::Apply); + // setup apply button + m_applyButton->setEnabled(false); connect(m_applyButton, &QPushButton::clicked, this, &OptionsDialog::applySettings); - auto watchedFoldersModel = new WatchedFoldersModel(TorrentFilesWatcher::instance(), this); - connect(watchedFoldersModel, &QAbstractListModel::dataChanged, this, &ThisType::enableApplyButton); - m_ui->scanFoldersView->header()->setSectionResizeMode(QHeaderView::ResizeToContents); - m_ui->scanFoldersView->setModel(watchedFoldersModel); - connect(m_ui->scanFoldersView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &ThisType::handleWatchedFolderViewSelectionChanged); - connect(m_ui->scanFoldersView, &QTreeView::doubleClicked, this, &ThisType::editWatchedFolderOptions); + // disable mouse wheel event on widgets to avoid mis-selection + auto *wheelEventEater = new WheelEventEater(this); + for (QComboBox *widget : asConst(findChildren())) + widget->installEventFilter(wheelEventEater); + for (QSpinBox *widget : asConst(findChildren())) + widget->installEventFilter(wheelEventEater); + + m_ui->tabSelection->setCurrentRow(m_storeLastViewedPage); + + if (const QSize dialogSize = m_storeDialogSize; dialogSize.isValid()) + resize(dialogSize); +} + +OptionsDialog::~OptionsDialog() +{ + // save dialog states + m_storeDialogSize = size(); + + QStringList hSplitterSizes; + for (const int size : asConst(m_ui->hsplitter->sizes())) + hSplitterSizes.append(QString::number(size)); + m_storeHSplitterSize = hSplitterSizes; + + m_storeLastViewedPage = m_ui->tabSelection->currentRow(); + + delete m_ui; +} + +void OptionsDialog::loadBehaviorTabOptions() +{ + const auto *pref = Preferences::instance(); + const auto *session = BitTorrent::Session::instance(); - // Languages supported initializeLanguageCombo(); + setLocale(pref->getLocale()); m_ui->checkUseCustomTheme->setChecked(Preferences::instance()->useCustomUITheme()); m_ui->customThemeFilePath->setSelectedPath(Preferences::instance()->customUIThemePath()); @@ -257,15 +289,46 @@ OptionsDialog::OptionsDialog(IGUIApplication *app, QWidget *parent) m_ui->customThemeFilePath->setDialogCaption(tr("Select qBittorrent UI Theme file")); m_ui->customThemeFilePath->setFileNameFilter(tr("qBittorrent UI Theme file (*.qbtheme config.json)")); - // Load week days (scheduler) - m_ui->comboBoxScheduleDays->addItems(translatedWeekdayNames()); + m_ui->confirmDeletion->setChecked(pref->confirmTorrentDeletion()); + m_ui->checkAltRowColors->setChecked(pref->useAlternatingRowColors()); + m_ui->checkHideZero->setChecked(pref->getHideZeroValues()); + m_ui->comboHideZero->setCurrentIndex(pref->getHideZeroComboValues()); + m_ui->comboHideZero->setEnabled(m_ui->checkHideZero->isChecked()); - // Load options - loadOptions(); + m_ui->actionTorrentDlOnDblClBox->setItemData(0, TOGGLE_PAUSE); + m_ui->actionTorrentDlOnDblClBox->setItemData(1, OPEN_DEST); + m_ui->actionTorrentDlOnDblClBox->setItemData(2, PREVIEW_FILE); + m_ui->actionTorrentDlOnDblClBox->setItemData(3, SHOW_OPTIONS); + m_ui->actionTorrentDlOnDblClBox->setItemData(4, NO_ACTION); + int actionDownloading = pref->getActionOnDblClOnTorrentDl(); + if ((actionDownloading < 0) || (actionDownloading >= m_ui->actionTorrentDlOnDblClBox->count())) + actionDownloading = TOGGLE_PAUSE; + m_ui->actionTorrentDlOnDblClBox->setCurrentIndex(m_ui->actionTorrentDlOnDblClBox->findData(actionDownloading)); -#ifdef Q_OS_MACOS - m_ui->checkShowSystray->setVisible(false); -#else + m_ui->actionTorrentFnOnDblClBox->setItemData(0, TOGGLE_PAUSE); + m_ui->actionTorrentFnOnDblClBox->setItemData(1, OPEN_DEST); + m_ui->actionTorrentFnOnDblClBox->setItemData(2, PREVIEW_FILE); + m_ui->actionTorrentFnOnDblClBox->setItemData(3, SHOW_OPTIONS); + m_ui->actionTorrentFnOnDblClBox->setItemData(4, NO_ACTION); + int actionSeeding = pref->getActionOnDblClOnTorrentFn(); + if ((actionSeeding < 0) || (actionSeeding >= m_ui->actionTorrentFnOnDblClBox->count())) + actionSeeding = OPEN_DEST; + m_ui->actionTorrentFnOnDblClBox->setCurrentIndex(m_ui->actionTorrentFnOnDblClBox->findData(actionSeeding)); + +#ifndef Q_OS_WIN + m_ui->checkStartup->setVisible(false); +#endif + m_ui->checkShowSplash->setChecked(!pref->isSplashScreenDisabled()); + m_ui->checkStartMinimized->setChecked(pref->startMinimized()); + m_ui->checkProgramExitConfirm->setChecked(pref->confirmOnExit()); + m_ui->checkProgramAutoExitConfirm->setChecked(!pref->dontConfirmAutoExit()); + +#if !(defined(Q_OS_WIN) || defined(Q_OS_MACOS)) + m_ui->groupFileAssociation->setVisible(false); + m_ui->checkProgramUpdates->setVisible(false); +#endif + +#ifndef Q_OS_MACOS // Disable systray integration if it is not supported by the system if (!QSystemTrayIcon::isSystemTrayAvailable()) { @@ -273,385 +336,110 @@ OptionsDialog::OptionsDialog(IGUIApplication *app, QWidget *parent) m_ui->checkShowSystray->setEnabled(false); m_ui->checkShowSystray->setToolTip(tr("Disabled due to failed to detect system tray presence")); } + m_ui->checkShowSystray->setChecked(pref->systemTrayEnabled()); + m_ui->checkMinimizeToSysTray->setChecked(pref->minimizeToTray()); + m_ui->checkCloseToSystray->setChecked(pref->closeToTray()); + m_ui->comboTrayIcon->setCurrentIndex(static_cast(pref->trayIconStyle())); #endif -#ifndef Q_OS_WIN - m_ui->checkStartup->setVisible(false); +#ifdef Q_OS_WIN + m_ui->checkStartup->setChecked(pref->WinStartup()); + m_ui->checkAssociateTorrents->setChecked(Preferences::isTorrentFileAssocSet()); + m_ui->checkAssociateMagnetLinks->setChecked(Preferences::isMagnetLinkAssocSet()); #endif -#if !(defined(Q_OS_WIN) || defined(Q_OS_MACOS)) - m_ui->groupFileAssociation->setVisible(false); - m_ui->checkProgramUpdates->setVisible(false); +#ifdef Q_OS_MACOS + m_ui->checkShowSystray->setVisible(false); + m_ui->checkAssociateTorrents->setChecked(Preferences::isTorrentFileAssocSet()); + m_ui->checkAssociateTorrents->setEnabled(!m_ui->checkAssociateTorrents->isChecked()); + m_ui->checkAssociateMagnetLinks->setChecked(Preferences::isMagnetLinkAssocSet()); + m_ui->checkAssociateMagnetLinks->setEnabled(!m_ui->checkAssociateMagnetLinks->isChecked()); #endif - m_ui->textWebUIRootFolder->setMode(FileSystemPathEdit::Mode::DirectoryOpen); - m_ui->textWebUIRootFolder->setDialogCaption(tr("Choose Alternative UI files location")); +#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) + m_ui->checkProgramUpdates->setChecked(pref->isUpdateCheckEnabled()); +#endif - // Connect signals / slots - // Shortcuts for frequently used signals that have more than one overload. They would require - // type casts and that is why we declare required member pointer here instead. - void (QComboBox::*qComboBoxCurrentIndexChanged)(int) = &QComboBox::currentIndexChanged; - void (QSpinBox::*qSpinBoxValueChanged)(int) = &QSpinBox::valueChanged; + m_ui->checkPreventFromSuspendWhenDownloading->setChecked(pref->preventFromSuspendWhenDownloading()); + m_ui->checkPreventFromSuspendWhenSeeding->setChecked(pref->preventFromSuspendWhenSeeding()); - connect(m_ui->comboProxyType, qComboBoxCurrentIndexChanged, this, &ThisType::enableProxy); + m_ui->checkFileLog->setChecked(app()->isFileLoggerEnabled()); + m_ui->textFileLogPath->setDialogCaption(tr("Choose a save directory")); + m_ui->textFileLogPath->setMode(FileSystemPathEdit::Mode::DirectorySave); + m_ui->textFileLogPath->setSelectedPath(app()->fileLoggerPath()); + const bool fileLogBackup = app()->isFileLoggerBackup(); + m_ui->checkFileLogBackup->setChecked(fileLogBackup); + m_ui->spinFileLogSize->setEnabled(fileLogBackup); + const bool fileLogDelete = app()->isFileLoggerDeleteOld(); + m_ui->checkFileLogDelete->setChecked(fileLogDelete); + m_ui->spinFileLogAge->setEnabled(fileLogDelete); + m_ui->comboFileLogAgeType->setEnabled(fileLogDelete); + m_ui->spinFileLogSize->setValue(app()->fileLoggerMaxSize() / 1024); + m_ui->spinFileLogAge->setValue(app()->fileLoggerAge()); + m_ui->comboFileLogAgeType->setCurrentIndex(app()->fileLoggerAgeType()); + + m_ui->checkBoxPerformanceWarning->setChecked(session->isPerformanceWarningEnabled()); - // Apply button is activated when a value is changed - // Behavior tab connect(m_ui->comboI18n, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); + connect(m_ui->checkUseCustomTheme, &QGroupBox::toggled, this, &ThisType::enableApplyButton); connect(m_ui->customThemeFilePath, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton); + connect(m_ui->confirmDeletion, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkAltRowColors, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkHideZero, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkHideZero, &QAbstractButton::toggled, m_ui->comboHideZero, &QWidget::setEnabled); + connect(m_ui->checkHideZero, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->comboHideZero, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); - connect(m_ui->checkShowSystray, &QGroupBox::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkCloseToSystray, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkMinimizeToSysTray, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkStartMinimized, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->actionTorrentDlOnDblClBox, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); + connect(m_ui->actionTorrentFnOnDblClBox, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); + #ifdef Q_OS_WIN connect(m_ui->checkStartup, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); #endif connect(m_ui->checkShowSplash, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkStartMinimized, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkProgramExitConfirm, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkProgramAutoExitConfirm, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkShowSystray, &QGroupBox::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkMinimizeToSysTray, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkCloseToSystray, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->comboTrayIcon, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); + connect(m_ui->checkPreventFromSuspendWhenDownloading, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkPreventFromSuspendWhenSeeding, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->comboTrayIcon, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); -#if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) && !defined(QT_DBUS_LIB) - m_ui->checkPreventFromSuspendWhenDownloading->setDisabled(true); - m_ui->checkPreventFromSuspendWhenSeeding->setDisabled(true); -#endif + #if defined(Q_OS_WIN) || defined(Q_OS_MACOS) connect(m_ui->checkAssociateTorrents, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkAssociateMagnetLinks, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkProgramUpdates, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); #endif - connect(m_ui->checkBoxPerformanceWarning, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + +#if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) && !defined(QT_DBUS_LIB) + m_ui->checkPreventFromSuspendWhenDownloading->setDisabled(true); + m_ui->checkPreventFromSuspendWhenSeeding->setDisabled(true); +#endif + connect(m_ui->checkFileLog, &QGroupBox::toggled, this, &ThisType::enableApplyButton); connect(m_ui->textFileLogPath, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton); - connect(m_ui->checkFileLogBackup, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkFileLogBackup, &QAbstractButton::toggled, m_ui->spinFileLogSize, &QWidget::setEnabled); - connect(m_ui->checkFileLogDelete, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkFileLogDelete, &QAbstractButton::toggled, m_ui->spinFileLogAge, &QWidget::setEnabled); + connect(m_ui->checkFileLogBackup, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkFileLogDelete, &QAbstractButton::toggled, m_ui->comboFileLogAgeType, &QWidget::setEnabled); + connect(m_ui->checkFileLogDelete, &QAbstractButton::toggled, m_ui->spinFileLogAge, &QWidget::setEnabled); + connect(m_ui->checkFileLogDelete, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->spinFileLogSize, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); connect(m_ui->spinFileLogAge, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); connect(m_ui->comboFileLogAgeType, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); - // Downloads tab - connect(m_ui->textSavePath, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton); - connect(m_ui->checkUseSubcategories, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkUseCategoryPaths, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->comboSavingMode, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); - connect(m_ui->comboTorrentCategoryChanged, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); - connect(m_ui->comboCategoryDefaultPathChanged, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); - connect(m_ui->comboCategoryChanged, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); - connect(m_ui->textDownloadPath, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton); - connect(m_ui->checkAppendqB, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkPreallocateAll, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkRecursiveDownload, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkAdditionDialog, &QGroupBox::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkAdditionDialogFront, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkStartPaused, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->contentLayoutComboBox, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); - connect(m_ui->deleteTorrentBox, &QGroupBox::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->deleteCancelledTorrentBox, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkExportDir, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkExportDir, &QAbstractButton::toggled, m_ui->textExportDir, &QWidget::setEnabled); - connect(m_ui->checkExportDirFin, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkExportDirFin, &QAbstractButton::toggled, m_ui->textExportDirFin, &QWidget::setEnabled); - connect(m_ui->textExportDir, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton); - connect(m_ui->textExportDirFin, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton); - connect(m_ui->actionTorrentDlOnDblClBox, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); - connect(m_ui->actionTorrentFnOnDblClBox, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); - connect(m_ui->checkUseDownloadPath, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkUseDownloadPath, &QAbstractButton::toggled, m_ui->textDownloadPath, &QWidget::setEnabled); - connect(m_ui->addWatchedFolderButton, &QAbstractButton::clicked, this, &ThisType::enableApplyButton); - connect(m_ui->groupExcludedFileNames, &QGroupBox::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->textExcludedFileNames, &QPlainTextEdit::textChanged, this, &ThisType::enableApplyButton); - connect(m_ui->removeWatchedFolderButton, &QAbstractButton::clicked, this, &ThisType::enableApplyButton); - connect(m_ui->groupMailNotification, &QGroupBox::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->senderEmailTxt, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); - connect(m_ui->lineEditDestEmail, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); - connect(m_ui->lineEditSmtpServer, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); - connect(m_ui->checkSmtpSSL, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->groupMailNotifAuth, &QGroupBox::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->mailNotifUsername, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); - connect(m_ui->mailNotifPassword, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); - connect(m_ui->autoRunBox, &QGroupBox::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->lineEditAutoRun, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); - connect(m_ui->autoRunConsole, &QCheckBox::toggled, this, &ThisType::enableApplyButton); - - const auto autoRunStr = u"%1\n %2\n %3\n %4\n %5\n %6\n %7\n %8\n %9\n %10\n %11\n %12\n %13\n%14"_qs - .arg(tr("Supported parameters (case sensitive):") - , tr("%N: Torrent name") - , tr("%L: Category") - , tr("%G: Tags (separated by comma)") - , tr("%F: Content path (same as root path for multifile torrent)") - , tr("%R: Root path (first torrent subdirectory path)") - , tr("%D: Save path") - , tr("%C: Number of files") - , tr("%Z: Torrent size (bytes)")) - .arg(tr("%T: Current tracker") - , tr("%I: Info hash v1 (or '-' if unavailable)") - , tr("%J: Info hash v2 (or '-' if unavailable)") - , tr("%K: Torrent ID (either sha-1 info hash for v1 torrent or truncated sha-256 info hash for v2/hybrid torrent)") - , tr("Tip: Encapsulate parameter with quotation marks to avoid text being cut off at whitespace (e.g., \"%N\")")); - m_ui->labelAutoRunParam->setText(autoRunStr); - - // Connection tab - connect(m_ui->comboProtocol, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); - connect(m_ui->spinPort, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); - connect(m_ui->checkUPnP, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->spinUploadLimit, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); - connect(m_ui->spinDownloadLimit, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); - connect(m_ui->spinUploadLimitAlt, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); - connect(m_ui->spinDownloadLimitAlt, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); - connect(m_ui->groupBoxSchedule, &QGroupBox::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->timeEditScheduleFrom, &QDateTimeEdit::timeChanged, this, &ThisType::enableApplyButton); - connect(m_ui->timeEditScheduleTo, &QDateTimeEdit::timeChanged, this, &ThisType::enableApplyButton); - connect(m_ui->comboBoxScheduleDays, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); - connect(m_ui->checkLimituTPConnections, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkLimitTransportOverhead, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkLimitLocalPeerRate, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - // Bittorrent tab - connect(m_ui->checkMaxConnections, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkMaxConnectionsPerTorrent, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkMaxUploads, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkMaxUploadsPerTorrent, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->spinMaxConnec, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); - connect(m_ui->spinMaxConnecPerTorrent, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); - connect(m_ui->spinMaxUploads, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); - connect(m_ui->spinMaxUploadsPerTorrent, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); - connect(m_ui->checkDHT, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkAnonymousMode, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->spinBoxMaxActiveCheckingTorrents, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); - connect(m_ui->checkPeX, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkLSD, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->comboEncryption, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); - connect(m_ui->checkMaxRatio, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkMaxRatio, &QAbstractButton::toggled, this, &ThisType::toggleComboRatioLimitAct); - connect(m_ui->spinMaxRatio, qOverload(&QDoubleSpinBox::valueChanged), - this, &ThisType::enableApplyButton); - connect(m_ui->comboRatioLimitAct, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); - connect(m_ui->checkMaxSeedingMinutes, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkMaxSeedingMinutes, &QAbstractButton::toggled, this, &ThisType::toggleComboRatioLimitAct); - connect(m_ui->spinMaxSeedingMinutes, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); - // Proxy tab - connect(m_ui->comboProxyType, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); - connect(m_ui->textProxyIP, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); - connect(m_ui->spinProxyPort, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); - connect(m_ui->checkProxyPeerConnections, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->isProxyOnlyForTorrents, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkProxyAuth, &QGroupBox::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->textProxyUsername, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); - connect(m_ui->textProxyPassword, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); - // Misc tab - connect(m_ui->checkIPFilter, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkIPFilter, &QAbstractButton::toggled, m_ui->textFilterPath, &QWidget::setEnabled); - connect(m_ui->checkIPFilter, &QAbstractButton::toggled, m_ui->IpFilterRefreshBtn, &QWidget::setEnabled); - connect(m_ui->checkIpFilterTrackers, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->textFilterPath, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton); - connect(m_ui->checkEnableQueueing, &QGroupBox::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->spinMaxActiveDownloads, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); - connect(m_ui->spinMaxActiveUploads, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); - connect(m_ui->spinMaxActiveTorrents, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); - connect(m_ui->checkIgnoreSlowTorrentsForQueueing, &QGroupBox::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->spinDownloadRateForSlowTorrents, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); - connect(m_ui->spinUploadRateForSlowTorrents, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); - connect(m_ui->spinSlowTorrentsInactivityTimer, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); - connect(m_ui->checkEnableAddTrackers, &QGroupBox::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->textTrackers, &QPlainTextEdit::textChanged, this, &ThisType::enableApplyButton); - - const QString slowTorrentsExplanation = u"

" - + tr("A torrent will be considered slow if its download and upload rates stay below these values for \"Torrent inactivity timer\" seconds") - + u"

"; - m_ui->labelDownloadRateForSlowTorrents->setToolTip(slowTorrentsExplanation); - m_ui->labelUploadRateForSlowTorrents->setToolTip(slowTorrentsExplanation); - m_ui->labelSlowTorrentInactivityTimer->setToolTip(slowTorrentsExplanation); - -#ifndef DISABLE_WEBUI - // Web UI tab - m_ui->textWebUIHttpsCert->setMode(FileSystemPathEdit::Mode::FileOpen); - m_ui->textWebUIHttpsCert->setFileNameFilter(tr("Certificate") + u" (*.cer *.crt *.pem)"); - m_ui->textWebUIHttpsCert->setDialogCaption(tr("Select certificate")); - m_ui->textWebUIHttpsKey->setMode(FileSystemPathEdit::Mode::FileOpen); - m_ui->textWebUIHttpsKey->setFileNameFilter(tr("Private key") + u" (*.key *.pem)"); - m_ui->textWebUIHttpsKey->setDialogCaption(tr("Select private key")); - - connect(m_ui->textServerDomains, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); - connect(m_ui->checkWebUi, &QGroupBox::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->textWebUiAddress, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); - connect(m_ui->spinWebUiPort, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); - connect(m_ui->checkWebUIUPnP, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkWebUiHttps, &QGroupBox::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->textWebUIHttpsCert, &FileSystemPathLineEdit::selectedPathChanged, this, &ThisType::enableApplyButton); - connect(m_ui->textWebUIHttpsCert, &FileSystemPathLineEdit::selectedPathChanged, this, &OptionsDialog::webUIHttpsCertChanged); - connect(m_ui->textWebUIHttpsKey, &FileSystemPathLineEdit::selectedPathChanged, this, &ThisType::enableApplyButton); - connect(m_ui->textWebUIHttpsKey, &FileSystemPathLineEdit::selectedPathChanged, this, &OptionsDialog::webUIHttpsKeyChanged); - connect(m_ui->textWebUiUsername, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); - connect(m_ui->textWebUiPassword, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); - connect(m_ui->checkBypassLocalAuth, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkBypassAuthSubnetWhitelist, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkBypassAuthSubnetWhitelist, &QAbstractButton::toggled, m_ui->IPSubnetWhitelistButton, &QPushButton::setEnabled); - connect(m_ui->spinBanCounter, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); - connect(m_ui->spinBanDuration, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); - connect(m_ui->spinSessionTimeout, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); - connect(m_ui->checkClickjacking, &QCheckBox::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkCSRFProtection, &QCheckBox::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkWebUiHttps, &QGroupBox::toggled, m_ui->checkSecureCookie, &QWidget::setEnabled); - connect(m_ui->checkSecureCookie, &QCheckBox::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->groupHostHeaderValidation, &QGroupBox::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->checkDynDNS, &QGroupBox::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->comboDNSService, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); - connect(m_ui->domainNameTxt, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); - connect(m_ui->DNSUsernameTxt, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); - connect(m_ui->DNSPasswordTxt, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); - connect(m_ui->groupAltWebUI, &QGroupBox::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->textWebUIRootFolder, &FileSystemPathLineEdit::selectedPathChanged, this, &ThisType::enableApplyButton); - connect(m_ui->groupWebUIAddCustomHTTPHeaders, &QGroupBox::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->textWebUICustomHTTPHeaders, &QPlainTextEdit::textChanged, this, &OptionsDialog::enableApplyButton); - connect(m_ui->groupEnableReverseProxySupport, &QGroupBox::toggled, this, &ThisType::enableApplyButton); - connect(m_ui->textTrustedReverseProxiesList, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); -#endif // DISABLE_WEBUI - - // RSS tab - connect(m_ui->checkRSSEnable, &QCheckBox::toggled, this, &OptionsDialog::enableApplyButton); - connect(m_ui->checkRSSAutoDownloaderEnable, &QCheckBox::toggled, this, &OptionsDialog::enableApplyButton); - connect(m_ui->textSmartEpisodeFilters, &QPlainTextEdit::textChanged, this, &OptionsDialog::enableApplyButton); - connect(m_ui->checkSmartFilterDownloadRepacks, &QCheckBox::toggled, this, &OptionsDialog::enableApplyButton); - connect(m_ui->spinRSSRefreshInterval, qSpinBoxValueChanged, this, &OptionsDialog::enableApplyButton); - connect(m_ui->spinRSSMaxArticlesPerFeed, qSpinBoxValueChanged, this, &OptionsDialog::enableApplyButton); - connect(m_ui->btnEditRules, &QPushButton::clicked, this, [this]() - { - auto *downloader = new AutomatedRssDownloader(this); - downloader->setAttribute(Qt::WA_DeleteOnClose); - downloader->open(); - }); - - // Disable apply Button - m_applyButton->setEnabled(false); - // Tab selection mechanism - connect(m_ui->tabSelection, &QListWidget::currentItemChanged, this, &ThisType::changePage); - // Load Advanced settings - m_advancedSettings = new AdvancedSettings(app, m_ui->tabAdvancedPage); - m_ui->advPageLayout->addWidget(m_advancedSettings); - connect(m_advancedSettings, &AdvancedSettings::settingsChanged, this, &ThisType::enableApplyButton); - - m_ui->textFileLogPath->setDialogCaption(tr("Choose a save directory")); - m_ui->textFileLogPath->setMode(FileSystemPathEdit::Mode::DirectorySave); - - m_ui->textExportDir->setDialogCaption(tr("Choose export directory")); - m_ui->textExportDir->setMode(FileSystemPathEdit::Mode::DirectorySave); - - m_ui->textExportDirFin->setDialogCaption(tr("Choose export directory")); - m_ui->textExportDirFin->setMode(FileSystemPathEdit::Mode::DirectorySave); - - m_ui->textFilterPath->setDialogCaption(tr("Choose an IP filter file")); - m_ui->textFilterPath->setFileNameFilter(tr("All supported filters") - + u" (*.dat *.p2p *.p2b);;.dat (*.dat);;.p2p (*.p2p);;.p2b (*.p2b)"); - - m_ui->textSavePath->setDialogCaption(tr("Choose a save directory")); - m_ui->textSavePath->setMode(FileSystemPathEdit::Mode::DirectorySave); - - m_ui->textDownloadPath->setDialogCaption(tr("Choose a save directory")); - m_ui->textDownloadPath->setMode(FileSystemPathEdit::Mode::DirectorySave); - - // disable mouse wheel event on widgets to avoid mis-selection - auto *wheelEventEater = new WheelEventEater(this); - for (QComboBox *widget : asConst(findChildren())) - widget->installEventFilter(wheelEventEater); - for (QSpinBox *widget : asConst(findChildren())) - widget->installEventFilter(wheelEventEater); - - m_ui->tabSelection->setCurrentRow(m_storeLastViewedPage); - - if (const QSize dialogSize = m_storeDialogSize; dialogSize.isValid()) - resize(dialogSize); -} - -void OptionsDialog::initializeLanguageCombo() -{ - // List language files - const QDir langDir(u":/lang"_qs); - const QStringList langFiles = langDir.entryList(QStringList(u"qbittorrent_*.qm"_qs), QDir::Files); - for (const QString &langFile : langFiles) - { - QString localeStr = langFile.mid(12); // remove "qbittorrent_" - localeStr.chop(3); // Remove ".qm" - QString languageName; - if (localeStr.startsWith(u"eo", Qt::CaseInsensitive)) - { - // QLocale doesn't work with that locale. Esperanto isn't a "real" language. - languageName = C_LOCALE_ESPERANTO; - } - else if (localeStr.startsWith(u"ltg", Qt::CaseInsensitive)) - { - // QLocale doesn't work with that locale. - languageName = C_LOCALE_LATGALIAN; - } - else - { - QLocale locale(localeStr); - languageName = languageToLocalizedString(locale); - } - m_ui->comboI18n->addItem(/*QIcon(":/icons/flags/"+country+".svg"), */ languageName, localeStr); - qDebug() << "Supported locale:" << localeStr; - } -} - -// Main destructor -OptionsDialog::~OptionsDialog() -{ - qDebug("-> destructing Options"); - - // save dialog states - m_storeDialogSize = size(); - - QStringList hSplitterSizes; - for (const int size : asConst(m_ui->hsplitter->sizes())) - hSplitterSizes.append(QString::number(size)); - m_storeHSplitterSize = hSplitterSizes; - - m_storeLastViewedPage = m_ui->tabSelection->currentRow(); - - delete m_ui; -} -void OptionsDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous) -{ - if (!current) - current = previous; - m_ui->tabOption->setCurrentIndex(m_ui->tabSelection->row(current)); -} - -void OptionsDialog::loadSplitterState() -{ - // width has been modified, use height as width reference instead - const int width = m_ui->tabSelection->item(TAB_UI)->sizeHint().height() * 2; - const QStringList defaultSizes = {QString::number(width), QString::number(m_ui->hsplitter->width() - width)}; - - QList splitterSizes; - for (const QString &string : asConst(m_storeHSplitterSize.get(defaultSizes))) - splitterSizes.append(string.toInt()); - - m_ui->hsplitter->setSizes(splitterSizes); -} - -void OptionsDialog::showEvent(QShowEvent *e) -{ - QDialog::showEvent(e); - - loadSplitterState(); + connect(m_ui->checkBoxPerformanceWarning, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); } -void OptionsDialog::saveOptions() +void OptionsDialog::saveBehaviorTabOptions() const { auto *pref = Preferences::instance(); auto *session = BitTorrent::Session::instance(); // Load the translation - QString locale = getLocale(); + const QString locale = getLocale(); if (pref->getLocale() != locale) { auto *translator = new QTranslator; @@ -661,8 +449,6 @@ void OptionsDialog::saveOptions() qDebug("%s locale unrecognized, using default (en).", qUtf8Printable(locale)); qApp->installTranslator(translator); } - - // Behavior preferences pref->setLocale(locale); pref->setUseCustomUITheme(m_ui->checkUseCustomTheme->isChecked()); @@ -672,365 +458,139 @@ void OptionsDialog::saveOptions() pref->setAlternatingRowColors(m_ui->checkAltRowColors->isChecked()); pref->setHideZeroValues(m_ui->checkHideZero->isChecked()); pref->setHideZeroComboValues(m_ui->comboHideZero->currentIndex()); -#ifndef Q_OS_MACOS - pref->setSystemTrayEnabled(m_ui->checkShowSystray->isChecked()); - pref->setTrayIconStyle(TrayIcon::Style(m_ui->comboTrayIcon->currentIndex())); - pref->setCloseToTray(m_ui->checkCloseToSystray->isChecked()); - pref->setMinimizeToTray(m_ui->checkMinimizeToSysTray->isChecked()); -#endif - pref->setStartMinimized(startMinimized()); - pref->setSplashScreenDisabled(isSplashScreenDisabled()); - pref->setConfirmOnExit(m_ui->checkProgramExitConfirm->isChecked()); - pref->setDontConfirmAutoExit(!m_ui->checkProgramAutoExitConfirm->isChecked()); - pref->setPreventFromSuspendWhenDownloading(m_ui->checkPreventFromSuspendWhenDownloading->isChecked()); - pref->setPreventFromSuspendWhenSeeding(m_ui->checkPreventFromSuspendWhenSeeding->isChecked()); -#ifdef Q_OS_WIN - pref->setWinStartup(WinStartup()); - // Windows: file association settings - Preferences::setTorrentFileAssoc(m_ui->checkAssociateTorrents->isChecked()); - Preferences::setMagnetLinkAssoc(m_ui->checkAssociateMagnetLinks->isChecked()); -#endif -#ifdef Q_OS_MACOS - if (m_ui->checkAssociateTorrents->isChecked()) - { - Preferences::setTorrentFileAssoc(); - m_ui->checkAssociateTorrents->setChecked(Preferences::isTorrentFileAssocSet()); - m_ui->checkAssociateTorrents->setEnabled(!m_ui->checkAssociateTorrents->isChecked()); - } - if (m_ui->checkAssociateMagnetLinks->isChecked()) - { - Preferences::setMagnetLinkAssoc(); - m_ui->checkAssociateMagnetLinks->setChecked(Preferences::isMagnetLinkAssocSet()); - m_ui->checkAssociateMagnetLinks->setEnabled(!m_ui->checkAssociateMagnetLinks->isChecked()); - } -#endif -#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) - pref->setUpdateCheckEnabled(m_ui->checkProgramUpdates->isChecked()); -#endif - session->setPerformanceWarningEnabled(m_ui->checkBoxPerformanceWarning->isChecked()); - app()->setFileLoggerPath(m_ui->textFileLogPath->selectedPath()); - app()->setFileLoggerBackup(m_ui->checkFileLogBackup->isChecked()); - app()->setFileLoggerMaxSize(m_ui->spinFileLogSize->value() * 1024); - app()->setFileLoggerAge(m_ui->spinFileLogAge->value()); - app()->setFileLoggerAgeType(m_ui->comboFileLogAgeType->currentIndex()); - app()->setFileLoggerDeleteOld(m_ui->checkFileLogDelete->isChecked()); - app()->setFileLoggerEnabled(m_ui->checkFileLog->isChecked()); - // End Behavior preferences - - RSS::Session::instance()->setRefreshInterval(m_ui->spinRSSRefreshInterval->value()); - RSS::Session::instance()->setMaxArticlesPerFeed(m_ui->spinRSSMaxArticlesPerFeed->value()); - RSS::Session::instance()->setProcessingEnabled(m_ui->checkRSSEnable->isChecked()); - RSS::AutoDownloader::instance()->setProcessingEnabled(m_ui->checkRSSAutoDownloaderEnable->isChecked()); - RSS::AutoDownloader::instance()->setSmartEpisodeFilters(m_ui->textSmartEpisodeFilters->toPlainText().split(u'\n', Qt::SkipEmptyParts)); - RSS::AutoDownloader::instance()->setDownloadRepacks(m_ui->checkSmartFilterDownloadRepacks->isChecked()); - - // Downloads preferences - session->setSavePath(Path(m_ui->textSavePath->selectedPath())); - session->setSubcategoriesEnabled(m_ui->checkUseSubcategories->isChecked()); - session->setUseCategoryPathsInManualMode(m_ui->checkUseCategoryPaths->isChecked()); - session->setAutoTMMDisabledByDefault(m_ui->comboSavingMode->currentIndex() == 0); - session->setDisableAutoTMMWhenCategoryChanged(m_ui->comboTorrentCategoryChanged->currentIndex() == 1); - session->setDisableAutoTMMWhenCategorySavePathChanged(m_ui->comboCategoryChanged->currentIndex() == 1); - session->setDisableAutoTMMWhenDefaultSavePathChanged(m_ui->comboCategoryDefaultPathChanged->currentIndex() == 1); - session->setDownloadPathEnabled(m_ui->checkUseDownloadPath->isChecked()); - session->setDownloadPath(m_ui->textDownloadPath->selectedPath()); - session->setAppendExtensionEnabled(m_ui->checkAppendqB->isChecked()); - session->setPreallocationEnabled(preAllocateAllFiles()); - pref->disableRecursiveDownload(!m_ui->checkRecursiveDownload->isChecked()); - AddNewTorrentDialog::setEnabled(useAdditionDialog()); - AddNewTorrentDialog::setTopLevel(m_ui->checkAdditionDialogFront->isChecked()); - session->setAddTorrentPaused(addTorrentsInPause()); - session->setTorrentContentLayout(static_cast(m_ui->contentLayoutComboBox->currentIndex())); - auto watchedFoldersModel = static_cast(m_ui->scanFoldersView->model()); - watchedFoldersModel->apply(); - session->setExcludedFileNamesEnabled(m_ui->groupExcludedFileNames->isChecked()); - session->setExcludedFileNames(m_ui->textExcludedFileNames->toPlainText().split(u'\n', Qt::SkipEmptyParts)); - session->setTorrentExportDirectory(getTorrentExportDir()); - session->setFinishedTorrentExportDirectory(getFinishedTorrentExportDir()); - pref->setMailNotificationEnabled(m_ui->groupMailNotification->isChecked()); - pref->setMailNotificationSender(m_ui->senderEmailTxt->text()); - pref->setMailNotificationEmail(m_ui->lineEditDestEmail->text()); - pref->setMailNotificationSMTP(m_ui->lineEditSmtpServer->text()); - pref->setMailNotificationSMTPSSL(m_ui->checkSmtpSSL->isChecked()); - pref->setMailNotificationSMTPAuth(m_ui->groupMailNotifAuth->isChecked()); - pref->setMailNotificationSMTPUsername(m_ui->mailNotifUsername->text()); - pref->setMailNotificationSMTPPassword(m_ui->mailNotifPassword->text()); - pref->setAutoRunEnabled(m_ui->autoRunBox->isChecked()); - pref->setAutoRunProgram(m_ui->lineEditAutoRun->text().trimmed()); -#if defined(Q_OS_WIN) - pref->setAutoRunConsoleEnabled(m_ui->autoRunConsole->isChecked()); -#endif pref->setActionOnDblClOnTorrentDl(m_ui->actionTorrentDlOnDblClBox->currentData().toInt()); pref->setActionOnDblClOnTorrentFn(m_ui->actionTorrentFnOnDblClBox->currentData().toInt()); - TorrentFileGuard::setAutoDeleteMode(!m_ui->deleteTorrentBox->isChecked() ? TorrentFileGuard::Never - : !m_ui->deleteCancelledTorrentBox->isChecked() ? TorrentFileGuard::IfAdded - : TorrentFileGuard::Always); - // End Downloads preferences - - // Connection preferences - session->setBTProtocol(static_cast(m_ui->comboProtocol->currentIndex())); - session->setPort(getPort()); - Net::PortForwarder::instance()->setEnabled(isUPnPEnabled()); - session->setGlobalDownloadSpeedLimit(m_ui->spinDownloadLimit->value() * 1024); - session->setGlobalUploadSpeedLimit(m_ui->spinUploadLimit->value() * 1024); - session->setAltGlobalDownloadSpeedLimit(m_ui->spinDownloadLimitAlt->value() * 1024); - session->setAltGlobalUploadSpeedLimit(m_ui->spinUploadLimitAlt->value() * 1024); - session->setUTPRateLimited(m_ui->checkLimituTPConnections->isChecked()); - session->setIncludeOverheadInLimits(m_ui->checkLimitTransportOverhead->isChecked()); - session->setIgnoreLimitsOnLAN(!m_ui->checkLimitLocalPeerRate->isChecked()); - pref->setSchedulerStartTime(m_ui->timeEditScheduleFrom->time()); - pref->setSchedulerEndTime(m_ui->timeEditScheduleTo->time()); - pref->setSchedulerDays(static_cast(m_ui->comboBoxScheduleDays->currentIndex())); - session->setBandwidthSchedulerEnabled(m_ui->groupBoxSchedule->isChecked()); - - auto proxyConfigManager = Net::ProxyConfigurationManager::instance(); - Net::ProxyConfiguration proxyConf; - proxyConf.type = getProxyType(); - proxyConf.ip = getProxyIp(); - proxyConf.port = getProxyPort(); - proxyConf.username = getProxyUsername(); - proxyConf.password = getProxyPassword(); - proxyConfigManager->setProxyOnlyForTorrents(m_ui->isProxyOnlyForTorrents->isChecked()); - proxyConfigManager->setProxyConfiguration(proxyConf); - - session->setProxyPeerConnectionsEnabled(m_ui->checkProxyPeerConnections->isChecked()); - // End Connection preferences - - // Bittorrent preferences - session->setMaxConnections(getMaxConnections()); - session->setMaxConnectionsPerTorrent(getMaxConnectionsPerTorrent()); - session->setMaxUploads(getMaxUploads()); - session->setMaxUploadsPerTorrent(getMaxUploadsPerTorrent()); - session->setDHTEnabled(isDHTEnabled()); - session->setPeXEnabled(m_ui->checkPeX->isChecked()); - session->setLSDEnabled(isLSDEnabled()); - session->setEncryption(getEncryptionSetting()); - session->setAnonymousModeEnabled(m_ui->checkAnonymousMode->isChecked()); - session->setMaxActiveCheckingTorrents(m_ui->spinBoxMaxActiveCheckingTorrents->value()); - session->setAddTrackersEnabled(m_ui->checkEnableAddTrackers->isChecked()); - session->setAdditionalTrackers(m_ui->textTrackers->toPlainText()); - session->setGlobalMaxRatio(getMaxRatio()); - session->setGlobalMaxSeedingMinutes(getMaxSeedingMinutes()); - - const QVector actIndex = - { - Pause, - Remove, - DeleteFiles, - EnableSuperSeeding - }; - session->setMaxRatioAction(actIndex.value(m_ui->comboRatioLimitAct->currentIndex())); - // End Bittorrent preferences - - // Misc preferences - // * IPFilter - session->setIPFilteringEnabled(isIPFilteringEnabled()); - session->setTrackerFilteringEnabled(m_ui->checkIpFilterTrackers->isChecked()); - session->setIPFilterFile(m_ui->textFilterPath->selectedPath()); - // End IPFilter preferences - // Queueing system - session->setQueueingSystemEnabled(isQueueingSystemEnabled()); - session->setMaxActiveDownloads(m_ui->spinMaxActiveDownloads->value()); - session->setMaxActiveUploads(m_ui->spinMaxActiveUploads->value()); - session->setMaxActiveTorrents(m_ui->spinMaxActiveTorrents->value()); - session->setIgnoreSlowTorrentsForQueueing(m_ui->checkIgnoreSlowTorrentsForQueueing->isChecked()); - session->setDownloadRateForSlowTorrents(m_ui->spinDownloadRateForSlowTorrents->value()); - session->setUploadRateForSlowTorrents(m_ui->spinUploadRateForSlowTorrents->value()); - session->setSlowTorrentsInactivityTimer(m_ui->spinSlowTorrentsInactivityTimer->value()); - // End Queueing system preferences - // Web UI - pref->setWebUiEnabled(isWebUiEnabled()); - if (isWebUiEnabled()) - { - pref->setServerDomains(m_ui->textServerDomains->text()); - pref->setWebUiAddress(m_ui->textWebUiAddress->text()); - pref->setWebUiPort(m_ui->spinWebUiPort->value()); - pref->setUPnPForWebUIPort(m_ui->checkWebUIUPnP->isChecked()); - pref->setWebUiHttpsEnabled(m_ui->checkWebUiHttps->isChecked()); - pref->setWebUIHttpsCertificatePath(m_ui->textWebUIHttpsCert->selectedPath()); - pref->setWebUIHttpsKeyPath(m_ui->textWebUIHttpsKey->selectedPath()); - pref->setWebUIMaxAuthFailCount(m_ui->spinBanCounter->value()); - pref->setWebUIBanDuration(std::chrono::seconds {m_ui->spinBanDuration->value()}); - pref->setWebUISessionTimeout(m_ui->spinSessionTimeout->value()); - // Authentication - pref->setWebUiUsername(webUiUsername()); - if (!webUiPassword().isEmpty()) - pref->setWebUIPassword(Utils::Password::PBKDF2::generate(webUiPassword())); - pref->setWebUiLocalAuthEnabled(!m_ui->checkBypassLocalAuth->isChecked()); - pref->setWebUiAuthSubnetWhitelistEnabled(m_ui->checkBypassAuthSubnetWhitelist->isChecked()); - // Security - pref->setWebUiClickjackingProtectionEnabled(m_ui->checkClickjacking->isChecked()); - pref->setWebUiCSRFProtectionEnabled(m_ui->checkCSRFProtection->isChecked()); - pref->setWebUiSecureCookieEnabled(m_ui->checkSecureCookie->isChecked()); - pref->setWebUIHostHeaderValidationEnabled(m_ui->groupHostHeaderValidation->isChecked()); - // DynDNS - pref->setDynDNSEnabled(m_ui->checkDynDNS->isChecked()); - pref->setDynDNSService(static_cast(m_ui->comboDNSService->currentIndex())); - pref->setDynDomainName(m_ui->domainNameTxt->text()); - pref->setDynDNSUsername(m_ui->DNSUsernameTxt->text()); - pref->setDynDNSPassword(m_ui->DNSPasswordTxt->text()); - // Alternative UI - pref->setAltWebUiEnabled(m_ui->groupAltWebUI->isChecked()); - pref->setWebUiRootFolder(m_ui->textWebUIRootFolder->selectedPath()); - // Custom HTTP headers - pref->setWebUICustomHTTPHeadersEnabled(m_ui->groupWebUIAddCustomHTTPHeaders->isChecked()); - pref->setWebUICustomHTTPHeaders(m_ui->textWebUICustomHTTPHeaders->toPlainText()); - // Reverse proxy - pref->setWebUIReverseProxySupportEnabled(m_ui->groupEnableReverseProxySupport->isChecked()); - pref->setWebUITrustedReverseProxiesList(m_ui->textTrustedReverseProxiesList->text()); - } - // End Web UI - // End preferences - // Save advanced settings - m_advancedSettings->saveAdvancedSettings(); - // Assume that user changed multiple settings - // so it's best to save immediately - pref->apply(); -} - -bool OptionsDialog::isIPFilteringEnabled() const -{ - return m_ui->checkIPFilter->isChecked(); -} - -Net::ProxyType OptionsDialog::getProxyType() const -{ - switch (m_ui->comboProxyType->currentIndex()) - { - case 1: - return Net::ProxyType::SOCKS4; - case 2: - if (isProxyAuthEnabled()) - return Net::ProxyType::SOCKS5_PW; - return Net::ProxyType::SOCKS5; - case 3: - if (isProxyAuthEnabled()) - return Net::ProxyType::HTTP_PW; - return Net::ProxyType::HTTP; - default: - return Net::ProxyType::None; - } -} - -void OptionsDialog::loadOptions() -{ - const auto *pref = Preferences::instance(); - const auto *session = BitTorrent::Session::instance(); - - // Behavior preferences - setLocale(pref->getLocale()); - m_ui->confirmDeletion->setChecked(pref->confirmTorrentDeletion()); - m_ui->checkAltRowColors->setChecked(pref->useAlternatingRowColors()); - m_ui->checkHideZero->setChecked(pref->getHideZeroValues()); - m_ui->comboHideZero->setEnabled(m_ui->checkHideZero->isChecked()); - m_ui->comboHideZero->setCurrentIndex(pref->getHideZeroComboValues()); - - m_ui->checkShowSplash->setChecked(!pref->isSplashScreenDisabled()); - m_ui->checkStartMinimized->setChecked(pref->startMinimized()); - m_ui->checkProgramExitConfirm->setChecked(pref->confirmOnExit()); - m_ui->checkProgramAutoExitConfirm->setChecked(!pref->dontConfirmAutoExit()); - -#ifndef Q_OS_MACOS - m_ui->checkShowSystray->setChecked(pref->systemTrayEnabled()); - m_ui->checkMinimizeToSysTray->setChecked(pref->minimizeToTray()); - m_ui->checkCloseToSystray->setChecked(pref->closeToTray()); - m_ui->comboTrayIcon->setCurrentIndex(static_cast(pref->trayIconStyle())); -#endif - m_ui->checkPreventFromSuspendWhenDownloading->setChecked(pref->preventFromSuspendWhenDownloading()); - m_ui->checkPreventFromSuspendWhenSeeding->setChecked(pref->preventFromSuspendWhenSeeding()); + pref->setSplashScreenDisabled(isSplashScreenDisabled()); + pref->setStartMinimized(startMinimized()); + pref->setConfirmOnExit(m_ui->checkProgramExitConfirm->isChecked()); + pref->setDontConfirmAutoExit(!m_ui->checkProgramAutoExitConfirm->isChecked()); #ifdef Q_OS_WIN - m_ui->checkStartup->setChecked(pref->WinStartup()); - m_ui->checkAssociateTorrents->setChecked(Preferences::isTorrentFileAssocSet()); - m_ui->checkAssociateMagnetLinks->setChecked(Preferences::isMagnetLinkAssocSet()); + pref->setWinStartup(WinStartup()); + + Preferences::setTorrentFileAssoc(m_ui->checkAssociateTorrents->isChecked()); + Preferences::setMagnetLinkAssoc(m_ui->checkAssociateMagnetLinks->isChecked()); +#endif + +#ifndef Q_OS_MACOS + pref->setSystemTrayEnabled(m_ui->checkShowSystray->isChecked()); + pref->setTrayIconStyle(TrayIcon::Style(m_ui->comboTrayIcon->currentIndex())); + pref->setCloseToTray(m_ui->checkCloseToSystray->isChecked()); + pref->setMinimizeToTray(m_ui->checkMinimizeToSysTray->isChecked()); #endif + #ifdef Q_OS_MACOS - m_ui->checkAssociateTorrents->setChecked(Preferences::isTorrentFileAssocSet()); - m_ui->checkAssociateTorrents->setEnabled(!m_ui->checkAssociateTorrents->isChecked()); - m_ui->checkAssociateMagnetLinks->setChecked(Preferences::isMagnetLinkAssocSet()); - m_ui->checkAssociateMagnetLinks->setEnabled(!m_ui->checkAssociateMagnetLinks->isChecked()); + if (m_ui->checkAssociateTorrents->isChecked()) + { + Preferences::setTorrentFileAssoc(); + m_ui->checkAssociateTorrents->setChecked(Preferences::isTorrentFileAssocSet()); + m_ui->checkAssociateTorrents->setEnabled(!m_ui->checkAssociateTorrents->isChecked()); + } + if (m_ui->checkAssociateMagnetLinks->isChecked()) + { + Preferences::setMagnetLinkAssoc(); + m_ui->checkAssociateMagnetLinks->setChecked(Preferences::isMagnetLinkAssocSet()); + m_ui->checkAssociateMagnetLinks->setEnabled(!m_ui->checkAssociateMagnetLinks->isChecked()); + } #endif + #if defined(Q_OS_WIN) || defined(Q_OS_MACOS) - m_ui->checkProgramUpdates->setChecked(pref->isUpdateCheckEnabled()); + pref->setUpdateCheckEnabled(m_ui->checkProgramUpdates->isChecked()); #endif - m_ui->checkBoxPerformanceWarning->setChecked(session->isPerformanceWarningEnabled()); - m_ui->checkFileLog->setChecked(app()->isFileLoggerEnabled()); - m_ui->textFileLogPath->setSelectedPath(app()->fileLoggerPath()); - const bool fileLogBackup = app()->isFileLoggerBackup(); - m_ui->checkFileLogBackup->setChecked(fileLogBackup); - m_ui->spinFileLogSize->setEnabled(fileLogBackup); - const bool fileLogDelete = app()->isFileLoggerDeleteOld(); - m_ui->checkFileLogDelete->setChecked(fileLogDelete); - m_ui->spinFileLogAge->setEnabled(fileLogDelete); - m_ui->comboFileLogAgeType->setEnabled(fileLogDelete); - m_ui->spinFileLogSize->setValue(app()->fileLoggerMaxSize() / 1024); - m_ui->spinFileLogAge->setValue(app()->fileLoggerAge()); - m_ui->comboFileLogAgeType->setCurrentIndex(app()->fileLoggerAgeType()); - // End Behavior preferences + pref->setPreventFromSuspendWhenDownloading(m_ui->checkPreventFromSuspendWhenDownloading->isChecked()); + pref->setPreventFromSuspendWhenSeeding(m_ui->checkPreventFromSuspendWhenSeeding->isChecked()); + + app()->setFileLoggerPath(m_ui->textFileLogPath->selectedPath()); + app()->setFileLoggerBackup(m_ui->checkFileLogBackup->isChecked()); + app()->setFileLoggerMaxSize(m_ui->spinFileLogSize->value() * 1024); + app()->setFileLoggerAge(m_ui->spinFileLogAge->value()); + app()->setFileLoggerAgeType(m_ui->comboFileLogAgeType->currentIndex()); + app()->setFileLoggerDeleteOld(m_ui->checkFileLogDelete->isChecked()); + app()->setFileLoggerEnabled(m_ui->checkFileLog->isChecked()); - m_ui->checkRSSEnable->setChecked(RSS::Session::instance()->isProcessingEnabled()); - m_ui->checkRSSAutoDownloaderEnable->setChecked(RSS::AutoDownloader::instance()->isProcessingEnabled()); - m_ui->textSmartEpisodeFilters->setPlainText(RSS::AutoDownloader::instance()->smartEpisodeFilters().join(u'\n')); - m_ui->checkSmartFilterDownloadRepacks->setChecked(RSS::AutoDownloader::instance()->downloadRepacks()); + session->setPerformanceWarningEnabled(m_ui->checkBoxPerformanceWarning->isChecked()); +} - m_ui->spinRSSRefreshInterval->setValue(RSS::Session::instance()->refreshInterval()); - m_ui->spinRSSMaxArticlesPerFeed->setValue(RSS::Session::instance()->maxArticlesPerFeed()); +void OptionsDialog::loadDownloadsTabOptions() +{ + const auto *pref = Preferences::instance(); + const auto *session = BitTorrent::Session::instance(); - // Downloads preferences m_ui->checkAdditionDialog->setChecked(AddNewTorrentDialog::isEnabled()); m_ui->checkAdditionDialogFront->setChecked(AddNewTorrentDialog::isTopLevel()); - m_ui->checkStartPaused->setChecked(session->isAddTorrentPaused()); + m_ui->contentLayoutComboBox->setCurrentIndex(static_cast(session->torrentContentLayout())); + m_ui->checkStartPaused->setChecked(session->isAddTorrentPaused()); + const TorrentFileGuard::AutoDeleteMode autoDeleteMode = TorrentFileGuard::autoDeleteMode(); m_ui->deleteTorrentBox->setChecked(autoDeleteMode != TorrentFileGuard::Never); m_ui->deleteCancelledTorrentBox->setChecked(autoDeleteMode == TorrentFileGuard::Always); + m_ui->deleteTorrentWarningIcon->setPixmap(QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical).pixmap(16, 16)); + m_ui->deleteTorrentWarningIcon->hide(); + m_ui->deleteTorrentWarningLabel->hide(); + m_ui->deleteTorrentWarningLabel->setToolTip(u"

" + + tr("By enabling these options, you can irrevocably lose your .torrent files!") + + u"

" + + tr("When these options are enabled, qBittorrent will delete .torrent files " + "after they were successfully (the first option) or not (the second option) added to its " + "download queue. This will be applied not only to the files opened via " + "“Add torrent” menu action but to those opened via file type association as well") + + u"

" + + tr("If you enable the second option (“Also when addition is cancelled”) the " + ".torrent file will be deleted even if you press “Cancel” in " + "the “Add torrent” dialog") + + u"

"); + + m_ui->checkPreallocateAll->setChecked(session->isPreallocationEnabled()); + m_ui->checkAppendqB->setChecked(session->isAppendExtensionEnabled()); + m_ui->checkRecursiveDownload->setChecked(!pref->recursiveDownloadDisabled()); - m_ui->textSavePath->setSelectedPath(session->savePath()); - m_ui->checkUseSubcategories->setChecked(session->isSubcategoriesEnabled()); - m_ui->checkUseCategoryPaths->setChecked(session->useCategoryPathsInManualMode()); m_ui->comboSavingMode->setCurrentIndex(!session->isAutoTMMDisabledByDefault()); m_ui->comboTorrentCategoryChanged->setCurrentIndex(session->isDisableAutoTMMWhenCategoryChanged()); m_ui->comboCategoryChanged->setCurrentIndex(session->isDisableAutoTMMWhenCategorySavePathChanged()); m_ui->comboCategoryDefaultPathChanged->setCurrentIndex(session->isDisableAutoTMMWhenDefaultSavePathChanged()); + + m_ui->checkUseSubcategories->setChecked(session->isSubcategoriesEnabled()); + m_ui->checkUseCategoryPaths->setChecked(session->useCategoryPathsInManualMode()); + + m_ui->textSavePath->setDialogCaption(tr("Choose a save directory")); + m_ui->textSavePath->setMode(FileSystemPathEdit::Mode::DirectorySave); + m_ui->textSavePath->setSelectedPath(session->savePath()); + m_ui->checkUseDownloadPath->setChecked(session->isDownloadPathEnabled()); + m_ui->textDownloadPath->setDialogCaption(tr("Choose a save directory")); m_ui->textDownloadPath->setEnabled(m_ui->checkUseDownloadPath->isChecked()); + m_ui->textDownloadPath->setMode(FileSystemPathEdit::Mode::DirectorySave); m_ui->textDownloadPath->setSelectedPath(session->downloadPath()); - m_ui->checkAppendqB->setChecked(session->isAppendExtensionEnabled()); - m_ui->checkPreallocateAll->setChecked(session->isPreallocationEnabled()); - m_ui->checkRecursiveDownload->setChecked(!pref->recursiveDownloadDisabled()); - m_ui->groupExcludedFileNames->setChecked(session->isExcludedFileNamesEnabled()); - m_ui->textExcludedFileNames->setPlainText(session->excludedFileNames().join(u'\n')); - if (session->torrentExportDirectory().isEmpty()) - { - // Disable - m_ui->checkExportDir->setChecked(false); - m_ui->textExportDir->setEnabled(false); - } - else - { - // Enable - m_ui->checkExportDir->setChecked(true); - m_ui->textExportDir->setEnabled(true); + const bool isExportDirEmpty = session->torrentExportDirectory().isEmpty(); + m_ui->checkExportDir->setChecked(!isExportDirEmpty); + m_ui->textExportDir->setDialogCaption(tr("Choose export directory")); + m_ui->textExportDir->setEnabled(m_ui->checkExportDir->isChecked()); + m_ui->textExportDir->setMode(FileSystemPathEdit::Mode::DirectorySave); + if (!isExportDirEmpty) m_ui->textExportDir->setSelectedPath(session->torrentExportDirectory()); - } - if (session->finishedTorrentExportDirectory().isEmpty()) - { - // Disable - m_ui->checkExportDirFin->setChecked(false); - m_ui->textExportDirFin->setEnabled(false); - } - else - { - // Enable - m_ui->checkExportDirFin->setChecked(true); - m_ui->textExportDirFin->setEnabled(true); + const bool isExportDirFinEmpty = session->finishedTorrentExportDirectory().isEmpty(); + m_ui->checkExportDirFin->setChecked(!isExportDirFinEmpty); + m_ui->textExportDirFin->setDialogCaption(tr("Choose export directory")); + m_ui->textExportDirFin->setEnabled(m_ui->checkExportDirFin->isChecked()); + m_ui->textExportDirFin->setMode(FileSystemPathEdit::Mode::DirectorySave); + if (!isExportDirFinEmpty) m_ui->textExportDirFin->setSelectedPath(session->finishedTorrentExportDirectory()); - } + + auto *watchedFoldersModel = new WatchedFoldersModel(TorrentFilesWatcher::instance(), this); + connect(watchedFoldersModel, &QAbstractListModel::dataChanged, this, &ThisType::enableApplyButton); + m_ui->scanFoldersView->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + m_ui->scanFoldersView->setModel(watchedFoldersModel); + connect(m_ui->scanFoldersView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &ThisType::handleWatchedFolderViewSelectionChanged); + connect(m_ui->scanFoldersView, &QTreeView::doubleClicked, this, &ThisType::editWatchedFolderOptions); + + m_ui->groupExcludedFileNames->setChecked(session->isExcludedFileNamesEnabled()); + m_ui->textExcludedFileNames->setPlainText(session->excludedFileNames().join(u'\n')); m_ui->groupMailNotification->setChecked(pref->isMailNotificationEnabled()); m_ui->senderEmailTxt->setText(pref->getMailNotificationSender()); @@ -1041,36 +601,142 @@ void OptionsDialog::loadOptions() m_ui->mailNotifUsername->setText(pref->getMailNotificationSMTPUsername()); m_ui->mailNotifPassword->setText(pref->getMailNotificationSMTPPassword()); - m_ui->autoRunBox->setChecked(pref->isAutoRunEnabled()); - m_ui->lineEditAutoRun->setText(pref->getAutoRunProgram()); + m_ui->autoRunBox->setChecked(pref->isAutoRunEnabled()); + const auto autoRunStr = u"%1\n %2\n %3\n %4\n %5\n %6\n %7\n %8\n %9\n %10\n %11\n %12\n %13\n%14"_qs + .arg(tr("Supported parameters (case sensitive):") + , tr("%N: Torrent name") + , tr("%L: Category") + , tr("%G: Tags (separated by comma)") + , tr("%F: Content path (same as root path for multifile torrent)") + , tr("%R: Root path (first torrent subdirectory path)") + , tr("%D: Save path") + , tr("%C: Number of files") + , tr("%Z: Torrent size (bytes)")) + .arg(tr("%T: Current tracker") + , tr("%I: Info hash v1 (or '-' if unavailable)") + , tr("%J: Info hash v2 (or '-' if unavailable)") + , tr("%K: Torrent ID (either sha-1 info hash for v1 torrent or truncated sha-256 info hash for v2/hybrid torrent)") + , tr("Tip: Encapsulate parameter with quotation marks to avoid text being cut off at whitespace (e.g., \"%N\")")); + m_ui->labelAutoRunParam->setText(autoRunStr); + m_ui->lineEditAutoRun->setText(pref->getAutoRunProgram()); +#if defined(Q_OS_WIN) + m_ui->autoRunConsole->setChecked(pref->isAutoRunConsoleEnabled()); +#else + m_ui->autoRunConsole->hide(); +#endif + + connect(m_ui->checkAdditionDialog, &QGroupBox::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkAdditionDialogFront, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + + connect(m_ui->contentLayoutComboBox, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); + + connect(m_ui->checkStartPaused, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->deleteTorrentBox, &QGroupBox::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->deleteCancelledTorrentBox, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + + connect(m_ui->checkPreallocateAll, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkAppendqB, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkRecursiveDownload, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + + connect(m_ui->comboSavingMode, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); + connect(m_ui->comboTorrentCategoryChanged, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); + connect(m_ui->comboCategoryChanged, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); + connect(m_ui->comboCategoryDefaultPathChanged, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); + + connect(m_ui->checkUseSubcategories, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkUseCategoryPaths, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + + connect(m_ui->textSavePath, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton); + connect(m_ui->textDownloadPath, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton); + + connect(m_ui->checkExportDir, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkExportDir, &QAbstractButton::toggled, m_ui->textExportDir, &QWidget::setEnabled); + connect(m_ui->checkExportDirFin, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkExportDirFin, &QAbstractButton::toggled, m_ui->textExportDirFin, &QWidget::setEnabled); + connect(m_ui->textExportDir, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton); + connect(m_ui->textExportDirFin, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton); + connect(m_ui->checkUseDownloadPath, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkUseDownloadPath, &QAbstractButton::toggled, m_ui->textDownloadPath, &QWidget::setEnabled); + + connect(m_ui->addWatchedFolderButton, &QAbstractButton::clicked, this, &ThisType::enableApplyButton); + + connect(m_ui->groupExcludedFileNames, &QGroupBox::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->textExcludedFileNames, &QPlainTextEdit::textChanged, this, &ThisType::enableApplyButton); + connect(m_ui->removeWatchedFolderButton, &QAbstractButton::clicked, this, &ThisType::enableApplyButton); + + connect(m_ui->groupMailNotification, &QGroupBox::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->senderEmailTxt, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); + connect(m_ui->lineEditDestEmail, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); + connect(m_ui->lineEditSmtpServer, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); + connect(m_ui->checkSmtpSSL, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->groupMailNotifAuth, &QGroupBox::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->mailNotifUsername, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); + connect(m_ui->mailNotifPassword, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); + + connect(m_ui->autoRunBox, &QGroupBox::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->lineEditAutoRun, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); + connect(m_ui->autoRunConsole, &QCheckBox::toggled, this, &ThisType::enableApplyButton); +} + +void OptionsDialog::saveDownloadsTabOptions() const +{ + auto *pref = Preferences::instance(); + auto *session = BitTorrent::Session::instance(); + + AddNewTorrentDialog::setEnabled(useAdditionDialog()); + AddNewTorrentDialog::setTopLevel(m_ui->checkAdditionDialogFront->isChecked()); + + session->setTorrentContentLayout(static_cast(m_ui->contentLayoutComboBox->currentIndex())); + + session->setAddTorrentPaused(addTorrentsInPause()); + TorrentFileGuard::setAutoDeleteMode(!m_ui->deleteTorrentBox->isChecked() ? TorrentFileGuard::Never + : !m_ui->deleteCancelledTorrentBox->isChecked() ? TorrentFileGuard::IfAdded + : TorrentFileGuard::Always); + + session->setPreallocationEnabled(preAllocateAllFiles()); + session->setAppendExtensionEnabled(m_ui->checkAppendqB->isChecked()); + pref->disableRecursiveDownload(!m_ui->checkRecursiveDownload->isChecked()); + + session->setAutoTMMDisabledByDefault(m_ui->comboSavingMode->currentIndex() == 0); + session->setDisableAutoTMMWhenCategoryChanged(m_ui->comboTorrentCategoryChanged->currentIndex() == 1); + session->setDisableAutoTMMWhenCategorySavePathChanged(m_ui->comboCategoryChanged->currentIndex() == 1); + session->setDisableAutoTMMWhenDefaultSavePathChanged(m_ui->comboCategoryDefaultPathChanged->currentIndex() == 1); + + session->setSubcategoriesEnabled(m_ui->checkUseSubcategories->isChecked()); + session->setUseCategoryPathsInManualMode(m_ui->checkUseCategoryPaths->isChecked()); + + session->setSavePath(Path(m_ui->textSavePath->selectedPath())); + session->setDownloadPathEnabled(m_ui->checkUseDownloadPath->isChecked()); + session->setDownloadPath(m_ui->textDownloadPath->selectedPath()); + session->setTorrentExportDirectory(getTorrentExportDir()); + session->setFinishedTorrentExportDirectory(getFinishedTorrentExportDir()); + + auto watchedFoldersModel = static_cast(m_ui->scanFoldersView->model()); + watchedFoldersModel->apply(); + + session->setExcludedFileNamesEnabled(m_ui->groupExcludedFileNames->isChecked()); + session->setExcludedFileNames(m_ui->textExcludedFileNames->toPlainText().split(u'\n', Qt::SkipEmptyParts)); + + pref->setMailNotificationEnabled(m_ui->groupMailNotification->isChecked()); + pref->setMailNotificationSender(m_ui->senderEmailTxt->text()); + pref->setMailNotificationEmail(m_ui->lineEditDestEmail->text()); + pref->setMailNotificationSMTP(m_ui->lineEditSmtpServer->text()); + pref->setMailNotificationSMTPSSL(m_ui->checkSmtpSSL->isChecked()); + pref->setMailNotificationSMTPAuth(m_ui->groupMailNotifAuth->isChecked()); + pref->setMailNotificationSMTPUsername(m_ui->mailNotifUsername->text()); + pref->setMailNotificationSMTPPassword(m_ui->mailNotifPassword->text()); + + pref->setAutoRunEnabled(m_ui->autoRunBox->isChecked()); + pref->setAutoRunProgram(m_ui->lineEditAutoRun->text().trimmed()); #if defined(Q_OS_WIN) - m_ui->autoRunConsole->setChecked(pref->isAutoRunConsoleEnabled()); -#else - m_ui->autoRunConsole->hide(); + pref->setAutoRunConsoleEnabled(m_ui->autoRunConsole->isChecked()); #endif +} - m_ui->actionTorrentDlOnDblClBox->setItemData(0, TOGGLE_PAUSE); - m_ui->actionTorrentDlOnDblClBox->setItemData(1, OPEN_DEST); - m_ui->actionTorrentDlOnDblClBox->setItemData(2, PREVIEW_FILE); - m_ui->actionTorrentDlOnDblClBox->setItemData(3, SHOW_OPTIONS); - m_ui->actionTorrentDlOnDblClBox->setItemData(4, NO_ACTION); - int actionDownloading = pref->getActionOnDblClOnTorrentDl(); - if ((actionDownloading < 0) || (actionDownloading >= m_ui->actionTorrentDlOnDblClBox->count())) - actionDownloading = TOGGLE_PAUSE; - m_ui->actionTorrentDlOnDblClBox->setCurrentIndex(m_ui->actionTorrentDlOnDblClBox->findData(actionDownloading)); - - m_ui->actionTorrentFnOnDblClBox->setItemData(0, TOGGLE_PAUSE); - m_ui->actionTorrentFnOnDblClBox->setItemData(1, OPEN_DEST); - m_ui->actionTorrentFnOnDblClBox->setItemData(2, PREVIEW_FILE); - m_ui->actionTorrentFnOnDblClBox->setItemData(3, SHOW_OPTIONS); - m_ui->actionTorrentFnOnDblClBox->setItemData(4, NO_ACTION); - int actionSeeding = pref->getActionOnDblClOnTorrentFn(); - if ((actionSeeding < 0) || (actionSeeding >= m_ui->actionTorrentFnOnDblClBox->count())) - actionSeeding = OPEN_DEST; - m_ui->actionTorrentFnOnDblClBox->setCurrentIndex(m_ui->actionTorrentFnOnDblClBox->findData(actionSeeding)); - // End Downloads preferences +void OptionsDialog::loadConnectionTabOptions() +{ + const auto *session = BitTorrent::Session::instance(); - // Connection preferences m_ui->comboProtocol->setCurrentIndex(static_cast(session->btProtocol())); m_ui->spinPort->setValue(session->port()); m_ui->checkUPnP->setChecked(Net::PortForwarder::instance()->isEnabled()); @@ -1170,43 +836,160 @@ void OptionsDialog::loadOptions() enableProxy(m_ui->comboProxyType->currentIndex()); m_ui->checkIPFilter->setChecked(session->isIPFilteringEnabled()); + m_ui->textFilterPath->setDialogCaption(tr("Choose an IP filter file")); m_ui->textFilterPath->setEnabled(m_ui->checkIPFilter->isChecked()); + m_ui->textFilterPath->setFileNameFilter(tr("All supported filters") + u" (*.dat *.p2p *.p2b);;.dat (*.dat);;.p2p (*.p2p);;.p2b (*.p2b)"); m_ui->textFilterPath->setSelectedPath(session->IPFilterFile()); + + m_ui->IpFilterRefreshBtn->setIcon(UIThemeManager::instance()->getIcon(u"view-refresh"_qs)); m_ui->IpFilterRefreshBtn->setEnabled(m_ui->checkIPFilter->isChecked()); m_ui->checkIpFilterTrackers->setChecked(session->isTrackerFilteringEnabled()); - // End Connection preferences - // Speed preferences - m_ui->spinDownloadLimit->setValue(session->globalDownloadSpeedLimit() / 1024); + connect(m_ui->comboProtocol, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); + connect(m_ui->spinPort, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); + connect(m_ui->checkUPnP, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + + connect(m_ui->checkMaxConnections, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkMaxConnectionsPerTorrent, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkMaxUploads, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkMaxUploadsPerTorrent, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->spinMaxConnec, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); + connect(m_ui->spinMaxConnecPerTorrent, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); + connect(m_ui->spinMaxUploads, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); + connect(m_ui->spinMaxUploadsPerTorrent, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); + + connect(m_ui->comboProxyType, qComboBoxCurrentIndexChanged, this, &ThisType::enableProxy); + connect(m_ui->comboProxyType, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); + connect(m_ui->textProxyIP, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); + connect(m_ui->spinProxyPort, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); + connect(m_ui->checkProxyPeerConnections, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->isProxyOnlyForTorrents, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkProxyAuth, &QGroupBox::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->textProxyUsername, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); + connect(m_ui->textProxyPassword, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); + + connect(m_ui->checkIPFilter, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkIPFilter, &QAbstractButton::toggled, m_ui->textFilterPath, &QWidget::setEnabled); + connect(m_ui->checkIPFilter, &QAbstractButton::toggled, m_ui->IpFilterRefreshBtn, &QWidget::setEnabled); + connect(m_ui->textFilterPath, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton); + connect(m_ui->checkIpFilterTrackers, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); +} + +void OptionsDialog::saveConnectionTabOptions() const +{ + auto *session = BitTorrent::Session::instance(); + + session->setBTProtocol(static_cast(m_ui->comboProtocol->currentIndex())); + session->setPort(getPort()); + Net::PortForwarder::instance()->setEnabled(isUPnPEnabled()); + + session->setMaxConnections(getMaxConnections()); + session->setMaxConnectionsPerTorrent(getMaxConnectionsPerTorrent()); + session->setMaxUploads(getMaxUploads()); + session->setMaxUploadsPerTorrent(getMaxUploadsPerTorrent()); + + auto proxyConfigManager = Net::ProxyConfigurationManager::instance(); + Net::ProxyConfiguration proxyConf; + proxyConf.type = getProxyType(); + proxyConf.ip = getProxyIp(); + proxyConf.port = getProxyPort(); + proxyConf.username = getProxyUsername(); + proxyConf.password = getProxyPassword(); + proxyConfigManager->setProxyOnlyForTorrents(m_ui->isProxyOnlyForTorrents->isChecked()); + proxyConfigManager->setProxyConfiguration(proxyConf); + session->setProxyPeerConnectionsEnabled(m_ui->checkProxyPeerConnections->isChecked()); + + // IPFilter + session->setIPFilteringEnabled(isIPFilteringEnabled()); + session->setTrackerFilteringEnabled(m_ui->checkIpFilterTrackers->isChecked()); + session->setIPFilterFile(m_ui->textFilterPath->selectedPath()); +} + +void OptionsDialog::loadSpeedTabOptions() +{ + const auto *pref = Preferences::instance(); + const auto *session = BitTorrent::Session::instance(); + + m_ui->labelGlobalRate->setPixmap(Utils::Gui::scaledPixmapSvg(UIThemeManager::instance()->getIconPath(u"slow_off"_qs), this, Utils::Gui::mediumIconSize(this).height())); m_ui->spinUploadLimit->setValue(session->globalUploadSpeedLimit() / 1024); - m_ui->spinDownloadLimitAlt->setValue(session->altGlobalDownloadSpeedLimit() / 1024); + m_ui->spinDownloadLimit->setValue(session->globalDownloadSpeedLimit() / 1024); + + m_ui->labelAltRate->setPixmap(Utils::Gui::scaledPixmapSvg(UIThemeManager::instance()->getIconPath(u"slow"_qs), this, Utils::Gui::mediumIconSize(this).height())); m_ui->spinUploadLimitAlt->setValue(session->altGlobalUploadSpeedLimit() / 1024); + m_ui->spinDownloadLimitAlt->setValue(session->altGlobalDownloadSpeedLimit() / 1024); - m_ui->checkLimituTPConnections->setChecked(session->isUTPRateLimited()); - m_ui->checkLimitTransportOverhead->setChecked(session->includeOverheadInLimits()); - m_ui->checkLimitLocalPeerRate->setChecked(!session->ignoreLimitsOnLAN()); + m_ui->comboBoxScheduleDays->addItems(translatedWeekdayNames()); m_ui->groupBoxSchedule->setChecked(session->isBandwidthSchedulerEnabled()); m_ui->timeEditScheduleFrom->setTime(pref->getSchedulerStartTime()); m_ui->timeEditScheduleTo->setTime(pref->getSchedulerEndTime()); m_ui->comboBoxScheduleDays->setCurrentIndex(static_cast(pref->getSchedulerDays())); - // End Speed preferences - // Bittorrent preferences + m_ui->checkLimituTPConnections->setChecked(session->isUTPRateLimited()); + m_ui->checkLimitTransportOverhead->setChecked(session->includeOverheadInLimits()); + m_ui->checkLimitLocalPeerRate->setChecked(!session->ignoreLimitsOnLAN()); + + connect(m_ui->spinUploadLimit, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); + connect(m_ui->spinDownloadLimit, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); + + connect(m_ui->spinUploadLimitAlt, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); + connect(m_ui->spinDownloadLimitAlt, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); + + connect(m_ui->groupBoxSchedule, &QGroupBox::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->timeEditScheduleFrom, &QDateTimeEdit::timeChanged, this, &ThisType::enableApplyButton); + connect(m_ui->timeEditScheduleTo, &QDateTimeEdit::timeChanged, this, &ThisType::enableApplyButton); + connect(m_ui->comboBoxScheduleDays, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); + + connect(m_ui->checkLimituTPConnections, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkLimitTransportOverhead, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkLimitLocalPeerRate, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); +} + +void OptionsDialog::saveSpeedTabOptions() const +{ + auto *pref = Preferences::instance(); + auto *session = BitTorrent::Session::instance(); + + session->setGlobalUploadSpeedLimit(m_ui->spinUploadLimit->value() * 1024); + session->setGlobalDownloadSpeedLimit(m_ui->spinDownloadLimit->value() * 1024); + + session->setAltGlobalUploadSpeedLimit(m_ui->spinUploadLimitAlt->value() * 1024); + session->setAltGlobalDownloadSpeedLimit(m_ui->spinDownloadLimitAlt->value() * 1024); + + session->setBandwidthSchedulerEnabled(m_ui->groupBoxSchedule->isChecked()); + pref->setSchedulerStartTime(m_ui->timeEditScheduleFrom->time()); + pref->setSchedulerEndTime(m_ui->timeEditScheduleTo->time()); + pref->setSchedulerDays(static_cast(m_ui->comboBoxScheduleDays->currentIndex())); + + session->setUTPRateLimited(m_ui->checkLimituTPConnections->isChecked()); + session->setIncludeOverheadInLimits(m_ui->checkLimitTransportOverhead->isChecked()); + session->setIgnoreLimitsOnLAN(!m_ui->checkLimitLocalPeerRate->isChecked()); +} + +void OptionsDialog::loadBittorrentTabOptions() +{ + const auto *session = BitTorrent::Session::instance(); + m_ui->checkDHT->setChecked(session->isDHTEnabled()); m_ui->checkPeX->setChecked(session->isPeXEnabled()); m_ui->checkLSD->setChecked(session->isLSDEnabled()); m_ui->comboEncryption->setCurrentIndex(session->encryption()); m_ui->checkAnonymousMode->setChecked(session->isAnonymousModeEnabled()); + m_ui->spinBoxMaxActiveCheckingTorrents->setValue(session->maxActiveCheckingTorrents()); - m_ui->checkEnableAddTrackers->setChecked(session->isAddTrackersEnabled()); - m_ui->textTrackers->setPlainText(session->additionalTrackers()); m_ui->checkEnableQueueing->setChecked(session->isQueueingSystemEnabled()); m_ui->spinMaxActiveDownloads->setValue(session->maxActiveDownloads()); m_ui->spinMaxActiveUploads->setValue(session->maxActiveUploads()); m_ui->spinMaxActiveTorrents->setValue(session->maxActiveTorrents()); + m_ui->checkIgnoreSlowTorrentsForQueueing->setChecked(session->ignoreSlowTorrentsForQueueing()); + const QString slowTorrentsExplanation = u"

" + + tr("A torrent will be considered slow if its download and upload rates stay below these values for \"Torrent inactivity timer\" seconds") + + u"

"; + m_ui->labelDownloadRateForSlowTorrents->setToolTip(slowTorrentsExplanation); + m_ui->labelUploadRateForSlowTorrents->setToolTip(slowTorrentsExplanation); + m_ui->labelSlowTorrentInactivityTimer->setToolTip(slowTorrentsExplanation); m_ui->spinDownloadRateForSlowTorrents->setValue(session->downloadRateForSlowTorrents()); m_ui->spinUploadRateForSlowTorrents->setValue(session->uploadRateForSlowTorrents()); m_ui->spinSlowTorrentsInactivityTimer->setValue(session->slowTorrentsInactivityTimer()); @@ -1248,10 +1031,128 @@ void OptionsDialog::loadOptions() {EnableSuperSeeding, 3} }; m_ui->comboRatioLimitAct->setCurrentIndex(actIndex.value(session->maxRatioAction())); - // End Bittorrent preferences - // Web UI preferences - m_ui->textServerDomains->setText(pref->getServerDomains()); + m_ui->checkEnableAddTrackers->setChecked(session->isAddTrackersEnabled()); + m_ui->textTrackers->setPlainText(session->additionalTrackers()); + + connect(m_ui->checkDHT, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkPeX, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkLSD, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->comboEncryption, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); + connect(m_ui->checkAnonymousMode, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + + connect(m_ui->spinBoxMaxActiveCheckingTorrents, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); + + connect(m_ui->checkEnableQueueing, &QGroupBox::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->spinMaxActiveDownloads, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); + connect(m_ui->spinMaxActiveUploads, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); + connect(m_ui->spinMaxActiveTorrents, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); + connect(m_ui->checkIgnoreSlowTorrentsForQueueing, &QGroupBox::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->spinDownloadRateForSlowTorrents, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); + connect(m_ui->spinUploadRateForSlowTorrents, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); + connect(m_ui->spinSlowTorrentsInactivityTimer, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); + + connect(m_ui->checkMaxRatio, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkMaxRatio, &QAbstractButton::toggled, this, &ThisType::toggleComboRatioLimitAct); + connect(m_ui->spinMaxRatio, qOverload(&QDoubleSpinBox::valueChanged),this, &ThisType::enableApplyButton); + connect(m_ui->comboRatioLimitAct, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); + connect(m_ui->checkMaxSeedingMinutes, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkMaxSeedingMinutes, &QAbstractButton::toggled, this, &ThisType::toggleComboRatioLimitAct); + connect(m_ui->spinMaxSeedingMinutes, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); + + connect(m_ui->checkEnableAddTrackers, &QGroupBox::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->textTrackers, &QPlainTextEdit::textChanged, this, &ThisType::enableApplyButton); +} + +void OptionsDialog::saveBittorrentTabOptions() const +{ + auto *session = BitTorrent::Session::instance(); + + session->setDHTEnabled(isDHTEnabled()); + session->setPeXEnabled(m_ui->checkPeX->isChecked()); + session->setLSDEnabled(isLSDEnabled()); + session->setEncryption(getEncryptionSetting()); + session->setAnonymousModeEnabled(m_ui->checkAnonymousMode->isChecked()); + + session->setMaxActiveCheckingTorrents(m_ui->spinBoxMaxActiveCheckingTorrents->value()); + // Queueing system + session->setQueueingSystemEnabled(isQueueingSystemEnabled()); + session->setMaxActiveDownloads(m_ui->spinMaxActiveDownloads->value()); + session->setMaxActiveUploads(m_ui->spinMaxActiveUploads->value()); + session->setMaxActiveTorrents(m_ui->spinMaxActiveTorrents->value()); + session->setIgnoreSlowTorrentsForQueueing(m_ui->checkIgnoreSlowTorrentsForQueueing->isChecked()); + session->setDownloadRateForSlowTorrents(m_ui->spinDownloadRateForSlowTorrents->value()); + session->setUploadRateForSlowTorrents(m_ui->spinUploadRateForSlowTorrents->value()); + session->setSlowTorrentsInactivityTimer(m_ui->spinSlowTorrentsInactivityTimer->value()); + + session->setGlobalMaxRatio(getMaxRatio()); + session->setGlobalMaxSeedingMinutes(getMaxSeedingMinutes()); + const QVector actIndex = + { + Pause, + Remove, + DeleteFiles, + EnableSuperSeeding + }; + session->setMaxRatioAction(actIndex.value(m_ui->comboRatioLimitAct->currentIndex())); + + session->setAddTrackersEnabled(m_ui->checkEnableAddTrackers->isChecked()); + session->setAdditionalTrackers(m_ui->textTrackers->toPlainText()); +} + +void OptionsDialog::loadRSSTabOptions() +{ + const auto *rssSession = RSS::Session::instance(); + const auto *autoDownloader = RSS::AutoDownloader::instance(); + + m_ui->checkRSSEnable->setChecked(rssSession->isProcessingEnabled()); + m_ui->spinRSSRefreshInterval->setValue(rssSession->refreshInterval()); + m_ui->spinRSSMaxArticlesPerFeed->setValue(rssSession->maxArticlesPerFeed()); + m_ui->checkRSSAutoDownloaderEnable->setChecked(autoDownloader->isProcessingEnabled()); + m_ui->textSmartEpisodeFilters->setPlainText(autoDownloader->smartEpisodeFilters().join(u'\n')); + m_ui->checkSmartFilterDownloadRepacks->setChecked(autoDownloader->downloadRepacks()); + + connect(m_ui->checkRSSEnable, &QCheckBox::toggled, this, &OptionsDialog::enableApplyButton); + connect(m_ui->checkRSSAutoDownloaderEnable, &QCheckBox::toggled, this, &OptionsDialog::enableApplyButton); + connect(m_ui->btnEditRules, &QPushButton::clicked, this, [this]() + { + auto *downloader = new AutomatedRssDownloader(this); + downloader->setAttribute(Qt::WA_DeleteOnClose); + downloader->open(); + }); + connect(m_ui->textSmartEpisodeFilters, &QPlainTextEdit::textChanged, this, &OptionsDialog::enableApplyButton); + connect(m_ui->checkSmartFilterDownloadRepacks, &QCheckBox::toggled, this, &OptionsDialog::enableApplyButton); + connect(m_ui->spinRSSRefreshInterval, qSpinBoxValueChanged, this, &OptionsDialog::enableApplyButton); + connect(m_ui->spinRSSMaxArticlesPerFeed, qSpinBoxValueChanged, this, &OptionsDialog::enableApplyButton); +} + +void OptionsDialog::saveRSSTabOptions() const +{ + auto *rssSession = RSS::Session::instance(); + auto *autoDownloader = RSS::AutoDownloader::instance(); + + rssSession->setProcessingEnabled(m_ui->checkRSSEnable->isChecked()); + rssSession->setRefreshInterval(m_ui->spinRSSRefreshInterval->value()); + rssSession->setMaxArticlesPerFeed(m_ui->spinRSSMaxArticlesPerFeed->value()); + autoDownloader->setProcessingEnabled(m_ui->checkRSSAutoDownloaderEnable->isChecked()); + autoDownloader->setSmartEpisodeFilters(m_ui->textSmartEpisodeFilters->toPlainText().split(u'\n', Qt::SkipEmptyParts)); + autoDownloader->setDownloadRepacks(m_ui->checkSmartFilterDownloadRepacks->isChecked()); +} + +#ifndef DISABLE_WEBUI +void OptionsDialog::loadWebUITabOptions() +{ + const auto *pref = Preferences::instance(); + + m_ui->textWebUIHttpsCert->setMode(FileSystemPathEdit::Mode::FileOpen); + m_ui->textWebUIHttpsCert->setFileNameFilter(tr("Certificate") + u" (*.cer *.crt *.pem)"); + m_ui->textWebUIHttpsCert->setDialogCaption(tr("Select certificate")); + m_ui->textWebUIHttpsKey->setMode(FileSystemPathEdit::Mode::FileOpen); + m_ui->textWebUIHttpsKey->setFileNameFilter(tr("Private key") + u" (*.key *.pem)"); + m_ui->textWebUIHttpsKey->setDialogCaption(tr("Select private key")); + m_ui->textWebUIRootFolder->setMode(FileSystemPathEdit::Mode::DirectoryOpen); + m_ui->textWebUIRootFolder->setDialogCaption(tr("Choose Alternative UI files location")); + m_ui->checkWebUi->setChecked(pref->isWebUiEnabled()); m_ui->textWebUiAddress->setText(pref->getWebUiAddress()); m_ui->spinWebUiPort->setValue(pref->getWebUiPort()); @@ -1266,33 +1167,217 @@ void OptionsDialog::loadOptions() m_ui->spinBanCounter->setValue(pref->getWebUIMaxAuthFailCount()); m_ui->spinBanDuration->setValue(pref->getWebUIBanDuration().count()); m_ui->spinSessionTimeout->setValue(pref->getWebUISessionTimeout()); - + // Alternative UI + m_ui->groupAltWebUI->setChecked(pref->isAltWebUiEnabled()); + m_ui->textWebUIRootFolder->setSelectedPath(pref->getWebUiRootFolder()); // Security m_ui->checkClickjacking->setChecked(pref->isWebUiClickjackingProtectionEnabled()); m_ui->checkCSRFProtection->setChecked(pref->isWebUiCSRFProtectionEnabled()); m_ui->checkSecureCookie->setEnabled(pref->isWebUiHttpsEnabled()); m_ui->checkSecureCookie->setChecked(pref->isWebUiSecureCookieEnabled()); m_ui->groupHostHeaderValidation->setChecked(pref->isWebUIHostHeaderValidationEnabled()); - + m_ui->textServerDomains->setText(pref->getServerDomains()); + // Custom HTTP headers + m_ui->groupWebUIAddCustomHTTPHeaders->setChecked(pref->isWebUICustomHTTPHeadersEnabled()); + m_ui->textWebUICustomHTTPHeaders->setPlainText(pref->getWebUICustomHTTPHeaders()); + // Reverse proxy + m_ui->groupEnableReverseProxySupport->setChecked(pref->isWebUIReverseProxySupportEnabled()); + m_ui->textTrustedReverseProxiesList->setText(pref->getWebUITrustedReverseProxiesList()); + // DynDNS m_ui->checkDynDNS->setChecked(pref->isDynDNSEnabled()); m_ui->comboDNSService->setCurrentIndex(static_cast(pref->getDynDNSService())); m_ui->domainNameTxt->setText(pref->getDynDomainName()); m_ui->DNSUsernameTxt->setText(pref->getDynDNSUsername()); m_ui->DNSPasswordTxt->setText(pref->getDynDNSPassword()); - m_ui->groupAltWebUI->setChecked(pref->isAltWebUiEnabled()); - m_ui->textWebUIRootFolder->setSelectedPath(pref->getWebUiRootFolder()); + connect(m_ui->checkWebUi, &QGroupBox::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->textWebUiAddress, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); + connect(m_ui->spinWebUiPort, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); + connect(m_ui->checkWebUIUPnP, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkWebUiHttps, &QGroupBox::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->textWebUIHttpsCert, &FileSystemPathLineEdit::selectedPathChanged, this, &ThisType::enableApplyButton); + connect(m_ui->textWebUIHttpsCert, &FileSystemPathLineEdit::selectedPathChanged, this, &OptionsDialog::webUIHttpsCertChanged); + connect(m_ui->textWebUIHttpsKey, &FileSystemPathLineEdit::selectedPathChanged, this, &ThisType::enableApplyButton); + connect(m_ui->textWebUIHttpsKey, &FileSystemPathLineEdit::selectedPathChanged, this, &OptionsDialog::webUIHttpsKeyChanged); + + connect(m_ui->textWebUiUsername, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); + connect(m_ui->textWebUiPassword, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); + + connect(m_ui->checkBypassLocalAuth, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkBypassAuthSubnetWhitelist, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkBypassAuthSubnetWhitelist, &QAbstractButton::toggled, m_ui->IPSubnetWhitelistButton, &QPushButton::setEnabled); + connect(m_ui->spinBanCounter, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); + connect(m_ui->spinBanDuration, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); + connect(m_ui->spinSessionTimeout, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); + + connect(m_ui->groupAltWebUI, &QGroupBox::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->textWebUIRootFolder, &FileSystemPathLineEdit::selectedPathChanged, this, &ThisType::enableApplyButton); + + connect(m_ui->checkClickjacking, &QCheckBox::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkCSRFProtection, &QCheckBox::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->checkWebUiHttps, &QGroupBox::toggled, m_ui->checkSecureCookie, &QWidget::setEnabled); + connect(m_ui->checkSecureCookie, &QCheckBox::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->groupHostHeaderValidation, &QGroupBox::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->textServerDomains, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); + + connect(m_ui->groupWebUIAddCustomHTTPHeaders, &QGroupBox::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->textWebUICustomHTTPHeaders, &QPlainTextEdit::textChanged, this, &OptionsDialog::enableApplyButton); + + connect(m_ui->groupEnableReverseProxySupport, &QGroupBox::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->textTrustedReverseProxiesList, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); + + connect(m_ui->checkDynDNS, &QGroupBox::toggled, this, &ThisType::enableApplyButton); + connect(m_ui->comboDNSService, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); + connect(m_ui->domainNameTxt, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); + connect(m_ui->DNSUsernameTxt, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); + connect(m_ui->DNSPasswordTxt, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); +} + +void OptionsDialog::saveWebUITabOptions() const +{ + auto *pref = Preferences::instance(); + + pref->setWebUiEnabled(isWebUiEnabled()); + pref->setWebUiAddress(m_ui->textWebUiAddress->text()); + pref->setWebUiPort(m_ui->spinWebUiPort->value()); + pref->setUPnPForWebUIPort(m_ui->checkWebUIUPnP->isChecked()); + pref->setWebUiHttpsEnabled(m_ui->checkWebUiHttps->isChecked()); + pref->setWebUIHttpsCertificatePath(m_ui->textWebUIHttpsCert->selectedPath()); + pref->setWebUIHttpsKeyPath(m_ui->textWebUIHttpsKey->selectedPath()); + pref->setWebUIMaxAuthFailCount(m_ui->spinBanCounter->value()); + pref->setWebUIBanDuration(std::chrono::seconds {m_ui->spinBanDuration->value()}); + pref->setWebUISessionTimeout(m_ui->spinSessionTimeout->value()); + // Authentication + pref->setWebUiUsername(webUiUsername()); + if (!webUiPassword().isEmpty()) + pref->setWebUIPassword(Utils::Password::PBKDF2::generate(webUiPassword())); + pref->setWebUiLocalAuthEnabled(!m_ui->checkBypassLocalAuth->isChecked()); + pref->setWebUiAuthSubnetWhitelistEnabled(m_ui->checkBypassAuthSubnetWhitelist->isChecked()); + // Alternative UI + pref->setAltWebUiEnabled(m_ui->groupAltWebUI->isChecked()); + pref->setWebUiRootFolder(m_ui->textWebUIRootFolder->selectedPath()); + // Security + pref->setWebUiClickjackingProtectionEnabled(m_ui->checkClickjacking->isChecked()); + pref->setWebUiCSRFProtectionEnabled(m_ui->checkCSRFProtection->isChecked()); + pref->setWebUiSecureCookieEnabled(m_ui->checkSecureCookie->isChecked()); + pref->setWebUIHostHeaderValidationEnabled(m_ui->groupHostHeaderValidation->isChecked()); + pref->setServerDomains(m_ui->textServerDomains->text()); // Custom HTTP headers - m_ui->groupWebUIAddCustomHTTPHeaders->setChecked(pref->isWebUICustomHTTPHeadersEnabled()); - m_ui->textWebUICustomHTTPHeaders->setPlainText(pref->getWebUICustomHTTPHeaders()); + pref->setWebUICustomHTTPHeadersEnabled(m_ui->groupWebUIAddCustomHTTPHeaders->isChecked()); + pref->setWebUICustomHTTPHeaders(m_ui->textWebUICustomHTTPHeaders->toPlainText()); // Reverse proxy - m_ui->groupEnableReverseProxySupport->setChecked(pref->isWebUIReverseProxySupportEnabled()); - m_ui->textTrustedReverseProxiesList->setText(pref->getWebUITrustedReverseProxiesList()); - // End Web UI preferences + pref->setWebUIReverseProxySupportEnabled(m_ui->groupEnableReverseProxySupport->isChecked()); + pref->setWebUITrustedReverseProxiesList(m_ui->textTrustedReverseProxiesList->text()); + // DynDNS + pref->setDynDNSEnabled(m_ui->checkDynDNS->isChecked()); + pref->setDynDNSService(static_cast(m_ui->comboDNSService->currentIndex())); + pref->setDynDomainName(m_ui->domainNameTxt->text()); + pref->setDynDNSUsername(m_ui->DNSUsernameTxt->text()); + pref->setDynDNSPassword(m_ui->DNSPasswordTxt->text()); +} +#endif // DISABLE_WEBUI + +void OptionsDialog::initializeLanguageCombo() +{ + // List language files + const QDir langDir(u":/lang"_qs); + const QStringList langFiles = langDir.entryList(QStringList(u"qbittorrent_*.qm"_qs), QDir::Files); + for (const QString &langFile : langFiles) + { + QString localeStr = langFile.mid(12); // remove "qbittorrent_" + localeStr.chop(3); // Remove ".qm" + QString languageName; + if (localeStr.startsWith(u"eo", Qt::CaseInsensitive)) + { + // QLocale doesn't work with that locale. Esperanto isn't a "real" language. + languageName = C_LOCALE_ESPERANTO; + } + else if (localeStr.startsWith(u"ltg", Qt::CaseInsensitive)) + { + // QLocale doesn't work with that locale. + languageName = C_LOCALE_LATGALIAN; + } + else + { + QLocale locale(localeStr); + languageName = languageToLocalizedString(locale); + } + m_ui->comboI18n->addItem(/*QIcon(":/icons/flags/"+country+".svg"), */ languageName, localeStr); + qDebug() << "Supported locale:" << localeStr; + } +} + +void OptionsDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous) +{ + if (!current) + current = previous; + m_ui->tabOption->setCurrentIndex(m_ui->tabSelection->row(current)); +} + +void OptionsDialog::loadSplitterState() +{ + // width has been modified, use height as width reference instead + const int width = m_ui->tabSelection->item(TAB_UI)->sizeHint().height() * 2; + const QStringList defaultSizes = {QString::number(width), QString::number(m_ui->hsplitter->width() - width)}; + + QList splitterSizes; + for (const QString &string : asConst(m_storeHSplitterSize.get(defaultSizes))) + splitterSizes.append(string.toInt()); + + m_ui->hsplitter->setSizes(splitterSizes); +} + +void OptionsDialog::showEvent(QShowEvent *e) +{ + QDialog::showEvent(e); + + loadSplitterState(); +} + +void OptionsDialog::saveOptions() const +{ + auto *pref = Preferences::instance(); + + saveBehaviorTabOptions(); + saveDownloadsTabOptions(); + saveConnectionTabOptions(); + saveSpeedTabOptions(); + saveBittorrentTabOptions(); + saveRSSTabOptions(); +#ifndef DISABLE_WEBUI + saveWebUITabOptions(); +#endif + m_advancedSettings->saveAdvancedSettings(); + + // Assume that user changed multiple settings + // so it's best to save immediately + pref->apply(); +} + +bool OptionsDialog::isIPFilteringEnabled() const +{ + return m_ui->checkIPFilter->isChecked(); +} + +Net::ProxyType OptionsDialog::getProxyType() const +{ + switch (m_ui->comboProxyType->currentIndex()) + { + case 1: + return Net::ProxyType::SOCKS4; + case 2: + if (isProxyAuthEnabled()) + return Net::ProxyType::SOCKS5_PW; + return Net::ProxyType::SOCKS5; + case 3: + if (isProxyAuthEnabled()) + return Net::ProxyType::HTTP_PW; + return Net::ProxyType::HTTP; + default: + return Net::ProxyType::None; + } } -// return min & max ports -// [min, max] int OptionsDialog::getPort() const { return m_ui->spinPort->value(); @@ -1407,6 +1492,7 @@ void OptionsDialog::on_buttonBox_accepted() m_ui->tabSelection->setCurrentRow(TAB_SPEED); return; } +#ifndef DISABLE_WEBUI if (!webUIAuthenticationOk()) { m_ui->tabSelection->setCurrentRow(TAB_WEBUI); @@ -1417,6 +1503,7 @@ void OptionsDialog::on_buttonBox_accepted() m_ui->tabSelection->setCurrentRow(TAB_WEBUI); return; } +#endif m_applyButton->setEnabled(false); saveOptions(); @@ -1432,6 +1519,7 @@ void OptionsDialog::applySettings() m_ui->tabSelection->setCurrentRow(TAB_SPEED); return; } +#ifndef DISABLE_WEBUI if (!webUIAuthenticationOk()) { m_ui->tabSelection->setCurrentRow(TAB_WEBUI); @@ -1442,6 +1530,7 @@ void OptionsDialog::applySettings() m_ui->tabSelection->setCurrentRow(TAB_WEBUI); return; } +#endif m_applyButton->setEnabled(false); saveOptions(); @@ -1706,23 +1795,7 @@ Path OptionsDialog::getFilter() const return m_ui->textFilterPath->selectedPath(); } -// Web UI - -bool OptionsDialog::isWebUiEnabled() const -{ - return m_ui->checkWebUi->isChecked(); -} - -QString OptionsDialog::webUiUsername() const -{ - return m_ui->textWebUiUsername->text(); -} - -QString OptionsDialog::webUiPassword() const -{ - return m_ui->textWebUiPassword->text(); -} - +#ifndef DISABLE_WEBUI void OptionsDialog::webUIHttpsCertChanged(const Path &path) { const auto isCertFileValid = [&path]() -> bool @@ -1767,16 +1840,59 @@ void OptionsDialog::webUIHttpsKeyChanged(const Path &path) isKeyFileValid() ? u"security-high"_qs : u"security-low"_qs), this, 24)); } +bool OptionsDialog::isWebUiEnabled() const +{ + return m_ui->checkWebUi->isChecked(); +} + +QString OptionsDialog::webUiUsername() const +{ + return m_ui->textWebUiUsername->text(); +} + +QString OptionsDialog::webUiPassword() const +{ + return m_ui->textWebUiPassword->text(); +} + +bool OptionsDialog::webUIAuthenticationOk() +{ + if (webUiUsername().length() < 3) + { + QMessageBox::warning(this, tr("Length Error"), tr("The Web UI username must be at least 3 characters long.")); + return false; + } + if (!webUiPassword().isEmpty() && (webUiPassword().length() < 6)) + { + QMessageBox::warning(this, tr("Length Error"), tr("The Web UI password must be at least 6 characters long.")); + return false; + } + return true; +} + +bool OptionsDialog::isAlternativeWebUIPathValid() +{ + if (m_ui->groupAltWebUI->isChecked() && m_ui->textWebUIRootFolder->selectedPath().isEmpty()) + { + QMessageBox::warning(this, tr("Location Error"), tr("The alternative Web UI files location cannot be blank.")); + return false; + } + return true; +} +#endif + void OptionsDialog::showConnectionTab() { m_ui->tabSelection->setCurrentRow(TAB_CONNECTION); } +#ifndef DISABLE_WEBUI void OptionsDialog::on_registerDNSBtn_clicked() { const auto service = static_cast(m_ui->comboDNSService->currentIndex()); QDesktopServices::openUrl(Net::DNSUpdater::getRegistrationUrl(service)); } +#endif void OptionsDialog::on_IpFilterRefreshBtn_clicked() { @@ -1812,31 +1928,6 @@ bool OptionsDialog::schedTimesOk() return true; } -bool OptionsDialog::webUIAuthenticationOk() -{ - if (webUiUsername().length() < 3) - { - QMessageBox::warning(this, tr("Length Error"), tr("The Web UI username must be at least 3 characters long.")); - return false; - } - if (!webUiPassword().isEmpty() && (webUiPassword().length() < 6)) - { - QMessageBox::warning(this, tr("Length Error"), tr("The Web UI password must be at least 6 characters long.")); - return false; - } - return true; -} - -bool OptionsDialog::isAlternativeWebUIPathValid() -{ - if (m_ui->groupAltWebUI->isChecked() && m_ui->textWebUIRootFolder->selectedPath().isEmpty()) - { - QMessageBox::warning(this, tr("Location Error"), tr("The alternative Web UI files location cannot be blank.")); - return false; - } - return true; -} - void OptionsDialog::on_banListButton_clicked() { auto dialog = new BanListOptionsDialog(this); diff --git a/src/gui/optionsdialog.h b/src/gui/optionsdialog.h index 4927ea535..b3d9788b4 100644 --- a/src/gui/optionsdialog.h +++ b/src/gui/optionsdialog.h @@ -103,19 +103,45 @@ private slots: void on_addWatchedFolderButton_clicked(); void on_editWatchedFolderButton_clicked(); void on_removeWatchedFolderButton_clicked(); - void on_registerDNSBtn_clicked(); void setLocale(const QString &localeStr); + +#ifndef DISABLE_WEBUI void webUIHttpsCertChanged(const Path &path); void webUIHttpsKeyChanged(const Path &path); + void on_registerDNSBtn_clicked(); +#endif private: void showEvent(QShowEvent *e) override; // Methods - void saveOptions(); - void loadOptions(); - void initializeLanguageCombo(); + void saveOptions() const; + + void loadBehaviorTabOptions(); + void saveBehaviorTabOptions() const; + + void loadDownloadsTabOptions(); + void saveDownloadsTabOptions() const; + + void loadConnectionTabOptions(); + void saveConnectionTabOptions() const; + + void loadSpeedTabOptions(); + void saveSpeedTabOptions() const; + + void loadBittorrentTabOptions(); + void saveBittorrentTabOptions() const; + + void loadRSSTabOptions(); + void saveRSSTabOptions() const; + +#ifndef DISABLE_WEBUI + void loadWebUITabOptions(); + void saveWebUITabOptions() const; +#endif // DISABLE_WEBUI + // General options + void initializeLanguageCombo(); QString getLocale() const; bool startMinimized() const; bool isSplashScreenDisabled() const; @@ -158,11 +184,13 @@ private: int getMaxActiveUploads() const; int getMaxActiveTorrents() const; // WebUI +#ifndef DISABLE_WEBUI bool isWebUiEnabled() const; QString webUiUsername() const; QString webUiPassword() const; bool webUIAuthenticationOk(); bool isAlternativeWebUIPathValid(); +#endif bool schedTimesOk();