Change "metadata received" stop condition behavior
[qBittorrent.git] / src / gui / optionsdialog.cpp
blobd0643688d0a9757f4cf7786bb0f9ecfdce1f30fc
1 /*
2 * Bittorrent Client using Qt and libtorrent.
3 * Copyright (C) 2023 Vladimir Golovnev <glassez@yandex.ru>
4 * Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * In addition, as a special exception, the copyright holders give permission to
21 * link this program with the OpenSSL project's "OpenSSL" library (or with
22 * modified versions of it that use the same license as the "OpenSSL" library),
23 * and distribute the linked executables. You must obey the GNU General Public
24 * License in all respects for all of the code used other than "OpenSSL". If you
25 * modify file(s), you may extend this exception to your version of the file(s),
26 * but you are not obligated to do so. If you do not wish to do so, delete this
27 * exception statement from your version.
30 #include "optionsdialog.h"
32 #include <cstdlib>
33 #include <limits>
35 #include <QApplication>
36 #include <QDebug>
37 #include <QDesktopServices>
38 #include <QDialogButtonBox>
39 #include <QEvent>
40 #include <QFileDialog>
41 #include <QMessageBox>
42 #include <QSystemTrayIcon>
43 #include <QTranslator>
45 #include "base/bittorrent/session.h"
46 #include "base/exceptions.h"
47 #include "base/global.h"
48 #include "base/net/portforwarder.h"
49 #include "base/net/proxyconfigurationmanager.h"
50 #include "base/path.h"
51 #include "base/preferences.h"
52 #include "base/rss/rss_autodownloader.h"
53 #include "base/rss/rss_session.h"
54 #include "base/torrentfileguard.h"
55 #include "base/torrentfileswatcher.h"
56 #include "base/utils/io.h"
57 #include "base/utils/misc.h"
58 #include "base/utils/net.h"
59 #include "base/utils/os.h"
60 #include "base/utils/password.h"
61 #include "base/utils/random.h"
62 #include "addnewtorrentdialog.h"
63 #include "advancedsettings.h"
64 #include "banlistoptionsdialog.h"
65 #include "interfaces/iguiapplication.h"
66 #include "ipsubnetwhitelistoptionsdialog.h"
67 #include "rss/automatedrssdownloader.h"
68 #include "ui_optionsdialog.h"
69 #include "uithemedialog.h"
70 #include "uithememanager.h"
71 #include "utils.h"
72 #include "watchedfolderoptionsdialog.h"
73 #include "watchedfoldersmodel.h"
74 #include "webui/webui.h"
76 #ifndef DISABLE_WEBUI
77 #include "base/net/dnsupdater.h"
78 #endif
80 #if defined Q_OS_MACOS || defined Q_OS_WIN
81 #include "base/utils/os.h"
82 #endif // defined Q_OS_MACOS || defined Q_OS_WIN
84 #define SETTINGS_KEY(name) u"OptionsDialog/" name
86 const int WEBUI_MIN_USERNAME_LENGTH = 3;
87 const int WEBUI_MIN_PASSWORD_LENGTH = 6;
89 namespace
91 QStringList translatedWeekdayNames()
93 // return translated strings from Monday to Sunday in user selected locale
95 const QLocale locale {Preferences::instance()->getLocale()};
96 const QDate date {2018, 11, 5}; // Monday
97 QStringList ret;
98 for (int i = 0; i < 7; ++i)
99 ret.append(locale.toString(date.addDays(i), u"dddd"_s));
100 return ret;
103 class WheelEventEater final : public QObject
105 public:
106 using QObject::QObject;
108 private:
109 bool eventFilter(QObject *, QEvent *event) override
111 return (event->type() == QEvent::Wheel);
115 bool isValidWebUIUsername(const QString &username)
117 return (username.length() >= WEBUI_MIN_USERNAME_LENGTH);
120 bool isValidWebUIPassword(const QString &password)
122 return (password.length() >= WEBUI_MIN_PASSWORD_LENGTH);
125 // Shortcuts for frequently used signals that have more than one overload. They would require
126 // type casts and that is why we declare required member pointer here instead.
127 void (QComboBox::*qComboBoxCurrentIndexChanged)(int) = &QComboBox::currentIndexChanged;
128 void (QSpinBox::*qSpinBoxValueChanged)(int) = &QSpinBox::valueChanged;
131 // Constructor
132 OptionsDialog::OptionsDialog(IGUIApplication *app, QWidget *parent)
133 : GUIApplicationComponent(app, parent)
134 , m_ui {new Ui::OptionsDialog}
135 , m_storeDialogSize {SETTINGS_KEY(u"Size"_s)}
136 , m_storeHSplitterSize {SETTINGS_KEY(u"HorizontalSplitterSizes"_s)}
137 , m_storeLastViewedPage {SETTINGS_KEY(u"LastViewedPage"_s)}
139 m_ui->setupUi(this);
140 m_applyButton = m_ui->buttonBox->button(QDialogButtonBox::Apply);
142 #ifdef Q_OS_UNIX
143 setWindowTitle(tr("Preferences"));
144 #endif
146 m_ui->hsplitter->setCollapsible(0, false);
147 m_ui->hsplitter->setCollapsible(1, false);
149 // Main icons
150 m_ui->tabSelection->item(TAB_UI)->setIcon(UIThemeManager::instance()->getIcon(u"preferences-desktop"_s));
151 m_ui->tabSelection->item(TAB_BITTORRENT)->setIcon(UIThemeManager::instance()->getIcon(u"preferences-bittorrent"_s, u"preferences-system-network"_s));
152 m_ui->tabSelection->item(TAB_CONNECTION)->setIcon(UIThemeManager::instance()->getIcon(u"network-connect"_s, u"network-wired"_s));
153 m_ui->tabSelection->item(TAB_DOWNLOADS)->setIcon(UIThemeManager::instance()->getIcon(u"download"_s, u"folder-download"_s));
154 m_ui->tabSelection->item(TAB_SPEED)->setIcon(UIThemeManager::instance()->getIcon(u"speedometer"_s, u"chronometer"_s));
155 m_ui->tabSelection->item(TAB_RSS)->setIcon(UIThemeManager::instance()->getIcon(u"application-rss"_s, u"application-rss+xml"_s));
156 #ifdef DISABLE_WEBUI
157 m_ui->tabSelection->item(TAB_WEBUI)->setHidden(true);
158 #else
159 m_ui->tabSelection->item(TAB_WEBUI)->setIcon(UIThemeManager::instance()->getIcon(u"preferences-webui"_s, u"network-server"_s));
160 #endif
161 m_ui->tabSelection->item(TAB_ADVANCED)->setIcon(UIThemeManager::instance()->getIcon(u"preferences-advanced"_s, u"preferences-other"_s));
163 // set uniform size for all icons
164 int maxHeight = -1;
165 for (int i = 0; i < m_ui->tabSelection->count(); ++i)
166 maxHeight = std::max(maxHeight, m_ui->tabSelection->visualItemRect(m_ui->tabSelection->item(i)).size().height());
167 for (int i = 0; i < m_ui->tabSelection->count(); ++i)
169 const QSize size(std::numeric_limits<int>::max(), static_cast<int>(maxHeight * 1.2));
170 m_ui->tabSelection->item(i)->setSizeHint(size);
173 connect(m_ui->tabSelection, &QListWidget::currentItemChanged, this, &ThisType::changePage);
175 // Load options
176 loadBehaviorTabOptions();
177 loadDownloadsTabOptions();
178 loadConnectionTabOptions();
179 loadSpeedTabOptions();
180 loadBittorrentTabOptions();
181 loadRSSTabOptions();
182 #ifndef DISABLE_WEBUI
183 loadWebUITabOptions();
184 #endif
186 // Load Advanced settings
187 m_advancedSettings = new AdvancedSettings(app, m_ui->tabAdvancedPage);
188 m_ui->advPageLayout->addWidget(m_advancedSettings);
189 connect(m_advancedSettings, &AdvancedSettings::settingsChanged, this, &ThisType::enableApplyButton);
191 // setup apply button
192 m_applyButton->setEnabled(false);
193 connect(m_applyButton, &QPushButton::clicked, this, [this]
195 if (applySettings())
196 m_applyButton->setEnabled(false);
199 // disable mouse wheel event on widgets to avoid misselection
200 auto *wheelEventEater = new WheelEventEater(this);
201 for (QComboBox *widget : asConst(findChildren<QComboBox *>()))
202 widget->installEventFilter(wheelEventEater);
203 for (QSpinBox *widget : asConst(findChildren<QSpinBox *>()))
204 widget->installEventFilter(wheelEventEater);
206 m_ui->tabSelection->setCurrentRow(m_storeLastViewedPage);
208 if (const QSize dialogSize = m_storeDialogSize; dialogSize.isValid())
209 resize(dialogSize);
212 OptionsDialog::~OptionsDialog()
214 // save dialog states
215 m_storeDialogSize = size();
217 QStringList hSplitterSizes;
218 for (const int size : asConst(m_ui->hsplitter->sizes()))
219 hSplitterSizes.append(QString::number(size));
220 m_storeHSplitterSize = hSplitterSizes;
222 m_storeLastViewedPage = m_ui->tabSelection->currentRow();
224 delete m_ui;
227 void OptionsDialog::loadBehaviorTabOptions()
229 const auto *pref = Preferences::instance();
230 const auto *session = BitTorrent::Session::instance();
232 initializeLanguageCombo();
233 setLocale(pref->getLocale());
235 m_ui->checkUseCustomTheme->setChecked(Preferences::instance()->useCustomUITheme());
236 m_ui->customThemeFilePath->setSelectedPath(Preferences::instance()->customUIThemePath());
237 m_ui->customThemeFilePath->setMode(FileSystemPathEdit::Mode::FileOpen);
238 m_ui->customThemeFilePath->setDialogCaption(tr("Select qBittorrent UI Theme file"));
239 m_ui->customThemeFilePath->setFileNameFilter(tr("qBittorrent UI Theme file (*.qbtheme config.json)"));
240 #if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS))
241 m_ui->checkUseSystemIcon->setChecked(pref->useSystemIcons());
242 #else
243 m_ui->checkUseSystemIcon->setVisible(false);
244 #endif
246 m_ui->confirmDeletion->setChecked(pref->confirmTorrentDeletion());
247 m_ui->checkAltRowColors->setChecked(pref->useAlternatingRowColors());
248 m_ui->checkHideZero->setChecked(pref->getHideZeroValues());
249 m_ui->comboHideZero->setCurrentIndex(pref->getHideZeroComboValues());
250 m_ui->comboHideZero->setEnabled(m_ui->checkHideZero->isChecked());
252 m_ui->actionTorrentDlOnDblClBox->setItemData(0, TOGGLE_PAUSE);
253 m_ui->actionTorrentDlOnDblClBox->setItemData(1, OPEN_DEST);
254 m_ui->actionTorrentDlOnDblClBox->setItemData(2, PREVIEW_FILE);
255 m_ui->actionTorrentDlOnDblClBox->setItemData(3, SHOW_OPTIONS);
256 m_ui->actionTorrentDlOnDblClBox->setItemData(4, NO_ACTION);
257 int actionDownloading = pref->getActionOnDblClOnTorrentDl();
258 if ((actionDownloading < 0) || (actionDownloading >= m_ui->actionTorrentDlOnDblClBox->count()))
259 actionDownloading = TOGGLE_PAUSE;
260 m_ui->actionTorrentDlOnDblClBox->setCurrentIndex(m_ui->actionTorrentDlOnDblClBox->findData(actionDownloading));
262 m_ui->actionTorrentFnOnDblClBox->setItemData(0, TOGGLE_PAUSE);
263 m_ui->actionTorrentFnOnDblClBox->setItemData(1, OPEN_DEST);
264 m_ui->actionTorrentFnOnDblClBox->setItemData(2, PREVIEW_FILE);
265 m_ui->actionTorrentFnOnDblClBox->setItemData(3, SHOW_OPTIONS);
266 m_ui->actionTorrentFnOnDblClBox->setItemData(4, NO_ACTION);
267 int actionSeeding = pref->getActionOnDblClOnTorrentFn();
268 if ((actionSeeding < 0) || (actionSeeding >= m_ui->actionTorrentFnOnDblClBox->count()))
269 actionSeeding = OPEN_DEST;
270 m_ui->actionTorrentFnOnDblClBox->setCurrentIndex(m_ui->actionTorrentFnOnDblClBox->findData(actionSeeding));
272 m_ui->checkBoxHideZeroStatusFilters->setChecked(pref->getHideZeroStatusFilters());
274 #ifndef Q_OS_WIN
275 m_ui->checkStartup->setVisible(false);
276 #endif
277 m_ui->checkShowSplash->setChecked(!pref->isSplashScreenDisabled());
278 m_ui->checkProgramExitConfirm->setChecked(pref->confirmOnExit());
279 m_ui->checkProgramAutoExitConfirm->setChecked(!pref->dontConfirmAutoExit());
280 m_ui->checkConfirmPauseAndResumeAll->setChecked(pref->confirmPauseAndResumeAll());
282 m_ui->windowStateComboBox->addItem(tr("Normal"), QVariant::fromValue(WindowState::Normal));
283 m_ui->windowStateComboBox->addItem(tr("Minimized"), QVariant::fromValue(WindowState::Minimized));
284 #ifndef Q_OS_MACOS
285 m_ui->windowStateComboBox->addItem(tr("Hidden"), QVariant::fromValue(WindowState::Hidden));
286 #endif
287 m_ui->windowStateComboBox->setCurrentIndex(m_ui->windowStateComboBox->findData(QVariant::fromValue(app()->startUpWindowState())));
289 #if !(defined(Q_OS_WIN) || defined(Q_OS_MACOS))
290 m_ui->groupFileAssociation->setVisible(false);
291 m_ui->checkProgramUpdates->setVisible(false);
292 #endif
294 #ifndef Q_OS_MACOS
295 // Disable systray integration if it is not supported by the system
296 if (!QSystemTrayIcon::isSystemTrayAvailable())
298 m_ui->checkShowSystray->setChecked(false);
299 m_ui->checkShowSystray->setEnabled(false);
300 m_ui->checkShowSystray->setToolTip(tr("Disabled due to failed to detect system tray presence"));
302 m_ui->checkShowSystray->setChecked(pref->systemTrayEnabled());
303 m_ui->checkMinimizeToSysTray->setChecked(pref->minimizeToTray());
304 m_ui->checkCloseToSystray->setChecked(pref->closeToTray());
305 m_ui->comboTrayIcon->setCurrentIndex(static_cast<int>(pref->trayIconStyle()));
306 #endif
308 #ifdef Q_OS_WIN
309 m_ui->checkStartup->setChecked(pref->WinStartup());
310 #endif
312 #ifdef Q_OS_MACOS
313 m_ui->checkShowSystray->setVisible(false);
314 m_ui->checkAssociateTorrents->setChecked(Utils::OS::isTorrentFileAssocSet());
315 m_ui->checkAssociateTorrents->setEnabled(!m_ui->checkAssociateTorrents->isChecked());
316 m_ui->checkAssociateMagnetLinks->setChecked(Utils::OS::isMagnetLinkAssocSet());
317 m_ui->checkAssociateMagnetLinks->setEnabled(!m_ui->checkAssociateMagnetLinks->isChecked());
318 #endif
320 #if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
321 m_ui->checkProgramUpdates->setChecked(pref->isUpdateCheckEnabled());
322 #endif
324 m_ui->checkPreventFromSuspendWhenDownloading->setChecked(pref->preventFromSuspendWhenDownloading());
325 m_ui->checkPreventFromSuspendWhenSeeding->setChecked(pref->preventFromSuspendWhenSeeding());
327 m_ui->textFileLogPath->setDialogCaption(tr("Choose a save directory"));
328 m_ui->textFileLogPath->setMode(FileSystemPathEdit::Mode::DirectorySave);
329 m_ui->textFileLogPath->setSelectedPath(app()->fileLoggerPath());
330 const bool fileLogBackup = app()->isFileLoggerBackup();
331 m_ui->checkFileLogBackup->setChecked(fileLogBackup);
332 m_ui->spinFileLogSize->setEnabled(fileLogBackup);
333 const bool fileLogDelete = app()->isFileLoggerDeleteOld();
334 m_ui->checkFileLogDelete->setChecked(fileLogDelete);
335 m_ui->spinFileLogAge->setEnabled(fileLogDelete);
336 m_ui->comboFileLogAgeType->setEnabled(fileLogDelete);
337 m_ui->spinFileLogSize->setValue(app()->fileLoggerMaxSize() / 1024);
338 m_ui->spinFileLogAge->setValue(app()->fileLoggerAge());
339 m_ui->comboFileLogAgeType->setCurrentIndex(app()->fileLoggerAgeType());
340 // Groupbox's check state must be initialized after some of its children if they are manually enabled/disabled
341 m_ui->checkFileLog->setChecked(app()->isFileLoggerEnabled());
343 m_ui->checkBoxPerformanceWarning->setChecked(session->isPerformanceWarningEnabled());
345 connect(m_ui->comboI18n, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
347 #if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS))
348 connect(m_ui->checkUseSystemIcon, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
349 #endif
350 connect(m_ui->checkUseCustomTheme, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
351 connect(m_ui->customThemeFilePath, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
353 m_ui->buttonCustomizeUITheme->setEnabled(!m_ui->checkUseCustomTheme->isChecked());
354 connect(m_ui->checkUseCustomTheme, &QGroupBox::toggled, this, [this]
356 m_ui->buttonCustomizeUITheme->setEnabled(!m_ui->checkUseCustomTheme->isChecked());
358 connect(m_ui->buttonCustomizeUITheme, &QPushButton::clicked, this, [this]
360 auto *dialog = new UIThemeDialog(this);
361 dialog->setAttribute(Qt::WA_DeleteOnClose);
362 dialog->open();
365 connect(m_ui->confirmDeletion, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
366 connect(m_ui->checkAltRowColors, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
367 connect(m_ui->checkHideZero, &QAbstractButton::toggled, m_ui->comboHideZero, &QWidget::setEnabled);
368 connect(m_ui->checkHideZero, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
369 connect(m_ui->comboHideZero, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
370 connect(m_ui->actionTorrentDlOnDblClBox, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
371 connect(m_ui->actionTorrentFnOnDblClBox, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
372 connect(m_ui->checkBoxHideZeroStatusFilters, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
374 #ifdef Q_OS_WIN
375 connect(m_ui->checkStartup, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
376 #endif
377 connect(m_ui->checkShowSplash, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
378 connect(m_ui->checkProgramExitConfirm, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
379 connect(m_ui->checkProgramAutoExitConfirm, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
380 connect(m_ui->checkConfirmPauseAndResumeAll, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
381 connect(m_ui->checkShowSystray, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
382 connect(m_ui->checkMinimizeToSysTray, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
383 connect(m_ui->checkCloseToSystray, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
384 connect(m_ui->comboTrayIcon, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
385 connect(m_ui->windowStateComboBox, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
387 connect(m_ui->checkPreventFromSuspendWhenDownloading, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
388 connect(m_ui->checkPreventFromSuspendWhenSeeding, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
390 #if defined(Q_OS_MACOS)
391 connect(m_ui->checkAssociateTorrents, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
392 connect(m_ui->checkAssociateMagnetLinks, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
393 #endif
395 #if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
396 connect(m_ui->checkProgramUpdates, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
397 #endif
399 #ifdef Q_OS_WIN
400 m_ui->assocPanel->hide();
401 #endif
403 #ifdef Q_OS_MAC
404 m_ui->defaultProgramPanel->hide();
405 #endif
407 #if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) && !defined(QBT_USES_DBUS)
408 m_ui->checkPreventFromSuspendWhenDownloading->setDisabled(true);
409 m_ui->checkPreventFromSuspendWhenSeeding->setDisabled(true);
410 #endif
412 connect(m_ui->checkFileLog, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
413 connect(m_ui->textFileLogPath, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
414 connect(m_ui->checkFileLogBackup, &QAbstractButton::toggled, m_ui->spinFileLogSize, &QWidget::setEnabled);
415 connect(m_ui->checkFileLogBackup, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
416 connect(m_ui->checkFileLogDelete, &QAbstractButton::toggled, m_ui->comboFileLogAgeType, &QWidget::setEnabled);
417 connect(m_ui->checkFileLogDelete, &QAbstractButton::toggled, m_ui->spinFileLogAge, &QWidget::setEnabled);
418 connect(m_ui->checkFileLogDelete, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
419 connect(m_ui->spinFileLogSize, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
420 connect(m_ui->spinFileLogAge, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
421 connect(m_ui->comboFileLogAgeType, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
423 connect(m_ui->checkBoxPerformanceWarning, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
426 void OptionsDialog::saveBehaviorTabOptions() const
428 auto *pref = Preferences::instance();
429 auto *session = BitTorrent::Session::instance();
431 // Load the translation
432 const QString locale = getLocale();
433 if (pref->getLocale() != locale)
435 auto *translator = new QTranslator;
436 if (translator->load(u":/lang/qbittorrent_"_s + locale))
437 qDebug("%s locale recognized, using translation.", qUtf8Printable(locale));
438 else
439 qDebug("%s locale unrecognized, using default (en).", qUtf8Printable(locale));
440 qApp->installTranslator(translator);
442 pref->setLocale(locale);
444 #if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS))
445 pref->useSystemIcons(m_ui->checkUseSystemIcon->isChecked());
446 #endif
447 pref->setUseCustomUITheme(m_ui->checkUseCustomTheme->isChecked());
448 pref->setCustomUIThemePath(m_ui->customThemeFilePath->selectedPath());
450 pref->setConfirmTorrentDeletion(m_ui->confirmDeletion->isChecked());
451 pref->setAlternatingRowColors(m_ui->checkAltRowColors->isChecked());
452 pref->setHideZeroValues(m_ui->checkHideZero->isChecked());
453 pref->setHideZeroComboValues(m_ui->comboHideZero->currentIndex());
455 pref->setActionOnDblClOnTorrentDl(m_ui->actionTorrentDlOnDblClBox->currentData().toInt());
456 pref->setActionOnDblClOnTorrentFn(m_ui->actionTorrentFnOnDblClBox->currentData().toInt());
458 pref->setHideZeroStatusFilters(m_ui->checkBoxHideZeroStatusFilters->isChecked());
460 pref->setSplashScreenDisabled(isSplashScreenDisabled());
461 pref->setConfirmOnExit(m_ui->checkProgramExitConfirm->isChecked());
462 pref->setDontConfirmAutoExit(!m_ui->checkProgramAutoExitConfirm->isChecked());
463 pref->setConfirmPauseAndResumeAll(m_ui->checkConfirmPauseAndResumeAll->isChecked());
465 #ifdef Q_OS_WIN
466 pref->setWinStartup(WinStartup());
467 #endif
469 #ifndef Q_OS_MACOS
470 pref->setSystemTrayEnabled(m_ui->checkShowSystray->isChecked());
471 pref->setTrayIconStyle(TrayIcon::Style(m_ui->comboTrayIcon->currentIndex()));
472 pref->setCloseToTray(m_ui->checkCloseToSystray->isChecked());
473 pref->setMinimizeToTray(m_ui->checkMinimizeToSysTray->isChecked());
474 #endif
476 #ifdef Q_OS_MACOS
477 if (m_ui->checkAssociateTorrents->isChecked())
479 Utils::OS::setTorrentFileAssoc();
480 m_ui->checkAssociateTorrents->setChecked(Utils::OS::isTorrentFileAssocSet());
481 m_ui->checkAssociateTorrents->setEnabled(!m_ui->checkAssociateTorrents->isChecked());
483 if (m_ui->checkAssociateMagnetLinks->isChecked())
485 Utils::OS::setMagnetLinkAssoc();
486 m_ui->checkAssociateMagnetLinks->setChecked(Utils::OS::isMagnetLinkAssocSet());
487 m_ui->checkAssociateMagnetLinks->setEnabled(!m_ui->checkAssociateMagnetLinks->isChecked());
489 #endif
491 #if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
492 pref->setUpdateCheckEnabled(m_ui->checkProgramUpdates->isChecked());
493 #endif
495 pref->setPreventFromSuspendWhenDownloading(m_ui->checkPreventFromSuspendWhenDownloading->isChecked());
496 pref->setPreventFromSuspendWhenSeeding(m_ui->checkPreventFromSuspendWhenSeeding->isChecked());
498 app()->setFileLoggerPath(m_ui->textFileLogPath->selectedPath());
499 app()->setFileLoggerBackup(m_ui->checkFileLogBackup->isChecked());
500 app()->setFileLoggerMaxSize(m_ui->spinFileLogSize->value() * 1024);
501 app()->setFileLoggerAge(m_ui->spinFileLogAge->value());
502 app()->setFileLoggerAgeType(m_ui->comboFileLogAgeType->currentIndex());
503 app()->setFileLoggerDeleteOld(m_ui->checkFileLogDelete->isChecked());
504 app()->setFileLoggerEnabled(m_ui->checkFileLog->isChecked());
506 app()->setStartUpWindowState(m_ui->windowStateComboBox->currentData().value<WindowState>());
508 session->setPerformanceWarningEnabled(m_ui->checkBoxPerformanceWarning->isChecked());
511 void OptionsDialog::loadDownloadsTabOptions()
513 const auto *pref = Preferences::instance();
514 const auto *session = BitTorrent::Session::instance();
516 m_ui->checkAdditionDialog->setChecked(pref->isAddNewTorrentDialogEnabled());
517 m_ui->checkAdditionDialogFront->setChecked(pref->isAddNewTorrentDialogTopLevel());
519 m_ui->contentLayoutComboBox->setCurrentIndex(static_cast<int>(session->torrentContentLayout()));
520 m_ui->checkAddToQueueTop->setChecked(session->isAddTorrentToQueueTop());
521 m_ui->checkStartPaused->setChecked(session->isAddTorrentPaused());
523 m_ui->stopConditionComboBox->setToolTip(
524 u"<html><body><p><b>" + tr("None") + u"</b> - " + tr("No stop condition is set.") + u"</p><p><b>" +
525 tr("Metadata received") + u"</b> - " + tr("Torrent will stop after metadata is received.") +
526 u" <em>" + tr("Torrents that have metadata initially will be added as stopped.") + u"</em></p><p><b>" +
527 tr("Files checked") + u"</b> - " + tr("Torrent will stop after files are initially checked.") +
528 u" <em>" + tr("This will also download metadata if it wasn't there initially.") + u"</em></p></body></html>");
529 m_ui->stopConditionComboBox->setItemData(0, QVariant::fromValue(BitTorrent::Torrent::StopCondition::None));
530 m_ui->stopConditionComboBox->setItemData(1, QVariant::fromValue(BitTorrent::Torrent::StopCondition::MetadataReceived));
531 m_ui->stopConditionComboBox->setItemData(2, QVariant::fromValue(BitTorrent::Torrent::StopCondition::FilesChecked));
532 m_ui->stopConditionComboBox->setCurrentIndex(m_ui->stopConditionComboBox->findData(QVariant::fromValue(session->torrentStopCondition())));
533 m_ui->stopConditionLabel->setEnabled(!m_ui->checkStartPaused->isChecked());
534 m_ui->stopConditionComboBox->setEnabled(!m_ui->checkStartPaused->isChecked());
536 m_ui->checkMergeTrackers->setChecked(session->isMergeTrackersEnabled());
537 m_ui->checkConfirmMergeTrackers->setEnabled(m_ui->checkAdditionDialog->isChecked());
538 m_ui->checkConfirmMergeTrackers->setChecked(m_ui->checkConfirmMergeTrackers->isEnabled() ? pref->confirmMergeTrackers() : false);
539 connect(m_ui->checkAdditionDialog, &QGroupBox::toggled, this, [this, pref]
541 m_ui->checkConfirmMergeTrackers->setEnabled(m_ui->checkAdditionDialog->isChecked());
542 m_ui->checkConfirmMergeTrackers->setChecked(m_ui->checkConfirmMergeTrackers->isEnabled() ? pref->confirmMergeTrackers() : false);
545 const TorrentFileGuard::AutoDeleteMode autoDeleteMode = TorrentFileGuard::autoDeleteMode();
546 m_ui->deleteTorrentBox->setChecked(autoDeleteMode != TorrentFileGuard::Never);
547 m_ui->deleteCancelledTorrentBox->setChecked(autoDeleteMode == TorrentFileGuard::Always);
548 m_ui->deleteTorrentWarningIcon->setPixmap(QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical).pixmap(16, 16));
549 m_ui->deleteTorrentWarningIcon->hide();
550 m_ui->deleteTorrentWarningLabel->hide();
551 m_ui->deleteTorrentWarningLabel->setToolTip(u"<html><body><p>" +
552 tr("By enabling these options, you can <strong>irrevocably lose</strong> your .torrent files!") +
553 u"</p><p>" +
554 tr("When these options are enabled, qBittorrent will <strong>delete</strong> .torrent files "
555 "after they were successfully (the first option) or not (the second option) added to its "
556 "download queue. This will be applied <strong>not only</strong> to the files opened via "
557 "&ldquo;Add torrent&rdquo; menu action but to those opened via <strong>file type association</strong> as well") +
558 u"</p><p>" +
559 tr("If you enable the second option (&ldquo;Also when addition is cancelled&rdquo;) the "
560 ".torrent file <strong>will be deleted</strong> even if you press &ldquo;<strong>Cancel</strong>&rdquo; in "
561 "the &ldquo;Add torrent&rdquo; dialog") +
562 u"</p></body></html>");
564 m_ui->checkPreallocateAll->setChecked(session->isPreallocationEnabled());
565 m_ui->checkAppendqB->setChecked(session->isAppendExtensionEnabled());
566 m_ui->checkUnwantedFolder->setChecked(session->isUnwantedFolderEnabled());
567 m_ui->checkRecursiveDownload->setChecked(pref->isRecursiveDownloadEnabled());
569 m_ui->comboSavingMode->setCurrentIndex(!session->isAutoTMMDisabledByDefault());
570 m_ui->comboTorrentCategoryChanged->setCurrentIndex(session->isDisableAutoTMMWhenCategoryChanged());
571 m_ui->comboCategoryChanged->setCurrentIndex(session->isDisableAutoTMMWhenCategorySavePathChanged());
572 m_ui->comboCategoryDefaultPathChanged->setCurrentIndex(session->isDisableAutoTMMWhenDefaultSavePathChanged());
574 m_ui->checkUseSubcategories->setChecked(session->isSubcategoriesEnabled());
575 m_ui->checkUseCategoryPaths->setChecked(session->useCategoryPathsInManualMode());
577 m_ui->textSavePath->setDialogCaption(tr("Choose a save directory"));
578 m_ui->textSavePath->setMode(FileSystemPathEdit::Mode::DirectorySave);
579 m_ui->textSavePath->setSelectedPath(session->savePath());
581 m_ui->checkUseDownloadPath->setChecked(session->isDownloadPathEnabled());
582 m_ui->textDownloadPath->setDialogCaption(tr("Choose a save directory"));
583 m_ui->textDownloadPath->setEnabled(m_ui->checkUseDownloadPath->isChecked());
584 m_ui->textDownloadPath->setMode(FileSystemPathEdit::Mode::DirectorySave);
585 m_ui->textDownloadPath->setSelectedPath(session->downloadPath());
587 const bool isExportDirEmpty = session->torrentExportDirectory().isEmpty();
588 m_ui->checkExportDir->setChecked(!isExportDirEmpty);
589 m_ui->textExportDir->setDialogCaption(tr("Choose export directory"));
590 m_ui->textExportDir->setEnabled(m_ui->checkExportDir->isChecked());
591 m_ui->textExportDir->setMode(FileSystemPathEdit::Mode::DirectorySave);
592 if (!isExportDirEmpty)
593 m_ui->textExportDir->setSelectedPath(session->torrentExportDirectory());
595 const bool isExportDirFinEmpty = session->finishedTorrentExportDirectory().isEmpty();
596 m_ui->checkExportDirFin->setChecked(!isExportDirFinEmpty);
597 m_ui->textExportDirFin->setDialogCaption(tr("Choose export directory"));
598 m_ui->textExportDirFin->setEnabled(m_ui->checkExportDirFin->isChecked());
599 m_ui->textExportDirFin->setMode(FileSystemPathEdit::Mode::DirectorySave);
600 if (!isExportDirFinEmpty)
601 m_ui->textExportDirFin->setSelectedPath(session->finishedTorrentExportDirectory());
603 auto *watchedFoldersModel = new WatchedFoldersModel(TorrentFilesWatcher::instance(), this);
604 connect(watchedFoldersModel, &QAbstractListModel::dataChanged, this, &ThisType::enableApplyButton);
605 m_ui->scanFoldersView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
606 m_ui->scanFoldersView->setModel(watchedFoldersModel);
607 connect(m_ui->scanFoldersView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &ThisType::handleWatchedFolderViewSelectionChanged);
608 connect(m_ui->scanFoldersView, &QTreeView::doubleClicked, this, &ThisType::editWatchedFolderOptions);
610 m_ui->groupExcludedFileNames->setChecked(session->isExcludedFileNamesEnabled());
611 m_ui->textExcludedFileNames->setPlainText(session->excludedFileNames().join(u'\n'));
613 m_ui->groupMailNotification->setChecked(pref->isMailNotificationEnabled());
614 m_ui->senderEmailTxt->setText(pref->getMailNotificationSender());
615 m_ui->lineEditDestEmail->setText(pref->getMailNotificationEmail());
616 m_ui->lineEditSmtpServer->setText(pref->getMailNotificationSMTP());
617 m_ui->checkSmtpSSL->setChecked(pref->getMailNotificationSMTPSSL());
618 m_ui->groupMailNotifAuth->setChecked(pref->getMailNotificationSMTPAuth());
619 m_ui->mailNotifUsername->setText(pref->getMailNotificationSMTPUsername());
620 m_ui->mailNotifPassword->setText(pref->getMailNotificationSMTPPassword());
622 m_ui->groupBoxRunOnAdded->setChecked(pref->isAutoRunOnTorrentAddedEnabled());
623 m_ui->groupBoxRunOnFinished->setChecked(pref->isAutoRunOnTorrentFinishedEnabled());
624 m_ui->lineEditRunOnAdded->setText(pref->getAutoRunOnTorrentAddedProgram());
625 m_ui->lineEditRunOnFinished->setText(pref->getAutoRunOnTorrentFinishedProgram());
626 #if defined(Q_OS_WIN)
627 m_ui->autoRunConsole->setChecked(pref->isAutoRunConsoleEnabled());
628 #else
629 m_ui->autoRunConsole->hide();
630 #endif
631 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"_s
632 .arg(tr("Supported parameters (case sensitive):")
633 , tr("%N: Torrent name")
634 , tr("%L: Category")
635 , tr("%G: Tags (separated by comma)")
636 , tr("%F: Content path (same as root path for multifile torrent)")
637 , tr("%R: Root path (first torrent subdirectory path)")
638 , tr("%D: Save path")
639 , tr("%C: Number of files")
640 , tr("%Z: Torrent size (bytes)"))
641 .arg(tr("%T: Current tracker")
642 , tr("%I: Info hash v1 (or '-' if unavailable)")
643 , tr("%J: Info hash v2 (or '-' if unavailable)")
644 , tr("%K: Torrent ID (either sha-1 info hash for v1 torrent or truncated sha-256 info hash for v2/hybrid torrent)")
645 , tr("Tip: Encapsulate parameter with quotation marks to avoid text being cut off at whitespace (e.g., \"%N\")"));
646 m_ui->labelAutoRunParam->setText(autoRunStr);
648 connect(m_ui->checkAdditionDialog, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
649 connect(m_ui->checkAdditionDialogFront, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
651 connect(m_ui->contentLayoutComboBox, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
653 connect(m_ui->checkAddToQueueTop, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
654 connect(m_ui->checkStartPaused, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
655 connect(m_ui->checkStartPaused, &QAbstractButton::toggled, this, [this](const bool checked)
657 m_ui->stopConditionLabel->setEnabled(!checked);
658 m_ui->stopConditionComboBox->setEnabled(!checked);
660 connect(m_ui->stopConditionComboBox, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
661 connect(m_ui->checkMergeTrackers, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
662 connect(m_ui->checkConfirmMergeTrackers, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
663 connect(m_ui->deleteTorrentBox, &QGroupBox::toggled, m_ui->deleteTorrentWarningIcon, &QWidget::setVisible);
664 connect(m_ui->deleteTorrentBox, &QGroupBox::toggled, m_ui->deleteTorrentWarningLabel, &QWidget::setVisible);
665 connect(m_ui->deleteTorrentBox, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
666 connect(m_ui->deleteCancelledTorrentBox, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
668 connect(m_ui->checkPreallocateAll, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
669 connect(m_ui->checkAppendqB, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
670 connect(m_ui->checkUnwantedFolder, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
671 connect(m_ui->checkRecursiveDownload, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
673 connect(m_ui->comboSavingMode, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
674 connect(m_ui->comboTorrentCategoryChanged, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
675 connect(m_ui->comboCategoryChanged, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
676 connect(m_ui->comboCategoryDefaultPathChanged, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
678 connect(m_ui->checkUseSubcategories, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
679 connect(m_ui->checkUseCategoryPaths, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
681 connect(m_ui->textSavePath, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
682 connect(m_ui->textDownloadPath, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
684 connect(m_ui->checkExportDir, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
685 connect(m_ui->checkExportDir, &QAbstractButton::toggled, m_ui->textExportDir, &QWidget::setEnabled);
686 connect(m_ui->checkExportDirFin, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
687 connect(m_ui->checkExportDirFin, &QAbstractButton::toggled, m_ui->textExportDirFin, &QWidget::setEnabled);
688 connect(m_ui->textExportDir, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
689 connect(m_ui->textExportDirFin, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
690 connect(m_ui->checkUseDownloadPath, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
691 connect(m_ui->checkUseDownloadPath, &QAbstractButton::toggled, m_ui->textDownloadPath, &QWidget::setEnabled);
693 connect(m_ui->addWatchedFolderButton, &QAbstractButton::clicked, this, &ThisType::enableApplyButton);
695 connect(m_ui->groupExcludedFileNames, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
696 connect(m_ui->textExcludedFileNames, &QPlainTextEdit::textChanged, this, &ThisType::enableApplyButton);
697 connect(m_ui->removeWatchedFolderButton, &QAbstractButton::clicked, this, &ThisType::enableApplyButton);
699 connect(m_ui->groupMailNotification, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
700 connect(m_ui->senderEmailTxt, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
701 connect(m_ui->lineEditDestEmail, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
702 connect(m_ui->lineEditSmtpServer, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
703 connect(m_ui->checkSmtpSSL, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
704 connect(m_ui->groupMailNotifAuth, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
705 connect(m_ui->mailNotifUsername, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
706 connect(m_ui->mailNotifPassword, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
708 connect(m_ui->groupBoxRunOnAdded, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
709 connect(m_ui->lineEditRunOnAdded, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
710 connect(m_ui->groupBoxRunOnFinished, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
711 connect(m_ui->lineEditRunOnFinished, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
712 connect(m_ui->autoRunConsole, &QCheckBox::toggled, this, &ThisType::enableApplyButton);
715 void OptionsDialog::saveDownloadsTabOptions() const
717 auto *pref = Preferences::instance();
718 auto *session = BitTorrent::Session::instance();
720 pref->setAddNewTorrentDialogEnabled(useAdditionDialog());
721 pref->setAddNewTorrentDialogTopLevel(m_ui->checkAdditionDialogFront->isChecked());
723 session->setTorrentContentLayout(static_cast<BitTorrent::TorrentContentLayout>(m_ui->contentLayoutComboBox->currentIndex()));
725 session->setAddTorrentToQueueTop(m_ui->checkAddToQueueTop->isChecked());
726 session->setAddTorrentPaused(addTorrentsInPause());
727 session->setTorrentStopCondition(m_ui->stopConditionComboBox->currentData().value<BitTorrent::Torrent::StopCondition>());
728 TorrentFileGuard::setAutoDeleteMode(!m_ui->deleteTorrentBox->isChecked() ? TorrentFileGuard::Never
729 : !m_ui->deleteCancelledTorrentBox->isChecked() ? TorrentFileGuard::IfAdded
730 : TorrentFileGuard::Always);
731 session->setMergeTrackersEnabled(m_ui->checkMergeTrackers->isChecked());
732 if (m_ui->checkConfirmMergeTrackers->isEnabled())
733 pref->setConfirmMergeTrackers(m_ui->checkConfirmMergeTrackers->isChecked());
735 session->setPreallocationEnabled(preAllocateAllFiles());
736 session->setAppendExtensionEnabled(m_ui->checkAppendqB->isChecked());
737 session->setUnwantedFolderEnabled(m_ui->checkUnwantedFolder->isChecked());
738 pref->setRecursiveDownloadEnabled(m_ui->checkRecursiveDownload->isChecked());
740 session->setAutoTMMDisabledByDefault(m_ui->comboSavingMode->currentIndex() == 0);
741 session->setDisableAutoTMMWhenCategoryChanged(m_ui->comboTorrentCategoryChanged->currentIndex() == 1);
742 session->setDisableAutoTMMWhenCategorySavePathChanged(m_ui->comboCategoryChanged->currentIndex() == 1);
743 session->setDisableAutoTMMWhenDefaultSavePathChanged(m_ui->comboCategoryDefaultPathChanged->currentIndex() == 1);
745 session->setSubcategoriesEnabled(m_ui->checkUseSubcategories->isChecked());
746 session->setUseCategoryPathsInManualMode(m_ui->checkUseCategoryPaths->isChecked());
748 session->setSavePath(Path(m_ui->textSavePath->selectedPath()));
749 session->setDownloadPathEnabled(m_ui->checkUseDownloadPath->isChecked());
750 session->setDownloadPath(m_ui->textDownloadPath->selectedPath());
751 session->setTorrentExportDirectory(getTorrentExportDir());
752 session->setFinishedTorrentExportDirectory(getFinishedTorrentExportDir());
754 auto *watchedFoldersModel = static_cast<WatchedFoldersModel *>(m_ui->scanFoldersView->model());
755 watchedFoldersModel->apply();
757 session->setExcludedFileNamesEnabled(m_ui->groupExcludedFileNames->isChecked());
758 session->setExcludedFileNames(m_ui->textExcludedFileNames->toPlainText().split(u'\n', Qt::SkipEmptyParts));
760 pref->setMailNotificationEnabled(m_ui->groupMailNotification->isChecked());
761 pref->setMailNotificationSender(m_ui->senderEmailTxt->text());
762 pref->setMailNotificationEmail(m_ui->lineEditDestEmail->text());
763 pref->setMailNotificationSMTP(m_ui->lineEditSmtpServer->text());
764 pref->setMailNotificationSMTPSSL(m_ui->checkSmtpSSL->isChecked());
765 pref->setMailNotificationSMTPAuth(m_ui->groupMailNotifAuth->isChecked());
766 pref->setMailNotificationSMTPUsername(m_ui->mailNotifUsername->text());
767 pref->setMailNotificationSMTPPassword(m_ui->mailNotifPassword->text());
769 pref->setAutoRunOnTorrentAddedEnabled(m_ui->groupBoxRunOnAdded->isChecked());
770 pref->setAutoRunOnTorrentAddedProgram(m_ui->lineEditRunOnAdded->text().trimmed());
771 pref->setAutoRunOnTorrentFinishedEnabled(m_ui->groupBoxRunOnFinished->isChecked());
772 pref->setAutoRunOnTorrentFinishedProgram(m_ui->lineEditRunOnFinished->text().trimmed());
773 #if defined(Q_OS_WIN)
774 pref->setAutoRunConsoleEnabled(m_ui->autoRunConsole->isChecked());
775 #endif
778 void OptionsDialog::loadConnectionTabOptions()
780 const auto *session = BitTorrent::Session::instance();
782 m_ui->comboProtocol->setCurrentIndex(static_cast<int>(session->btProtocol()));
783 m_ui->spinPort->setValue(session->port());
784 m_ui->checkUPnP->setChecked(Net::PortForwarder::instance()->isEnabled());
786 int intValue = session->maxConnections();
787 if (intValue > 0)
789 // enable
790 m_ui->checkMaxConnections->setChecked(true);
791 m_ui->spinMaxConnec->setEnabled(true);
792 m_ui->spinMaxConnec->setValue(intValue);
794 else
796 // disable
797 m_ui->checkMaxConnections->setChecked(false);
798 m_ui->spinMaxConnec->setEnabled(false);
800 intValue = session->maxConnectionsPerTorrent();
801 if (intValue > 0)
803 // enable
804 m_ui->checkMaxConnectionsPerTorrent->setChecked(true);
805 m_ui->spinMaxConnecPerTorrent->setEnabled(true);
806 m_ui->spinMaxConnecPerTorrent->setValue(intValue);
808 else
810 // disable
811 m_ui->checkMaxConnectionsPerTorrent->setChecked(false);
812 m_ui->spinMaxConnecPerTorrent->setEnabled(false);
814 intValue = session->maxUploads();
815 if (intValue > 0)
817 // enable
818 m_ui->checkMaxUploads->setChecked(true);
819 m_ui->spinMaxUploads->setEnabled(true);
820 m_ui->spinMaxUploads->setValue(intValue);
822 else
824 // disable
825 m_ui->checkMaxUploads->setChecked(false);
826 m_ui->spinMaxUploads->setEnabled(false);
828 intValue = session->maxUploadsPerTorrent();
829 if (intValue > 0)
831 // enable
832 m_ui->checkMaxUploadsPerTorrent->setChecked(true);
833 m_ui->spinMaxUploadsPerTorrent->setEnabled(true);
834 m_ui->spinMaxUploadsPerTorrent->setValue(intValue);
836 else
838 // disable
839 m_ui->checkMaxUploadsPerTorrent->setChecked(false);
840 m_ui->spinMaxUploadsPerTorrent->setEnabled(false);
843 #if defined(QBT_USES_LIBTORRENT2) && TORRENT_USE_I2P
844 m_ui->textI2PHost->setText(session->I2PAddress());
845 m_ui->spinI2PPort->setValue(session->I2PPort());
846 m_ui->checkI2PMixed->setChecked(session->I2PMixedMode());
847 m_ui->groupI2P->setChecked(session->isI2PEnabled());
848 #else
849 m_ui->groupI2P->hide();
850 #endif
852 const auto *proxyConfigManager = Net::ProxyConfigurationManager::instance();
853 const Net::ProxyConfiguration proxyConf = proxyConfigManager->proxyConfiguration();
855 m_ui->comboProxyType->addItem(tr("(None)"), QVariant::fromValue(Net::ProxyType::None));
856 m_ui->comboProxyType->addItem(tr("SOCKS4"), QVariant::fromValue(Net::ProxyType::SOCKS4));
857 m_ui->comboProxyType->addItem(tr("SOCKS5"), QVariant::fromValue(Net::ProxyType::SOCKS5));
858 m_ui->comboProxyType->addItem(tr("HTTP"), QVariant::fromValue(Net::ProxyType::HTTP));
859 m_ui->comboProxyType->setCurrentIndex(m_ui->comboProxyType->findData(QVariant::fromValue(proxyConf.type)));
860 adjustProxyOptions();
862 m_ui->textProxyIP->setText(proxyConf.ip);
863 m_ui->spinProxyPort->setValue(proxyConf.port);
864 m_ui->textProxyUsername->setText(proxyConf.username);
865 m_ui->textProxyPassword->setText(proxyConf.password);
866 m_ui->checkProxyAuth->setChecked(proxyConf.authEnabled);
867 m_ui->checkProxyHostnameLookup->setChecked(proxyConf.hostnameLookupEnabled);
869 m_ui->checkProxyPeerConnections->setChecked(session->isProxyPeerConnectionsEnabled());
870 m_ui->checkProxyBitTorrent->setChecked(Preferences::instance()->useProxyForBT());
871 m_ui->checkProxyRSS->setChecked(Preferences::instance()->useProxyForRSS());
872 m_ui->checkProxyMisc->setChecked(Preferences::instance()->useProxyForGeneralPurposes());
874 m_ui->checkIPFilter->setChecked(session->isIPFilteringEnabled());
875 m_ui->textFilterPath->setDialogCaption(tr("Choose an IP filter file"));
876 m_ui->textFilterPath->setEnabled(m_ui->checkIPFilter->isChecked());
877 m_ui->textFilterPath->setFileNameFilter(tr("All supported filters") + u" (*.dat *.p2p *.p2b);;.dat (*.dat);;.p2p (*.p2p);;.p2b (*.p2b)");
878 m_ui->textFilterPath->setSelectedPath(session->IPFilterFile());
880 m_ui->IpFilterRefreshBtn->setIcon(UIThemeManager::instance()->getIcon(u"view-refresh"_s));
881 m_ui->IpFilterRefreshBtn->setEnabled(m_ui->checkIPFilter->isChecked());
882 m_ui->checkIpFilterTrackers->setChecked(session->isTrackerFilteringEnabled());
884 connect(m_ui->comboProtocol, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
885 connect(m_ui->spinPort, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
886 connect(m_ui->checkUPnP, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
888 connect(m_ui->checkMaxConnections, &QAbstractButton::toggled, m_ui->spinMaxConnec, &QWidget::setEnabled);
889 connect(m_ui->checkMaxConnections, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
890 connect(m_ui->checkMaxConnectionsPerTorrent, &QAbstractButton::toggled, m_ui->spinMaxConnecPerTorrent, &QWidget::setEnabled);
891 connect(m_ui->checkMaxConnectionsPerTorrent, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
892 connect(m_ui->checkMaxUploads, &QAbstractButton::toggled, m_ui->spinMaxUploads, &QWidget::setEnabled);
893 connect(m_ui->checkMaxUploads, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
894 connect(m_ui->checkMaxUploadsPerTorrent, &QAbstractButton::toggled, m_ui->spinMaxUploadsPerTorrent, &QWidget::setEnabled);
895 connect(m_ui->checkMaxUploadsPerTorrent, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
896 connect(m_ui->spinMaxConnec, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
897 connect(m_ui->spinMaxConnecPerTorrent, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
898 connect(m_ui->spinMaxUploads, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
899 connect(m_ui->spinMaxUploadsPerTorrent, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
901 connect(m_ui->comboProxyType, qComboBoxCurrentIndexChanged, this, &ThisType::adjustProxyOptions);
902 connect(m_ui->comboProxyType, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
903 connect(m_ui->textProxyIP, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
904 connect(m_ui->spinProxyPort, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
906 #if defined(QBT_USES_LIBTORRENT2) && TORRENT_USE_I2P
907 connect(m_ui->textI2PHost, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
908 connect(m_ui->spinI2PPort, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
909 connect(m_ui->checkI2PMixed, &QCheckBox::toggled, this, &ThisType::enableApplyButton);
910 connect(m_ui->groupI2P, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
911 #endif
913 connect(m_ui->checkProxyBitTorrent, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
914 connect(m_ui->checkProxyBitTorrent, &QGroupBox::toggled, this, &ThisType::adjustProxyOptions);
915 connect(m_ui->checkProxyPeerConnections, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
916 connect(m_ui->checkProxyHostnameLookup, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
917 connect(m_ui->checkProxyRSS, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
918 connect(m_ui->checkProxyMisc, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
920 connect(m_ui->checkProxyAuth, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
921 connect(m_ui->textProxyUsername, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
922 connect(m_ui->textProxyPassword, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
924 connect(m_ui->checkIPFilter, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
925 connect(m_ui->checkIPFilter, &QAbstractButton::toggled, m_ui->textFilterPath, &QWidget::setEnabled);
926 connect(m_ui->checkIPFilter, &QAbstractButton::toggled, m_ui->IpFilterRefreshBtn, &QWidget::setEnabled);
927 connect(m_ui->textFilterPath, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
928 connect(m_ui->checkIpFilterTrackers, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
931 void OptionsDialog::saveConnectionTabOptions() const
933 auto *session = BitTorrent::Session::instance();
935 session->setBTProtocol(static_cast<BitTorrent::BTProtocol>(m_ui->comboProtocol->currentIndex()));
936 session->setPort(getPort());
937 Net::PortForwarder::instance()->setEnabled(isUPnPEnabled());
939 session->setMaxConnections(getMaxConnections());
940 session->setMaxConnectionsPerTorrent(getMaxConnectionsPerTorrent());
941 session->setMaxUploads(getMaxUploads());
942 session->setMaxUploadsPerTorrent(getMaxUploadsPerTorrent());
944 #if defined(QBT_USES_LIBTORRENT2) && TORRENT_USE_I2P
945 session->setI2PEnabled(m_ui->groupI2P->isChecked());
946 session->setI2PAddress(m_ui->textI2PHost->text().trimmed());
947 session->setI2PPort(m_ui->spinI2PPort->value());
948 session->setI2PMixedMode(m_ui->checkI2PMixed->isChecked());
949 #endif
951 auto *proxyConfigManager = Net::ProxyConfigurationManager::instance();
952 Net::ProxyConfiguration proxyConf;
953 proxyConf.type = getProxyType();
954 proxyConf.ip = getProxyIp();
955 proxyConf.port = getProxyPort();
956 proxyConf.authEnabled = m_ui->checkProxyAuth->isChecked();
957 proxyConf.username = getProxyUsername();
958 proxyConf.password = getProxyPassword();
959 proxyConf.hostnameLookupEnabled = m_ui->checkProxyHostnameLookup->isChecked();
960 proxyConfigManager->setProxyConfiguration(proxyConf);
962 Preferences::instance()->setUseProxyForBT(m_ui->checkProxyBitTorrent->isChecked());
963 Preferences::instance()->setUseProxyForRSS(m_ui->checkProxyRSS->isChecked());
964 Preferences::instance()->setUseProxyForGeneralPurposes(m_ui->checkProxyMisc->isChecked());
966 session->setProxyPeerConnectionsEnabled(m_ui->checkProxyPeerConnections->isChecked());
968 // IPFilter
969 session->setIPFilteringEnabled(isIPFilteringEnabled());
970 session->setTrackerFilteringEnabled(m_ui->checkIpFilterTrackers->isChecked());
971 session->setIPFilterFile(m_ui->textFilterPath->selectedPath());
974 void OptionsDialog::loadSpeedTabOptions()
976 const auto *pref = Preferences::instance();
977 const auto *session = BitTorrent::Session::instance();
979 m_ui->labelGlobalRate->setPixmap(UIThemeManager::instance()->getScaledPixmap(u"slow_off"_s, Utils::Gui::mediumIconSize(this).height()));
980 m_ui->spinUploadLimit->setValue(session->globalUploadSpeedLimit() / 1024);
981 m_ui->spinDownloadLimit->setValue(session->globalDownloadSpeedLimit() / 1024);
983 m_ui->labelAltRate->setPixmap(UIThemeManager::instance()->getScaledPixmap(u"slow"_s, Utils::Gui::mediumIconSize(this).height()));
984 m_ui->spinUploadLimitAlt->setValue(session->altGlobalUploadSpeedLimit() / 1024);
985 m_ui->spinDownloadLimitAlt->setValue(session->altGlobalDownloadSpeedLimit() / 1024);
987 m_ui->comboBoxScheduleDays->addItems(translatedWeekdayNames());
989 m_ui->groupBoxSchedule->setChecked(session->isBandwidthSchedulerEnabled());
990 m_ui->timeEditScheduleFrom->setTime(pref->getSchedulerStartTime());
991 m_ui->timeEditScheduleTo->setTime(pref->getSchedulerEndTime());
992 m_ui->comboBoxScheduleDays->setCurrentIndex(static_cast<int>(pref->getSchedulerDays()));
994 m_ui->checkLimituTPConnections->setChecked(session->isUTPRateLimited());
995 m_ui->checkLimitTransportOverhead->setChecked(session->includeOverheadInLimits());
996 m_ui->checkLimitLocalPeerRate->setChecked(!session->ignoreLimitsOnLAN());
998 connect(m_ui->spinUploadLimit, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
999 connect(m_ui->spinDownloadLimit, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1001 connect(m_ui->spinUploadLimitAlt, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1002 connect(m_ui->spinDownloadLimitAlt, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1004 connect(m_ui->groupBoxSchedule, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
1005 connect(m_ui->timeEditScheduleFrom, &QDateTimeEdit::timeChanged, this, &ThisType::enableApplyButton);
1006 connect(m_ui->timeEditScheduleTo, &QDateTimeEdit::timeChanged, this, &ThisType::enableApplyButton);
1007 connect(m_ui->comboBoxScheduleDays, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
1009 connect(m_ui->checkLimituTPConnections, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
1010 connect(m_ui->checkLimitTransportOverhead, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
1011 connect(m_ui->checkLimitLocalPeerRate, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
1014 void OptionsDialog::saveSpeedTabOptions() const
1016 auto *pref = Preferences::instance();
1017 auto *session = BitTorrent::Session::instance();
1019 session->setGlobalUploadSpeedLimit(m_ui->spinUploadLimit->value() * 1024);
1020 session->setGlobalDownloadSpeedLimit(m_ui->spinDownloadLimit->value() * 1024);
1022 session->setAltGlobalUploadSpeedLimit(m_ui->spinUploadLimitAlt->value() * 1024);
1023 session->setAltGlobalDownloadSpeedLimit(m_ui->spinDownloadLimitAlt->value() * 1024);
1025 session->setBandwidthSchedulerEnabled(m_ui->groupBoxSchedule->isChecked());
1026 pref->setSchedulerStartTime(m_ui->timeEditScheduleFrom->time());
1027 pref->setSchedulerEndTime(m_ui->timeEditScheduleTo->time());
1028 pref->setSchedulerDays(static_cast<Scheduler::Days>(m_ui->comboBoxScheduleDays->currentIndex()));
1030 session->setUTPRateLimited(m_ui->checkLimituTPConnections->isChecked());
1031 session->setIncludeOverheadInLimits(m_ui->checkLimitTransportOverhead->isChecked());
1032 session->setIgnoreLimitsOnLAN(!m_ui->checkLimitLocalPeerRate->isChecked());
1035 void OptionsDialog::loadBittorrentTabOptions()
1037 const auto *session = BitTorrent::Session::instance();
1039 m_ui->checkDHT->setChecked(session->isDHTEnabled());
1040 m_ui->checkPeX->setChecked(session->isPeXEnabled());
1041 m_ui->checkLSD->setChecked(session->isLSDEnabled());
1042 m_ui->comboEncryption->setCurrentIndex(session->encryption());
1043 m_ui->checkAnonymousMode->setChecked(session->isAnonymousModeEnabled());
1045 m_ui->spinBoxMaxActiveCheckingTorrents->setValue(session->maxActiveCheckingTorrents());
1047 m_ui->checkEnableQueueing->setChecked(session->isQueueingSystemEnabled());
1048 m_ui->spinMaxActiveDownloads->setValue(session->maxActiveDownloads());
1049 m_ui->spinMaxActiveUploads->setValue(session->maxActiveUploads());
1050 m_ui->spinMaxActiveTorrents->setValue(session->maxActiveTorrents());
1052 m_ui->checkIgnoreSlowTorrentsForQueueing->setChecked(session->ignoreSlowTorrentsForQueueing());
1053 const QString slowTorrentsExplanation = u"<html><body><p>"
1054 + tr("A torrent will be considered slow if its download and upload rates stay below these values for \"Torrent inactivity timer\" seconds")
1055 + u"</p></body></html>";
1056 m_ui->labelDownloadRateForSlowTorrents->setToolTip(slowTorrentsExplanation);
1057 m_ui->labelUploadRateForSlowTorrents->setToolTip(slowTorrentsExplanation);
1058 m_ui->labelSlowTorrentInactivityTimer->setToolTip(slowTorrentsExplanation);
1059 m_ui->spinDownloadRateForSlowTorrents->setValue(session->downloadRateForSlowTorrents());
1060 m_ui->spinUploadRateForSlowTorrents->setValue(session->uploadRateForSlowTorrents());
1061 m_ui->spinSlowTorrentsInactivityTimer->setValue(session->slowTorrentsInactivityTimer());
1063 if (session->globalMaxRatio() >= 0.)
1065 // Enable
1066 m_ui->checkMaxRatio->setChecked(true);
1067 m_ui->spinMaxRatio->setEnabled(true);
1068 m_ui->comboRatioLimitAct->setEnabled(true);
1069 m_ui->spinMaxRatio->setValue(session->globalMaxRatio());
1071 else
1073 // Disable
1074 m_ui->checkMaxRatio->setChecked(false);
1075 m_ui->spinMaxRatio->setEnabled(false);
1077 if (session->globalMaxSeedingMinutes() >= 0)
1079 // Enable
1080 m_ui->checkMaxSeedingMinutes->setChecked(true);
1081 m_ui->spinMaxSeedingMinutes->setEnabled(true);
1082 m_ui->spinMaxSeedingMinutes->setValue(session->globalMaxSeedingMinutes());
1084 else
1086 // Disable
1087 m_ui->checkMaxSeedingMinutes->setChecked(false);
1088 m_ui->spinMaxSeedingMinutes->setEnabled(false);
1090 if (session->globalMaxInactiveSeedingMinutes() >= 0)
1092 // Enable
1093 m_ui->checkMaxInactiveSeedingMinutes->setChecked(true);
1094 m_ui->spinMaxInactiveSeedingMinutes->setEnabled(true);
1095 m_ui->spinMaxInactiveSeedingMinutes->setValue(session->globalMaxInactiveSeedingMinutes());
1097 else
1099 // Disable
1100 m_ui->checkMaxInactiveSeedingMinutes->setChecked(false);
1101 m_ui->spinMaxInactiveSeedingMinutes->setEnabled(false);
1103 m_ui->comboRatioLimitAct->setEnabled((session->globalMaxSeedingMinutes() >= 0) || (session->globalMaxRatio() >= 0.) || (session->globalMaxInactiveSeedingMinutes() >= 0));
1105 const QHash<MaxRatioAction, int> actIndex =
1107 {Pause, 0},
1108 {Remove, 1},
1109 {DeleteFiles, 2},
1110 {EnableSuperSeeding, 3}
1112 m_ui->comboRatioLimitAct->setCurrentIndex(actIndex.value(session->maxRatioAction()));
1114 m_ui->checkEnableAddTrackers->setChecked(session->isAddTrackersEnabled());
1115 m_ui->textTrackers->setPlainText(session->additionalTrackers());
1117 connect(m_ui->checkDHT, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
1118 connect(m_ui->checkPeX, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
1119 connect(m_ui->checkLSD, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
1120 connect(m_ui->comboEncryption, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
1121 connect(m_ui->checkAnonymousMode, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
1123 connect(m_ui->spinBoxMaxActiveCheckingTorrents, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1125 connect(m_ui->checkEnableQueueing, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
1126 connect(m_ui->spinMaxActiveDownloads, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1127 connect(m_ui->spinMaxActiveUploads, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1128 connect(m_ui->spinMaxActiveTorrents, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1129 connect(m_ui->checkIgnoreSlowTorrentsForQueueing, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
1130 connect(m_ui->spinDownloadRateForSlowTorrents, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1131 connect(m_ui->spinUploadRateForSlowTorrents, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1132 connect(m_ui->spinSlowTorrentsInactivityTimer, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1134 connect(m_ui->checkMaxRatio, &QAbstractButton::toggled, m_ui->spinMaxRatio, &QWidget::setEnabled);
1135 connect(m_ui->checkMaxRatio, &QAbstractButton::toggled, this, &ThisType::toggleComboRatioLimitAct);
1136 connect(m_ui->checkMaxRatio, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
1137 connect(m_ui->spinMaxRatio, qOverload<double>(&QDoubleSpinBox::valueChanged),this, &ThisType::enableApplyButton);
1138 connect(m_ui->comboRatioLimitAct, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
1139 connect(m_ui->checkMaxSeedingMinutes, &QAbstractButton::toggled, m_ui->spinMaxSeedingMinutes, &QWidget::setEnabled);
1140 connect(m_ui->checkMaxSeedingMinutes, &QAbstractButton::toggled, this, &ThisType::toggleComboRatioLimitAct);
1141 connect(m_ui->checkMaxSeedingMinutes, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
1142 connect(m_ui->spinMaxSeedingMinutes, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1143 connect(m_ui->checkMaxInactiveSeedingMinutes, &QAbstractButton::toggled, m_ui->spinMaxInactiveSeedingMinutes, &QWidget::setEnabled);
1144 connect(m_ui->checkMaxInactiveSeedingMinutes, &QAbstractButton::toggled, this, &ThisType::toggleComboRatioLimitAct);
1145 connect(m_ui->checkMaxInactiveSeedingMinutes, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
1146 connect(m_ui->spinMaxInactiveSeedingMinutes, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1148 connect(m_ui->checkEnableAddTrackers, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
1149 connect(m_ui->textTrackers, &QPlainTextEdit::textChanged, this, &ThisType::enableApplyButton);
1152 void OptionsDialog::saveBittorrentTabOptions() const
1154 auto *session = BitTorrent::Session::instance();
1156 session->setDHTEnabled(isDHTEnabled());
1157 session->setPeXEnabled(m_ui->checkPeX->isChecked());
1158 session->setLSDEnabled(isLSDEnabled());
1159 session->setEncryption(getEncryptionSetting());
1160 session->setAnonymousModeEnabled(m_ui->checkAnonymousMode->isChecked());
1162 session->setMaxActiveCheckingTorrents(m_ui->spinBoxMaxActiveCheckingTorrents->value());
1163 // Queueing system
1164 session->setQueueingSystemEnabled(isQueueingSystemEnabled());
1165 session->setMaxActiveDownloads(m_ui->spinMaxActiveDownloads->value());
1166 session->setMaxActiveUploads(m_ui->spinMaxActiveUploads->value());
1167 session->setMaxActiveTorrents(m_ui->spinMaxActiveTorrents->value());
1168 session->setIgnoreSlowTorrentsForQueueing(m_ui->checkIgnoreSlowTorrentsForQueueing->isChecked());
1169 session->setDownloadRateForSlowTorrents(m_ui->spinDownloadRateForSlowTorrents->value());
1170 session->setUploadRateForSlowTorrents(m_ui->spinUploadRateForSlowTorrents->value());
1171 session->setSlowTorrentsInactivityTimer(m_ui->spinSlowTorrentsInactivityTimer->value());
1173 session->setGlobalMaxRatio(getMaxRatio());
1174 session->setGlobalMaxSeedingMinutes(getMaxSeedingMinutes());
1175 session->setGlobalMaxInactiveSeedingMinutes(getMaxInactiveSeedingMinutes());
1176 const QVector<MaxRatioAction> actIndex =
1178 Pause,
1179 Remove,
1180 DeleteFiles,
1181 EnableSuperSeeding
1183 session->setMaxRatioAction(actIndex.value(m_ui->comboRatioLimitAct->currentIndex()));
1185 session->setAddTrackersEnabled(m_ui->checkEnableAddTrackers->isChecked());
1186 session->setAdditionalTrackers(m_ui->textTrackers->toPlainText());
1189 void OptionsDialog::loadRSSTabOptions()
1191 const auto *rssSession = RSS::Session::instance();
1192 const auto *autoDownloader = RSS::AutoDownloader::instance();
1194 m_ui->checkRSSEnable->setChecked(rssSession->isProcessingEnabled());
1195 m_ui->spinRSSRefreshInterval->setValue(rssSession->refreshInterval());
1196 m_ui->spinRSSMaxArticlesPerFeed->setValue(rssSession->maxArticlesPerFeed());
1197 m_ui->checkRSSAutoDownloaderEnable->setChecked(autoDownloader->isProcessingEnabled());
1198 m_ui->textSmartEpisodeFilters->setPlainText(autoDownloader->smartEpisodeFilters().join(u'\n'));
1199 m_ui->checkSmartFilterDownloadRepacks->setChecked(autoDownloader->downloadRepacks());
1201 connect(m_ui->checkRSSEnable, &QCheckBox::toggled, this, &OptionsDialog::enableApplyButton);
1202 connect(m_ui->checkRSSAutoDownloaderEnable, &QCheckBox::toggled, this, &OptionsDialog::enableApplyButton);
1203 connect(m_ui->btnEditRules, &QPushButton::clicked, this, [this]()
1205 auto *downloader = new AutomatedRssDownloader(this);
1206 downloader->setAttribute(Qt::WA_DeleteOnClose);
1207 downloader->open();
1209 connect(m_ui->textSmartEpisodeFilters, &QPlainTextEdit::textChanged, this, &OptionsDialog::enableApplyButton);
1210 connect(m_ui->checkSmartFilterDownloadRepacks, &QCheckBox::toggled, this, &OptionsDialog::enableApplyButton);
1211 connect(m_ui->spinRSSRefreshInterval, qSpinBoxValueChanged, this, &OptionsDialog::enableApplyButton);
1212 connect(m_ui->spinRSSMaxArticlesPerFeed, qSpinBoxValueChanged, this, &OptionsDialog::enableApplyButton);
1215 void OptionsDialog::saveRSSTabOptions() const
1217 auto *rssSession = RSS::Session::instance();
1218 auto *autoDownloader = RSS::AutoDownloader::instance();
1220 rssSession->setProcessingEnabled(m_ui->checkRSSEnable->isChecked());
1221 rssSession->setRefreshInterval(m_ui->spinRSSRefreshInterval->value());
1222 rssSession->setMaxArticlesPerFeed(m_ui->spinRSSMaxArticlesPerFeed->value());
1223 autoDownloader->setProcessingEnabled(m_ui->checkRSSAutoDownloaderEnable->isChecked());
1224 autoDownloader->setSmartEpisodeFilters(m_ui->textSmartEpisodeFilters->toPlainText().split(u'\n', Qt::SkipEmptyParts));
1225 autoDownloader->setDownloadRepacks(m_ui->checkSmartFilterDownloadRepacks->isChecked());
1228 #ifndef DISABLE_WEBUI
1229 void OptionsDialog::loadWebUITabOptions()
1231 const auto *pref = Preferences::instance();
1233 m_ui->textWebUIHttpsCert->setMode(FileSystemPathEdit::Mode::FileOpen);
1234 m_ui->textWebUIHttpsCert->setFileNameFilter(tr("Certificate") + u" (*.cer *.crt *.pem)");
1235 m_ui->textWebUIHttpsCert->setDialogCaption(tr("Select certificate"));
1236 m_ui->textWebUIHttpsKey->setMode(FileSystemPathEdit::Mode::FileOpen);
1237 m_ui->textWebUIHttpsKey->setFileNameFilter(tr("Private key") + u" (*.key *.pem)");
1238 m_ui->textWebUIHttpsKey->setDialogCaption(tr("Select private key"));
1239 m_ui->textWebUIRootFolder->setMode(FileSystemPathEdit::Mode::DirectoryOpen);
1240 m_ui->textWebUIRootFolder->setDialogCaption(tr("Choose Alternative UI files location"));
1242 if (app()->webUI()->isErrored())
1243 m_ui->labelWebUIError->setText(tr("WebUI configuration failed. Reason: %1").arg(app()->webUI()->errorMessage()));
1244 else
1245 m_ui->labelWebUIError->hide();
1247 m_ui->checkWebUI->setChecked(pref->isWebUIEnabled());
1248 m_ui->textWebUIAddress->setText(pref->getWebUIAddress());
1249 m_ui->spinWebUIPort->setValue(pref->getWebUIPort());
1250 m_ui->checkWebUIUPnP->setChecked(pref->useUPnPForWebUIPort());
1251 m_ui->checkWebUIHttps->setChecked(pref->isWebUIHttpsEnabled());
1252 webUIHttpsCertChanged(pref->getWebUIHttpsCertificatePath());
1253 webUIHttpsKeyChanged(pref->getWebUIHttpsKeyPath());
1254 m_ui->textWebUIUsername->setText(pref->getWebUIUsername());
1255 m_ui->checkBypassLocalAuth->setChecked(!pref->isWebUILocalAuthEnabled());
1256 m_ui->checkBypassAuthSubnetWhitelist->setChecked(pref->isWebUIAuthSubnetWhitelistEnabled());
1257 m_ui->IPSubnetWhitelistButton->setEnabled(m_ui->checkBypassAuthSubnetWhitelist->isChecked());
1258 m_ui->spinBanCounter->setValue(pref->getWebUIMaxAuthFailCount());
1259 m_ui->spinBanDuration->setValue(pref->getWebUIBanDuration().count());
1260 m_ui->spinSessionTimeout->setValue(pref->getWebUISessionTimeout());
1261 // Alternative UI
1262 m_ui->groupAltWebUI->setChecked(pref->isAltWebUIEnabled());
1263 m_ui->textWebUIRootFolder->setSelectedPath(pref->getWebUIRootFolder());
1264 // Security
1265 m_ui->checkClickjacking->setChecked(pref->isWebUIClickjackingProtectionEnabled());
1266 m_ui->checkCSRFProtection->setChecked(pref->isWebUICSRFProtectionEnabled());
1267 m_ui->checkSecureCookie->setEnabled(pref->isWebUIHttpsEnabled());
1268 m_ui->checkSecureCookie->setChecked(pref->isWebUISecureCookieEnabled());
1269 m_ui->groupHostHeaderValidation->setChecked(pref->isWebUIHostHeaderValidationEnabled());
1270 m_ui->textServerDomains->setText(pref->getServerDomains());
1271 // Custom HTTP headers
1272 m_ui->groupWebUIAddCustomHTTPHeaders->setChecked(pref->isWebUICustomHTTPHeadersEnabled());
1273 m_ui->textWebUICustomHTTPHeaders->setPlainText(pref->getWebUICustomHTTPHeaders());
1274 // Reverse proxy
1275 m_ui->groupEnableReverseProxySupport->setChecked(pref->isWebUIReverseProxySupportEnabled());
1276 m_ui->textTrustedReverseProxiesList->setText(pref->getWebUITrustedReverseProxiesList());
1277 // DynDNS
1278 m_ui->checkDynDNS->setChecked(pref->isDynDNSEnabled());
1279 m_ui->comboDNSService->setCurrentIndex(static_cast<int>(pref->getDynDNSService()));
1280 m_ui->domainNameTxt->setText(pref->getDynDomainName());
1281 m_ui->DNSUsernameTxt->setText(pref->getDynDNSUsername());
1282 m_ui->DNSPasswordTxt->setText(pref->getDynDNSPassword());
1284 connect(m_ui->checkWebUI, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
1285 connect(m_ui->textWebUIAddress, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
1286 connect(m_ui->spinWebUIPort, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1287 connect(m_ui->checkWebUIUPnP, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
1288 connect(m_ui->checkWebUIHttps, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
1289 connect(m_ui->textWebUIHttpsCert, &FileSystemPathLineEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
1290 connect(m_ui->textWebUIHttpsCert, &FileSystemPathLineEdit::selectedPathChanged, this, &OptionsDialog::webUIHttpsCertChanged);
1291 connect(m_ui->textWebUIHttpsKey, &FileSystemPathLineEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
1292 connect(m_ui->textWebUIHttpsKey, &FileSystemPathLineEdit::selectedPathChanged, this, &OptionsDialog::webUIHttpsKeyChanged);
1294 connect(m_ui->textWebUIUsername, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
1295 connect(m_ui->textWebUIPassword, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
1297 connect(m_ui->checkBypassLocalAuth, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
1298 connect(m_ui->checkBypassAuthSubnetWhitelist, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
1299 connect(m_ui->checkBypassAuthSubnetWhitelist, &QAbstractButton::toggled, m_ui->IPSubnetWhitelistButton, &QWidget::setEnabled);
1300 connect(m_ui->spinBanCounter, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1301 connect(m_ui->spinBanDuration, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1302 connect(m_ui->spinSessionTimeout, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1304 connect(m_ui->groupAltWebUI, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
1305 connect(m_ui->textWebUIRootFolder, &FileSystemPathLineEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
1307 connect(m_ui->checkClickjacking, &QCheckBox::toggled, this, &ThisType::enableApplyButton);
1308 connect(m_ui->checkCSRFProtection, &QCheckBox::toggled, this, &ThisType::enableApplyButton);
1309 connect(m_ui->checkWebUIHttps, &QGroupBox::toggled, m_ui->checkSecureCookie, &QWidget::setEnabled);
1310 connect(m_ui->checkSecureCookie, &QCheckBox::toggled, this, &ThisType::enableApplyButton);
1311 connect(m_ui->groupHostHeaderValidation, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
1312 connect(m_ui->textServerDomains, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
1314 connect(m_ui->groupWebUIAddCustomHTTPHeaders, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
1315 connect(m_ui->textWebUICustomHTTPHeaders, &QPlainTextEdit::textChanged, this, &OptionsDialog::enableApplyButton);
1317 connect(m_ui->groupEnableReverseProxySupport, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
1318 connect(m_ui->textTrustedReverseProxiesList, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
1320 connect(m_ui->checkDynDNS, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
1321 connect(m_ui->comboDNSService, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
1322 connect(m_ui->domainNameTxt, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
1323 connect(m_ui->DNSUsernameTxt, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
1324 connect(m_ui->DNSPasswordTxt, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
1327 void OptionsDialog::saveWebUITabOptions() const
1329 auto *pref = Preferences::instance();
1331 const bool webUIEnabled = isWebUIEnabled();
1333 pref->setWebUIEnabled(webUIEnabled);
1334 pref->setWebUIAddress(m_ui->textWebUIAddress->text());
1335 pref->setWebUIPort(m_ui->spinWebUIPort->value());
1336 pref->setUPnPForWebUIPort(m_ui->checkWebUIUPnP->isChecked());
1337 pref->setWebUIHttpsEnabled(m_ui->checkWebUIHttps->isChecked());
1338 pref->setWebUIHttpsCertificatePath(m_ui->textWebUIHttpsCert->selectedPath());
1339 pref->setWebUIHttpsKeyPath(m_ui->textWebUIHttpsKey->selectedPath());
1340 pref->setWebUIMaxAuthFailCount(m_ui->spinBanCounter->value());
1341 pref->setWebUIBanDuration(std::chrono::seconds {m_ui->spinBanDuration->value()});
1342 pref->setWebUISessionTimeout(m_ui->spinSessionTimeout->value());
1343 // Authentication
1344 if (const QString username = webUIUsername(); isValidWebUIUsername(username))
1345 pref->setWebUIUsername(username);
1346 if (const QString password = webUIPassword(); isValidWebUIPassword(password))
1347 pref->setWebUIPassword(Utils::Password::PBKDF2::generate(password));
1348 pref->setWebUILocalAuthEnabled(!m_ui->checkBypassLocalAuth->isChecked());
1349 pref->setWebUIAuthSubnetWhitelistEnabled(m_ui->checkBypassAuthSubnetWhitelist->isChecked());
1350 // Alternative UI
1351 pref->setAltWebUIEnabled(m_ui->groupAltWebUI->isChecked());
1352 pref->setWebUIRootFolder(m_ui->textWebUIRootFolder->selectedPath());
1353 // Security
1354 pref->setWebUIClickjackingProtectionEnabled(m_ui->checkClickjacking->isChecked());
1355 pref->setWebUICSRFProtectionEnabled(m_ui->checkCSRFProtection->isChecked());
1356 pref->setWebUISecureCookieEnabled(m_ui->checkSecureCookie->isChecked());
1357 pref->setWebUIHostHeaderValidationEnabled(m_ui->groupHostHeaderValidation->isChecked());
1358 pref->setServerDomains(m_ui->textServerDomains->text());
1359 // Custom HTTP headers
1360 pref->setWebUICustomHTTPHeadersEnabled(m_ui->groupWebUIAddCustomHTTPHeaders->isChecked());
1361 pref->setWebUICustomHTTPHeaders(m_ui->textWebUICustomHTTPHeaders->toPlainText());
1362 // Reverse proxy
1363 pref->setWebUIReverseProxySupportEnabled(m_ui->groupEnableReverseProxySupport->isChecked());
1364 pref->setWebUITrustedReverseProxiesList(m_ui->textTrustedReverseProxiesList->text());
1365 // DynDNS
1366 pref->setDynDNSEnabled(m_ui->checkDynDNS->isChecked());
1367 pref->setDynDNSService(static_cast<DNS::Service>(m_ui->comboDNSService->currentIndex()));
1368 pref->setDynDomainName(m_ui->domainNameTxt->text());
1369 pref->setDynDNSUsername(m_ui->DNSUsernameTxt->text());
1370 pref->setDynDNSPassword(m_ui->DNSPasswordTxt->text());
1372 #endif // DISABLE_WEBUI
1374 void OptionsDialog::initializeLanguageCombo()
1376 // List language files
1377 const QDir langDir(u":/lang"_s);
1378 const QStringList langFiles = langDir.entryList(QStringList(u"qbittorrent_*.qm"_s), QDir::Files);
1379 for (const QString &langFile : langFiles)
1381 const QString localeStr = langFile.section(u"_"_s, 1, -1).section(u"."_s, 0, 0); // remove "qbittorrent_" and ".qm"
1382 m_ui->comboI18n->addItem(/*QIcon(":/icons/flags/"+country+".svg"), */ Utils::Misc::languageToLocalizedString(localeStr), localeStr);
1383 qDebug() << "Supported locale:" << localeStr;
1387 void OptionsDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous)
1389 if (!current)
1390 current = previous;
1391 m_ui->tabOption->setCurrentIndex(m_ui->tabSelection->row(current));
1394 void OptionsDialog::loadSplitterState()
1396 // width has been modified, use height as width reference instead
1397 const int width = m_ui->tabSelection->item(TAB_UI)->sizeHint().height() * 2;
1398 const QStringList defaultSizes = {QString::number(width), QString::number(m_ui->hsplitter->width() - width)};
1400 QList<int> splitterSizes;
1401 for (const QString &string : asConst(m_storeHSplitterSize.get(defaultSizes)))
1402 splitterSizes.append(string.toInt());
1404 m_ui->hsplitter->setSizes(splitterSizes);
1407 void OptionsDialog::showEvent(QShowEvent *e)
1409 QDialog::showEvent(e);
1411 loadSplitterState();
1414 void OptionsDialog::saveOptions() const
1416 auto *pref = Preferences::instance();
1418 saveBehaviorTabOptions();
1419 saveDownloadsTabOptions();
1420 saveConnectionTabOptions();
1421 saveSpeedTabOptions();
1422 saveBittorrentTabOptions();
1423 saveRSSTabOptions();
1424 #ifndef DISABLE_WEBUI
1425 saveWebUITabOptions();
1426 #endif
1427 m_advancedSettings->saveAdvancedSettings();
1429 // Assume that user changed multiple settings
1430 // so it's best to save immediately
1431 pref->apply();
1434 bool OptionsDialog::isIPFilteringEnabled() const
1436 return m_ui->checkIPFilter->isChecked();
1439 Net::ProxyType OptionsDialog::getProxyType() const
1441 return m_ui->comboProxyType->currentData().value<Net::ProxyType>();
1444 int OptionsDialog::getPort() const
1446 return m_ui->spinPort->value();
1449 void OptionsDialog::on_randomButton_clicked()
1451 // Range [1024: 65535]
1452 m_ui->spinPort->setValue(Utils::Random::rand(1024, 65535));
1455 int OptionsDialog::getEncryptionSetting() const
1457 return m_ui->comboEncryption->currentIndex();
1460 int OptionsDialog::getMaxActiveDownloads() const
1462 return m_ui->spinMaxActiveDownloads->value();
1465 int OptionsDialog::getMaxActiveUploads() const
1467 return m_ui->spinMaxActiveUploads->value();
1470 int OptionsDialog::getMaxActiveTorrents() const
1472 return m_ui->spinMaxActiveTorrents->value();
1475 bool OptionsDialog::isQueueingSystemEnabled() const
1477 return m_ui->checkEnableQueueing->isChecked();
1480 bool OptionsDialog::isDHTEnabled() const
1482 return m_ui->checkDHT->isChecked();
1485 bool OptionsDialog::isLSDEnabled() const
1487 return m_ui->checkLSD->isChecked();
1490 bool OptionsDialog::isUPnPEnabled() const
1492 return m_ui->checkUPnP->isChecked();
1495 // Return Share ratio
1496 qreal OptionsDialog::getMaxRatio() const
1498 if (m_ui->checkMaxRatio->isChecked())
1499 return m_ui->spinMaxRatio->value();
1500 return -1;
1503 // Return Seeding Minutes
1504 int OptionsDialog::getMaxSeedingMinutes() const
1506 if (m_ui->checkMaxSeedingMinutes->isChecked())
1507 return m_ui->spinMaxSeedingMinutes->value();
1508 return -1;
1511 // Return Inactive Seeding Minutes
1512 int OptionsDialog::getMaxInactiveSeedingMinutes() const
1514 return m_ui->checkMaxInactiveSeedingMinutes->isChecked()
1515 ? m_ui->spinMaxInactiveSeedingMinutes->value()
1516 : -1;
1519 // Return max connections number
1520 int OptionsDialog::getMaxConnections() const
1522 if (!m_ui->checkMaxConnections->isChecked())
1523 return -1;
1525 return m_ui->spinMaxConnec->value();
1528 int OptionsDialog::getMaxConnectionsPerTorrent() const
1530 if (!m_ui->checkMaxConnectionsPerTorrent->isChecked())
1531 return -1;
1533 return m_ui->spinMaxConnecPerTorrent->value();
1536 int OptionsDialog::getMaxUploads() const
1538 if (!m_ui->checkMaxUploads->isChecked())
1539 return -1;
1541 return m_ui->spinMaxUploads->value();
1544 int OptionsDialog::getMaxUploadsPerTorrent() const
1546 if (!m_ui->checkMaxUploadsPerTorrent->isChecked())
1547 return -1;
1549 return m_ui->spinMaxUploadsPerTorrent->value();
1552 void OptionsDialog::on_buttonBox_accepted()
1554 if (m_applyButton->isEnabled())
1556 if (!applySettings())
1557 return;
1559 m_applyButton->setEnabled(false);
1562 accept();
1565 bool OptionsDialog::applySettings()
1567 if (!schedTimesOk())
1569 m_ui->tabSelection->setCurrentRow(TAB_SPEED);
1570 return false;
1572 #ifndef DISABLE_WEBUI
1573 if (isWebUIEnabled() && !webUIAuthenticationOk())
1575 m_ui->tabSelection->setCurrentRow(TAB_WEBUI);
1576 return false;
1578 if (!isAlternativeWebUIPathValid())
1580 m_ui->tabSelection->setCurrentRow(TAB_WEBUI);
1581 return false;
1583 #endif
1585 saveOptions();
1586 return true;
1589 void OptionsDialog::on_buttonBox_rejected()
1591 reject();
1594 bool OptionsDialog::useAdditionDialog() const
1596 return m_ui->checkAdditionDialog->isChecked();
1599 void OptionsDialog::enableApplyButton()
1601 m_applyButton->setEnabled(true);
1604 void OptionsDialog::toggleComboRatioLimitAct()
1606 // Verify if the share action button must be enabled
1607 m_ui->comboRatioLimitAct->setEnabled(m_ui->checkMaxRatio->isChecked() || m_ui->checkMaxSeedingMinutes->isChecked() || m_ui->checkMaxInactiveSeedingMinutes->isChecked());
1610 void OptionsDialog::adjustProxyOptions()
1612 const auto currentProxyType = m_ui->comboProxyType->currentData().value<Net::ProxyType>();
1613 const bool isAuthSupported = ((currentProxyType == Net::ProxyType::SOCKS5)
1614 || (currentProxyType == Net::ProxyType::HTTP));
1616 m_ui->checkProxyAuth->setEnabled(isAuthSupported);
1618 if (currentProxyType == Net::ProxyType::None)
1620 m_ui->labelProxyTypeIncompatible->setVisible(false);
1622 m_ui->lblProxyIP->setEnabled(false);
1623 m_ui->textProxyIP->setEnabled(false);
1624 m_ui->lblProxyPort->setEnabled(false);
1625 m_ui->spinProxyPort->setEnabled(false);
1627 m_ui->checkProxyHostnameLookup->setEnabled(false);
1628 m_ui->checkProxyRSS->setEnabled(false);
1629 m_ui->checkProxyMisc->setEnabled(false);
1630 m_ui->checkProxyBitTorrent->setEnabled(false);
1631 m_ui->checkProxyPeerConnections->setEnabled(false);
1633 else
1635 m_ui->lblProxyIP->setEnabled(true);
1636 m_ui->textProxyIP->setEnabled(true);
1637 m_ui->lblProxyPort->setEnabled(true);
1638 m_ui->spinProxyPort->setEnabled(true);
1640 m_ui->checkProxyBitTorrent->setEnabled(true);
1641 m_ui->checkProxyPeerConnections->setEnabled(true);
1643 if (currentProxyType == Net::ProxyType::SOCKS4)
1645 m_ui->labelProxyTypeIncompatible->setVisible(true);
1647 m_ui->checkProxyHostnameLookup->setEnabled(false);
1648 m_ui->checkProxyRSS->setEnabled(false);
1649 m_ui->checkProxyMisc->setEnabled(false);
1651 else
1653 // SOCKS5 or HTTP
1654 m_ui->labelProxyTypeIncompatible->setVisible(false);
1656 m_ui->checkProxyHostnameLookup->setEnabled(true);
1657 m_ui->checkProxyRSS->setEnabled(true);
1658 m_ui->checkProxyMisc->setEnabled(true);
1663 bool OptionsDialog::isSplashScreenDisabled() const
1665 return !m_ui->checkShowSplash->isChecked();
1668 #ifdef Q_OS_WIN
1669 bool OptionsDialog::WinStartup() const
1671 return m_ui->checkStartup->isChecked();
1673 #endif
1675 bool OptionsDialog::preAllocateAllFiles() const
1677 return m_ui->checkPreallocateAll->isChecked();
1680 bool OptionsDialog::addTorrentsInPause() const
1682 return m_ui->checkStartPaused->isChecked();
1685 // Proxy settings
1686 bool OptionsDialog::isProxyEnabled() const
1688 return m_ui->comboProxyType->currentIndex();
1691 QString OptionsDialog::getProxyIp() const
1693 return m_ui->textProxyIP->text().trimmed();
1696 unsigned short OptionsDialog::getProxyPort() const
1698 return m_ui->spinProxyPort->value();
1701 QString OptionsDialog::getProxyUsername() const
1703 QString username = m_ui->textProxyUsername->text().trimmed();
1704 return username;
1707 QString OptionsDialog::getProxyPassword() const
1709 QString password = m_ui->textProxyPassword->text();
1710 password = password.trimmed();
1711 return password;
1714 // Locale Settings
1715 QString OptionsDialog::getLocale() const
1717 return m_ui->comboI18n->itemData(m_ui->comboI18n->currentIndex(), Qt::UserRole).toString();
1720 void OptionsDialog::setLocale(const QString &localeStr)
1722 QString name;
1723 if (localeStr.startsWith(u"eo", Qt::CaseInsensitive))
1725 name = u"eo"_s;
1727 else if (localeStr.startsWith(u"ltg", Qt::CaseInsensitive))
1729 name = u"ltg"_s;
1731 else
1733 QLocale locale(localeStr);
1734 if (locale.language() == QLocale::Uzbek)
1735 name = u"uz@Latn"_s;
1736 else if (locale.language() == QLocale::Azerbaijani)
1737 name = u"az@latin"_s;
1738 else
1739 name = locale.name();
1741 // Attempt to find exact match
1742 int index = m_ui->comboI18n->findData(name, Qt::UserRole);
1743 if (index < 0)
1745 //Attempt to find a language match without a country
1746 int pos = name.indexOf(u'_');
1747 if (pos > -1)
1749 QString lang = name.left(pos);
1750 index = m_ui->comboI18n->findData(lang, Qt::UserRole);
1753 if (index < 0)
1755 // Unrecognized, use US English
1756 index = m_ui->comboI18n->findData(u"en"_s, Qt::UserRole);
1757 Q_ASSERT(index >= 0);
1759 m_ui->comboI18n->setCurrentIndex(index);
1762 Path OptionsDialog::getTorrentExportDir() const
1764 if (m_ui->checkExportDir->isChecked())
1765 return m_ui->textExportDir->selectedPath();
1766 return {};
1769 Path OptionsDialog::getFinishedTorrentExportDir() const
1771 if (m_ui->checkExportDirFin->isChecked())
1772 return m_ui->textExportDirFin->selectedPath();
1773 return {};
1776 void OptionsDialog::on_addWatchedFolderButton_clicked()
1778 Preferences *const pref = Preferences::instance();
1779 const Path dir {QFileDialog::getExistingDirectory(
1780 this, tr("Select folder to monitor"), pref->getScanDirsLastPath().parentPath().toString())};
1781 if (dir.isEmpty())
1782 return;
1784 auto *dialog = new WatchedFolderOptionsDialog({}, this);
1785 dialog->setAttribute(Qt::WA_DeleteOnClose);
1786 connect(dialog, &QDialog::accepted, this, [this, dialog, dir, pref]()
1790 auto *watchedFoldersModel = static_cast<WatchedFoldersModel *>(m_ui->scanFoldersView->model());
1791 watchedFoldersModel->addFolder(dir, dialog->watchedFolderOptions());
1793 pref->setScanDirsLastPath(dir);
1795 for (int i = 0; i < watchedFoldersModel->columnCount(); ++i)
1796 m_ui->scanFoldersView->resizeColumnToContents(i);
1798 enableApplyButton();
1800 catch (const RuntimeError &err)
1802 QMessageBox::critical(this, tr("Adding entry failed"), err.message());
1806 dialog->open();
1809 void OptionsDialog::on_editWatchedFolderButton_clicked()
1811 const QModelIndex selected
1812 = m_ui->scanFoldersView->selectionModel()->selectedIndexes().at(0);
1814 editWatchedFolderOptions(selected);
1817 void OptionsDialog::on_removeWatchedFolderButton_clicked()
1819 const QModelIndexList selected
1820 = m_ui->scanFoldersView->selectionModel()->selectedIndexes();
1822 for (const QModelIndex &index : selected)
1823 m_ui->scanFoldersView->model()->removeRow(index.row());
1826 void OptionsDialog::handleWatchedFolderViewSelectionChanged()
1828 const QModelIndexList selectedIndexes = m_ui->scanFoldersView->selectionModel()->selectedIndexes();
1829 m_ui->removeWatchedFolderButton->setEnabled(!selectedIndexes.isEmpty());
1830 m_ui->editWatchedFolderButton->setEnabled(selectedIndexes.count() == 1);
1833 void OptionsDialog::editWatchedFolderOptions(const QModelIndex &index)
1835 if (!index.isValid())
1836 return;
1838 auto *watchedFoldersModel = static_cast<WatchedFoldersModel *>(m_ui->scanFoldersView->model());
1839 auto *dialog = new WatchedFolderOptionsDialog(watchedFoldersModel->folderOptions(index.row()), this);
1840 dialog->setAttribute(Qt::WA_DeleteOnClose);
1841 connect(dialog, &QDialog::accepted, this, [this, dialog, index, watchedFoldersModel]()
1843 if (index.isValid())
1845 // The index could be invalidated while the dialog was displayed,
1846 // for example, if you deleted the folder using the Web API.
1847 watchedFoldersModel->setFolderOptions(index.row(), dialog->watchedFolderOptions());
1848 enableApplyButton();
1852 dialog->open();
1855 // Return Filter object to apply to BT session
1856 Path OptionsDialog::getFilter() const
1858 return m_ui->textFilterPath->selectedPath();
1861 #ifndef DISABLE_WEBUI
1862 void OptionsDialog::webUIHttpsCertChanged(const Path &path)
1864 const auto readResult = Utils::IO::readFile(path, Utils::Net::MAX_SSL_FILE_SIZE);
1865 const bool isCertValid = Utils::Net::isSSLCertificatesValid(readResult.value_or(QByteArray()));
1867 m_ui->textWebUIHttpsCert->setSelectedPath(path);
1868 m_ui->lblSslCertStatus->setPixmap(UIThemeManager::instance()->getScaledPixmap(
1869 (isCertValid ? u"security-high"_s : u"security-low"_s), 24));
1872 void OptionsDialog::webUIHttpsKeyChanged(const Path &path)
1874 const auto readResult = Utils::IO::readFile(path, Utils::Net::MAX_SSL_FILE_SIZE);
1875 const bool isKeyValid = Utils::Net::isSSLKeyValid(readResult.value_or(QByteArray()));
1877 m_ui->textWebUIHttpsKey->setSelectedPath(path);
1878 m_ui->lblSslKeyStatus->setPixmap(UIThemeManager::instance()->getScaledPixmap(
1879 (isKeyValid ? u"security-high"_s : u"security-low"_s), 24));
1882 bool OptionsDialog::isWebUIEnabled() const
1884 return m_ui->checkWebUI->isChecked();
1887 QString OptionsDialog::webUIUsername() const
1889 return m_ui->textWebUIUsername->text();
1892 QString OptionsDialog::webUIPassword() const
1894 return m_ui->textWebUIPassword->text();
1897 bool OptionsDialog::webUIAuthenticationOk()
1899 if (!isValidWebUIUsername(webUIUsername()))
1901 QMessageBox::warning(this, tr("Length Error"), tr("The WebUI username must be at least 3 characters long."));
1902 return false;
1905 const bool dontChangePassword = webUIPassword().isEmpty() && !Preferences::instance()->getWebUIPassword().isEmpty();
1906 if (!isValidWebUIPassword(webUIPassword()) && !dontChangePassword)
1908 QMessageBox::warning(this, tr("Length Error"), tr("The WebUI password must be at least 6 characters long."));
1909 return false;
1911 return true;
1914 bool OptionsDialog::isAlternativeWebUIPathValid()
1916 if (m_ui->groupAltWebUI->isChecked() && m_ui->textWebUIRootFolder->selectedPath().isEmpty())
1918 QMessageBox::warning(this, tr("Location Error"), tr("The alternative WebUI files location cannot be blank."));
1919 return false;
1921 return true;
1923 #endif
1925 void OptionsDialog::showConnectionTab()
1927 m_ui->tabSelection->setCurrentRow(TAB_CONNECTION);
1930 #ifndef DISABLE_WEBUI
1931 void OptionsDialog::on_registerDNSBtn_clicked()
1933 const auto service = static_cast<DNS::Service>(m_ui->comboDNSService->currentIndex());
1934 QDesktopServices::openUrl(Net::DNSUpdater::getRegistrationUrl(service));
1936 #endif
1938 void OptionsDialog::on_IpFilterRefreshBtn_clicked()
1940 if (m_refreshingIpFilter) return;
1941 m_refreshingIpFilter = true;
1942 // Updating program preferences
1943 BitTorrent::Session *const session = BitTorrent::Session::instance();
1944 session->setIPFilteringEnabled(true);
1945 session->setIPFilterFile({}); // forcing Session reload filter file
1946 session->setIPFilterFile(getFilter());
1947 connect(session, &BitTorrent::Session::IPFilterParsed, this, &OptionsDialog::handleIPFilterParsed);
1948 setCursor(QCursor(Qt::WaitCursor));
1951 void OptionsDialog::handleIPFilterParsed(bool error, int ruleCount)
1953 setCursor(QCursor(Qt::ArrowCursor));
1954 if (error)
1955 QMessageBox::warning(this, tr("Parsing error"), tr("Failed to parse the provided IP filter"));
1956 else
1957 QMessageBox::information(this, tr("Successfully refreshed"), tr("Successfully parsed the provided IP filter: %1 rules were applied.", "%1 is a number").arg(ruleCount));
1958 m_refreshingIpFilter = false;
1959 disconnect(BitTorrent::Session::instance(), &BitTorrent::Session::IPFilterParsed, this, &OptionsDialog::handleIPFilterParsed);
1962 bool OptionsDialog::schedTimesOk()
1964 if (m_ui->timeEditScheduleFrom->time() == m_ui->timeEditScheduleTo->time())
1966 QMessageBox::warning(this, tr("Time Error"), tr("The start time and the end time can't be the same."));
1967 return false;
1969 return true;
1972 void OptionsDialog::on_banListButton_clicked()
1974 auto *dialog = new BanListOptionsDialog(this);
1975 dialog->setAttribute(Qt::WA_DeleteOnClose);
1976 connect(dialog, &QDialog::accepted, this, &OptionsDialog::enableApplyButton);
1977 dialog->open();
1980 void OptionsDialog::on_IPSubnetWhitelistButton_clicked()
1982 auto *dialog = new IPSubnetWhitelistOptionsDialog(this);
1983 dialog->setAttribute(Qt::WA_DeleteOnClose);
1984 connect(dialog, &QDialog::accepted, this, &OptionsDialog::enableApplyButton);
1985 dialog->open();