Allow to globally disable the use of proxy
[qBittorrent.git] / src / gui / optionsdialog.cpp
blobe3898f652c413d9e3edc555d9f5e9846b395a6ed
1 /*
2 * Bittorrent Client using Qt and libtorrent.
3 * Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * In addition, as a special exception, the copyright holders give permission to
20 * link this program with the OpenSSL project's "OpenSSL" library (or with
21 * modified versions of it that use the same license as the "OpenSSL" library),
22 * and distribute the linked executables. You must obey the GNU General Public
23 * License in all respects for all of the code used other than "OpenSSL". If you
24 * modify file(s), you may extend this exception to your version of the file(s),
25 * but you are not obligated to do so. If you do not wish to do so, delete this
26 * exception statement from your version.
29 #include "optionsdialog.h"
31 #include <cstdlib>
32 #include <limits>
34 #include <QApplication>
35 #include <QDebug>
36 #include <QDesktopServices>
37 #include <QDialogButtonBox>
38 #include <QEvent>
39 #include <QFileDialog>
40 #include <QMessageBox>
41 #include <QSystemTrayIcon>
42 #include <QTranslator>
44 #include "base/bittorrent/session.h"
45 #include "base/exceptions.h"
46 #include "base/global.h"
47 #include "base/net/portforwarder.h"
48 #include "base/net/proxyconfigurationmanager.h"
49 #include "base/path.h"
50 #include "base/preferences.h"
51 #include "base/rss/rss_autodownloader.h"
52 #include "base/rss/rss_session.h"
53 #include "base/torrentfileguard.h"
54 #include "base/torrentfileswatcher.h"
55 #include "base/utils/io.h"
56 #include "base/utils/misc.h"
57 #include "base/utils/net.h"
58 #include "base/utils/password.h"
59 #include "base/utils/random.h"
60 #include "addnewtorrentdialog.h"
61 #include "advancedsettings.h"
62 #include "banlistoptionsdialog.h"
63 #include "interfaces/iguiapplication.h"
64 #include "ipsubnetwhitelistoptionsdialog.h"
65 #include "rss/automatedrssdownloader.h"
66 #include "ui_optionsdialog.h"
67 #include "uithemedialog.h"
68 #include "uithememanager.h"
69 #include "utils.h"
70 #include "watchedfolderoptionsdialog.h"
71 #include "watchedfoldersmodel.h"
73 #ifndef DISABLE_WEBUI
74 #include "base/net/dnsupdater.h"
75 #endif
77 #define SETTINGS_KEY(name) u"OptionsDialog/" name
79 namespace
81 QStringList translatedWeekdayNames()
83 // return translated strings from Monday to Sunday in user selected locale
85 const QLocale locale {Preferences::instance()->getLocale()};
86 const QDate date {2018, 11, 5}; // Monday
87 QStringList ret;
88 for (int i = 0; i < 7; ++i)
89 ret.append(locale.toString(date.addDays(i), u"dddd"_s));
90 return ret;
93 class WheelEventEater final : public QObject
95 public:
96 using QObject::QObject;
98 private:
99 bool eventFilter(QObject *, QEvent *event) override
101 return (event->type() == QEvent::Wheel);
105 // Shortcuts for frequently used signals that have more than one overload. They would require
106 // type casts and that is why we declare required member pointer here instead.
107 void (QComboBox::*qComboBoxCurrentIndexChanged)(int) = &QComboBox::currentIndexChanged;
108 void (QSpinBox::*qSpinBoxValueChanged)(int) = &QSpinBox::valueChanged;
111 // Constructor
112 OptionsDialog::OptionsDialog(IGUIApplication *app, QWidget *parent)
113 : QDialog(parent)
114 , GUIApplicationComponent(app)
115 , m_ui {new Ui::OptionsDialog}
116 , m_storeDialogSize {SETTINGS_KEY(u"Size"_s)}
117 , m_storeHSplitterSize {SETTINGS_KEY(u"HorizontalSplitterSizes"_s)}
118 , m_storeLastViewedPage {SETTINGS_KEY(u"LastViewedPage"_s)}
120 m_ui->setupUi(this);
121 m_applyButton = m_ui->buttonBox->button(QDialogButtonBox::Apply);
123 #ifdef Q_OS_UNIX
124 setWindowTitle(tr("Preferences"));
125 #endif
127 m_ui->hsplitter->setCollapsible(0, false);
128 m_ui->hsplitter->setCollapsible(1, false);
130 // Main icons
131 m_ui->tabSelection->item(TAB_UI)->setIcon(UIThemeManager::instance()->getIcon(u"preferences-desktop"_s));
132 m_ui->tabSelection->item(TAB_BITTORRENT)->setIcon(UIThemeManager::instance()->getIcon(u"preferences-bittorrent"_s, u"preferences-system-network"_s));
133 m_ui->tabSelection->item(TAB_CONNECTION)->setIcon(UIThemeManager::instance()->getIcon(u"network-connect"_s, u"network-wired"_s));
134 m_ui->tabSelection->item(TAB_DOWNLOADS)->setIcon(UIThemeManager::instance()->getIcon(u"download"_s, u"folder-download"_s));
135 m_ui->tabSelection->item(TAB_SPEED)->setIcon(UIThemeManager::instance()->getIcon(u"speedometer"_s, u"chronometer"_s));
136 m_ui->tabSelection->item(TAB_RSS)->setIcon(UIThemeManager::instance()->getIcon(u"application-rss"_s, u"application-rss+xml"_s));
137 #ifdef DISABLE_WEBUI
138 m_ui->tabSelection->item(TAB_WEBUI)->setHidden(true);
139 #else
140 m_ui->tabSelection->item(TAB_WEBUI)->setIcon(UIThemeManager::instance()->getIcon(u"preferences-webui"_s, u"network-server"_s));
141 #endif
142 m_ui->tabSelection->item(TAB_ADVANCED)->setIcon(UIThemeManager::instance()->getIcon(u"preferences-advanced"_s, u"preferences-other"_s));
144 // set uniform size for all icons
145 int maxHeight = -1;
146 for (int i = 0; i < m_ui->tabSelection->count(); ++i)
147 maxHeight = std::max(maxHeight, m_ui->tabSelection->visualItemRect(m_ui->tabSelection->item(i)).size().height());
148 for (int i = 0; i < m_ui->tabSelection->count(); ++i)
150 const QSize size(std::numeric_limits<int>::max(), static_cast<int>(maxHeight * 1.2));
151 m_ui->tabSelection->item(i)->setSizeHint(size);
154 connect(m_ui->tabSelection, &QListWidget::currentItemChanged, this, &ThisType::changePage);
156 // Load options
157 loadBehaviorTabOptions();
158 loadDownloadsTabOptions();
159 loadConnectionTabOptions();
160 loadSpeedTabOptions();
161 loadBittorrentTabOptions();
162 loadRSSTabOptions();
163 #ifndef DISABLE_WEBUI
164 loadWebUITabOptions();
165 #endif
167 // Load Advanced settings
168 m_advancedSettings = new AdvancedSettings(app, m_ui->tabAdvancedPage);
169 m_ui->advPageLayout->addWidget(m_advancedSettings);
170 connect(m_advancedSettings, &AdvancedSettings::settingsChanged, this, &ThisType::enableApplyButton);
172 // setup apply button
173 m_applyButton->setEnabled(false);
174 connect(m_applyButton, &QPushButton::clicked, this, &OptionsDialog::applySettings);
176 // disable mouse wheel event on widgets to avoid misselection
177 auto *wheelEventEater = new WheelEventEater(this);
178 for (QComboBox *widget : asConst(findChildren<QComboBox *>()))
179 widget->installEventFilter(wheelEventEater);
180 for (QSpinBox *widget : asConst(findChildren<QSpinBox *>()))
181 widget->installEventFilter(wheelEventEater);
183 m_ui->tabSelection->setCurrentRow(m_storeLastViewedPage);
185 if (const QSize dialogSize = m_storeDialogSize; dialogSize.isValid())
186 resize(dialogSize);
189 OptionsDialog::~OptionsDialog()
191 // save dialog states
192 m_storeDialogSize = size();
194 QStringList hSplitterSizes;
195 for (const int size : asConst(m_ui->hsplitter->sizes()))
196 hSplitterSizes.append(QString::number(size));
197 m_storeHSplitterSize = hSplitterSizes;
199 m_storeLastViewedPage = m_ui->tabSelection->currentRow();
201 delete m_ui;
204 void OptionsDialog::loadBehaviorTabOptions()
206 const auto *pref = Preferences::instance();
207 const auto *session = BitTorrent::Session::instance();
209 initializeLanguageCombo();
210 setLocale(pref->getLocale());
212 m_ui->checkUseCustomTheme->setChecked(Preferences::instance()->useCustomUITheme());
213 m_ui->customThemeFilePath->setSelectedPath(Preferences::instance()->customUIThemePath());
214 m_ui->customThemeFilePath->setMode(FileSystemPathEdit::Mode::FileOpen);
215 m_ui->customThemeFilePath->setDialogCaption(tr("Select qBittorrent UI Theme file"));
216 m_ui->customThemeFilePath->setFileNameFilter(tr("qBittorrent UI Theme file (*.qbtheme config.json)"));
217 #if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS))
218 m_ui->checkUseSystemIcon->setChecked(pref->useSystemIcons());
219 #else
220 m_ui->checkUseSystemIcon->setVisible(false);
221 #endif
223 m_ui->confirmDeletion->setChecked(pref->confirmTorrentDeletion());
224 m_ui->checkAltRowColors->setChecked(pref->useAlternatingRowColors());
225 m_ui->checkHideZero->setChecked(pref->getHideZeroValues());
226 m_ui->comboHideZero->setCurrentIndex(pref->getHideZeroComboValues());
227 m_ui->comboHideZero->setEnabled(m_ui->checkHideZero->isChecked());
229 m_ui->actionTorrentDlOnDblClBox->setItemData(0, TOGGLE_PAUSE);
230 m_ui->actionTorrentDlOnDblClBox->setItemData(1, OPEN_DEST);
231 m_ui->actionTorrentDlOnDblClBox->setItemData(2, PREVIEW_FILE);
232 m_ui->actionTorrentDlOnDblClBox->setItemData(3, SHOW_OPTIONS);
233 m_ui->actionTorrentDlOnDblClBox->setItemData(4, NO_ACTION);
234 int actionDownloading = pref->getActionOnDblClOnTorrentDl();
235 if ((actionDownloading < 0) || (actionDownloading >= m_ui->actionTorrentDlOnDblClBox->count()))
236 actionDownloading = TOGGLE_PAUSE;
237 m_ui->actionTorrentDlOnDblClBox->setCurrentIndex(m_ui->actionTorrentDlOnDblClBox->findData(actionDownloading));
239 m_ui->actionTorrentFnOnDblClBox->setItemData(0, TOGGLE_PAUSE);
240 m_ui->actionTorrentFnOnDblClBox->setItemData(1, OPEN_DEST);
241 m_ui->actionTorrentFnOnDblClBox->setItemData(2, PREVIEW_FILE);
242 m_ui->actionTorrentFnOnDblClBox->setItemData(3, SHOW_OPTIONS);
243 m_ui->actionTorrentFnOnDblClBox->setItemData(4, NO_ACTION);
244 int actionSeeding = pref->getActionOnDblClOnTorrentFn();
245 if ((actionSeeding < 0) || (actionSeeding >= m_ui->actionTorrentFnOnDblClBox->count()))
246 actionSeeding = OPEN_DEST;
247 m_ui->actionTorrentFnOnDblClBox->setCurrentIndex(m_ui->actionTorrentFnOnDblClBox->findData(actionSeeding));
249 m_ui->checkBoxHideZeroStatusFilters->setChecked(pref->getHideZeroStatusFilters());
251 #ifndef Q_OS_WIN
252 m_ui->checkStartup->setVisible(false);
253 #endif
254 m_ui->checkShowSplash->setChecked(!pref->isSplashScreenDisabled());
255 m_ui->checkProgramExitConfirm->setChecked(pref->confirmOnExit());
256 m_ui->checkProgramAutoExitConfirm->setChecked(!pref->dontConfirmAutoExit());
257 m_ui->checkConfirmPauseAndResumeAll->setChecked(pref->confirmPauseAndResumeAll());
259 m_ui->windowStateComboBox->addItem(tr("Normal"), QVariant::fromValue(WindowState::Normal));
260 m_ui->windowStateComboBox->addItem(tr("Minimized"), QVariant::fromValue(WindowState::Minimized));
261 #ifndef Q_OS_MACOS
262 m_ui->windowStateComboBox->addItem(tr("Hidden"), QVariant::fromValue(WindowState::Hidden));
263 #endif
264 m_ui->windowStateComboBox->setCurrentIndex(m_ui->windowStateComboBox->findData(QVariant::fromValue(app()->startUpWindowState())));
266 #if !(defined(Q_OS_WIN) || defined(Q_OS_MACOS))
267 m_ui->groupFileAssociation->setVisible(false);
268 m_ui->checkProgramUpdates->setVisible(false);
269 #endif
271 #ifndef Q_OS_MACOS
272 // Disable systray integration if it is not supported by the system
273 if (!QSystemTrayIcon::isSystemTrayAvailable())
275 m_ui->checkShowSystray->setChecked(false);
276 m_ui->checkShowSystray->setEnabled(false);
277 m_ui->checkShowSystray->setToolTip(tr("Disabled due to failed to detect system tray presence"));
279 m_ui->checkShowSystray->setChecked(pref->systemTrayEnabled());
280 m_ui->checkMinimizeToSysTray->setChecked(pref->minimizeToTray());
281 m_ui->checkCloseToSystray->setChecked(pref->closeToTray());
282 m_ui->comboTrayIcon->setCurrentIndex(static_cast<int>(pref->trayIconStyle()));
283 #endif
285 #ifdef Q_OS_WIN
286 m_ui->checkStartup->setChecked(pref->WinStartup());
287 m_ui->checkAssociateTorrents->setChecked(Preferences::isTorrentFileAssocSet());
288 m_ui->checkAssociateMagnetLinks->setChecked(Preferences::isMagnetLinkAssocSet());
289 #endif
291 #ifdef Q_OS_MACOS
292 m_ui->checkShowSystray->setVisible(false);
293 m_ui->checkAssociateTorrents->setChecked(Preferences::isTorrentFileAssocSet());
294 m_ui->checkAssociateTorrents->setEnabled(!m_ui->checkAssociateTorrents->isChecked());
295 m_ui->checkAssociateMagnetLinks->setChecked(Preferences::isMagnetLinkAssocSet());
296 m_ui->checkAssociateMagnetLinks->setEnabled(!m_ui->checkAssociateMagnetLinks->isChecked());
297 #endif
299 #if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
300 m_ui->checkProgramUpdates->setChecked(pref->isUpdateCheckEnabled());
301 #endif
303 m_ui->checkPreventFromSuspendWhenDownloading->setChecked(pref->preventFromSuspendWhenDownloading());
304 m_ui->checkPreventFromSuspendWhenSeeding->setChecked(pref->preventFromSuspendWhenSeeding());
306 m_ui->textFileLogPath->setDialogCaption(tr("Choose a save directory"));
307 m_ui->textFileLogPath->setMode(FileSystemPathEdit::Mode::DirectorySave);
308 m_ui->textFileLogPath->setSelectedPath(app()->fileLoggerPath());
309 const bool fileLogBackup = app()->isFileLoggerBackup();
310 m_ui->checkFileLogBackup->setChecked(fileLogBackup);
311 m_ui->spinFileLogSize->setEnabled(fileLogBackup);
312 const bool fileLogDelete = app()->isFileLoggerDeleteOld();
313 m_ui->checkFileLogDelete->setChecked(fileLogDelete);
314 m_ui->spinFileLogAge->setEnabled(fileLogDelete);
315 m_ui->comboFileLogAgeType->setEnabled(fileLogDelete);
316 m_ui->spinFileLogSize->setValue(app()->fileLoggerMaxSize() / 1024);
317 m_ui->spinFileLogAge->setValue(app()->fileLoggerAge());
318 m_ui->comboFileLogAgeType->setCurrentIndex(app()->fileLoggerAgeType());
319 // Groupbox's check state must be initialized after some of its children if they are manually enabled/disabled
320 m_ui->checkFileLog->setChecked(app()->isFileLoggerEnabled());
322 m_ui->checkBoxPerformanceWarning->setChecked(session->isPerformanceWarningEnabled());
324 connect(m_ui->comboI18n, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
326 #if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS))
327 connect(m_ui->checkUseSystemIcon, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
328 #endif
329 connect(m_ui->checkUseCustomTheme, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
330 connect(m_ui->customThemeFilePath, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
332 m_ui->buttonCustomizeUITheme->setEnabled(!m_ui->checkUseCustomTheme->isChecked());
333 connect(m_ui->checkUseCustomTheme, &QGroupBox::toggled, this, [this]
335 m_ui->buttonCustomizeUITheme->setEnabled(!m_ui->checkUseCustomTheme->isChecked());
337 connect(m_ui->buttonCustomizeUITheme, &QPushButton::clicked, this, [this]
339 auto *dialog = new UIThemeDialog(this);
340 dialog->setAttribute(Qt::WA_DeleteOnClose);
341 dialog->open();
344 connect(m_ui->confirmDeletion, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
345 connect(m_ui->checkAltRowColors, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
346 connect(m_ui->checkHideZero, &QAbstractButton::toggled, m_ui->comboHideZero, &QWidget::setEnabled);
347 connect(m_ui->checkHideZero, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
348 connect(m_ui->comboHideZero, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
349 connect(m_ui->actionTorrentDlOnDblClBox, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
350 connect(m_ui->actionTorrentFnOnDblClBox, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
351 connect(m_ui->checkBoxHideZeroStatusFilters, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
353 #ifdef Q_OS_WIN
354 connect(m_ui->checkStartup, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
355 #endif
356 connect(m_ui->checkShowSplash, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
357 connect(m_ui->checkProgramExitConfirm, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
358 connect(m_ui->checkProgramAutoExitConfirm, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
359 connect(m_ui->checkConfirmPauseAndResumeAll, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
360 connect(m_ui->checkShowSystray, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
361 connect(m_ui->checkMinimizeToSysTray, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
362 connect(m_ui->checkCloseToSystray, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
363 connect(m_ui->comboTrayIcon, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
364 connect(m_ui->windowStateComboBox, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
366 connect(m_ui->checkPreventFromSuspendWhenDownloading, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
367 connect(m_ui->checkPreventFromSuspendWhenSeeding, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
369 #if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
370 connect(m_ui->checkAssociateTorrents, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
371 connect(m_ui->checkAssociateMagnetLinks, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
372 connect(m_ui->checkProgramUpdates, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
373 #endif
375 #if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) && !defined(QBT_USES_DBUS)
376 m_ui->checkPreventFromSuspendWhenDownloading->setDisabled(true);
377 m_ui->checkPreventFromSuspendWhenSeeding->setDisabled(true);
378 #endif
380 connect(m_ui->checkFileLog, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
381 connect(m_ui->textFileLogPath, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
382 connect(m_ui->checkFileLogBackup, &QAbstractButton::toggled, m_ui->spinFileLogSize, &QWidget::setEnabled);
383 connect(m_ui->checkFileLogBackup, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
384 connect(m_ui->checkFileLogDelete, &QAbstractButton::toggled, m_ui->comboFileLogAgeType, &QWidget::setEnabled);
385 connect(m_ui->checkFileLogDelete, &QAbstractButton::toggled, m_ui->spinFileLogAge, &QWidget::setEnabled);
386 connect(m_ui->checkFileLogDelete, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
387 connect(m_ui->spinFileLogSize, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
388 connect(m_ui->spinFileLogAge, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
389 connect(m_ui->comboFileLogAgeType, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
391 connect(m_ui->checkBoxPerformanceWarning, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
394 void OptionsDialog::saveBehaviorTabOptions() const
396 auto *pref = Preferences::instance();
397 auto *session = BitTorrent::Session::instance();
399 // Load the translation
400 const QString locale = getLocale();
401 if (pref->getLocale() != locale)
403 auto *translator = new QTranslator;
404 if (translator->load(u":/lang/qbittorrent_"_s + locale))
405 qDebug("%s locale recognized, using translation.", qUtf8Printable(locale));
406 else
407 qDebug("%s locale unrecognized, using default (en).", qUtf8Printable(locale));
408 qApp->installTranslator(translator);
410 pref->setLocale(locale);
412 #if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS))
413 pref->useSystemIcons(m_ui->checkUseSystemIcon->isChecked());
414 #endif
415 pref->setUseCustomUITheme(m_ui->checkUseCustomTheme->isChecked());
416 pref->setCustomUIThemePath(m_ui->customThemeFilePath->selectedPath());
418 pref->setConfirmTorrentDeletion(m_ui->confirmDeletion->isChecked());
419 pref->setAlternatingRowColors(m_ui->checkAltRowColors->isChecked());
420 pref->setHideZeroValues(m_ui->checkHideZero->isChecked());
421 pref->setHideZeroComboValues(m_ui->comboHideZero->currentIndex());
423 pref->setActionOnDblClOnTorrentDl(m_ui->actionTorrentDlOnDblClBox->currentData().toInt());
424 pref->setActionOnDblClOnTorrentFn(m_ui->actionTorrentFnOnDblClBox->currentData().toInt());
426 pref->setHideZeroStatusFilters(m_ui->checkBoxHideZeroStatusFilters->isChecked());
428 pref->setSplashScreenDisabled(isSplashScreenDisabled());
429 pref->setConfirmOnExit(m_ui->checkProgramExitConfirm->isChecked());
430 pref->setDontConfirmAutoExit(!m_ui->checkProgramAutoExitConfirm->isChecked());
431 pref->setConfirmPauseAndResumeAll(m_ui->checkConfirmPauseAndResumeAll->isChecked());
433 #ifdef Q_OS_WIN
434 pref->setWinStartup(WinStartup());
436 Preferences::setTorrentFileAssoc(m_ui->checkAssociateTorrents->isChecked());
437 Preferences::setMagnetLinkAssoc(m_ui->checkAssociateMagnetLinks->isChecked());
438 #endif
440 #ifndef Q_OS_MACOS
441 pref->setSystemTrayEnabled(m_ui->checkShowSystray->isChecked());
442 pref->setTrayIconStyle(TrayIcon::Style(m_ui->comboTrayIcon->currentIndex()));
443 pref->setCloseToTray(m_ui->checkCloseToSystray->isChecked());
444 pref->setMinimizeToTray(m_ui->checkMinimizeToSysTray->isChecked());
445 #endif
447 #ifdef Q_OS_MACOS
448 if (m_ui->checkAssociateTorrents->isChecked())
450 Preferences::setTorrentFileAssoc();
451 m_ui->checkAssociateTorrents->setChecked(Preferences::isTorrentFileAssocSet());
452 m_ui->checkAssociateTorrents->setEnabled(!m_ui->checkAssociateTorrents->isChecked());
454 if (m_ui->checkAssociateMagnetLinks->isChecked())
456 Preferences::setMagnetLinkAssoc();
457 m_ui->checkAssociateMagnetLinks->setChecked(Preferences::isMagnetLinkAssocSet());
458 m_ui->checkAssociateMagnetLinks->setEnabled(!m_ui->checkAssociateMagnetLinks->isChecked());
460 #endif
462 #if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
463 pref->setUpdateCheckEnabled(m_ui->checkProgramUpdates->isChecked());
464 #endif
466 pref->setPreventFromSuspendWhenDownloading(m_ui->checkPreventFromSuspendWhenDownloading->isChecked());
467 pref->setPreventFromSuspendWhenSeeding(m_ui->checkPreventFromSuspendWhenSeeding->isChecked());
469 app()->setFileLoggerPath(m_ui->textFileLogPath->selectedPath());
470 app()->setFileLoggerBackup(m_ui->checkFileLogBackup->isChecked());
471 app()->setFileLoggerMaxSize(m_ui->spinFileLogSize->value() * 1024);
472 app()->setFileLoggerAge(m_ui->spinFileLogAge->value());
473 app()->setFileLoggerAgeType(m_ui->comboFileLogAgeType->currentIndex());
474 app()->setFileLoggerDeleteOld(m_ui->checkFileLogDelete->isChecked());
475 app()->setFileLoggerEnabled(m_ui->checkFileLog->isChecked());
477 app()->setStartUpWindowState(m_ui->windowStateComboBox->currentData().value<WindowState>());
479 session->setPerformanceWarningEnabled(m_ui->checkBoxPerformanceWarning->isChecked());
482 void OptionsDialog::loadDownloadsTabOptions()
484 const auto *pref = Preferences::instance();
485 const auto *session = BitTorrent::Session::instance();
487 m_ui->checkAdditionDialog->setChecked(AddNewTorrentDialog::isEnabled());
488 m_ui->checkAdditionDialogFront->setChecked(AddNewTorrentDialog::isTopLevel());
490 m_ui->contentLayoutComboBox->setCurrentIndex(static_cast<int>(session->torrentContentLayout()));
491 m_ui->checkAddToQueueTop->setChecked(session->isAddTorrentToQueueTop());
492 m_ui->checkStartPaused->setChecked(session->isAddTorrentPaused());
494 m_ui->stopConditionComboBox->setToolTip(
495 u"<html><body><p><b>" + tr("None") + u"</b> - " + tr("No stop condition is set.") + u"</p><p><b>" +
496 tr("Metadata received") + u"</b> - " + tr("Torrent will stop after metadata is received.") +
497 u" <em>" + tr("Torrents that have metadata initially aren't affected.") + u"</em></p><p><b>" +
498 tr("Files checked") + u"</b> - " + tr("Torrent will stop after files are initially checked.") +
499 u" <em>" + tr("This will also download metadata if it wasn't there initially.") + u"</em></p></body></html>");
500 m_ui->stopConditionComboBox->setItemData(0, QVariant::fromValue(BitTorrent::Torrent::StopCondition::None));
501 m_ui->stopConditionComboBox->setItemData(1, QVariant::fromValue(BitTorrent::Torrent::StopCondition::MetadataReceived));
502 m_ui->stopConditionComboBox->setItemData(2, QVariant::fromValue(BitTorrent::Torrent::StopCondition::FilesChecked));
503 m_ui->stopConditionComboBox->setCurrentIndex(m_ui->stopConditionComboBox->findData(QVariant::fromValue(session->torrentStopCondition())));
504 m_ui->stopConditionLabel->setEnabled(!m_ui->checkStartPaused->isChecked());
505 m_ui->stopConditionComboBox->setEnabled(!m_ui->checkStartPaused->isChecked());
507 const TorrentFileGuard::AutoDeleteMode autoDeleteMode = TorrentFileGuard::autoDeleteMode();
508 m_ui->deleteTorrentBox->setChecked(autoDeleteMode != TorrentFileGuard::Never);
509 m_ui->deleteCancelledTorrentBox->setChecked(autoDeleteMode == TorrentFileGuard::Always);
510 m_ui->deleteTorrentWarningIcon->setPixmap(QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical).pixmap(16, 16));
511 m_ui->deleteTorrentWarningIcon->hide();
512 m_ui->deleteTorrentWarningLabel->hide();
513 m_ui->deleteTorrentWarningLabel->setToolTip(u"<html><body><p>" +
514 tr("By enabling these options, you can <strong>irrevocably lose</strong> your .torrent files!") +
515 u"</p><p>" +
516 tr("When these options are enabled, qBittorrent will <strong>delete</strong> .torrent files "
517 "after they were successfully (the first option) or not (the second option) added to its "
518 "download queue. This will be applied <strong>not only</strong> to the files opened via "
519 "&ldquo;Add torrent&rdquo; menu action but to those opened via <strong>file type association</strong> as well") +
520 u"</p><p>" +
521 tr("If you enable the second option (&ldquo;Also when addition is cancelled&rdquo;) the "
522 ".torrent file <strong>will be deleted</strong> even if you press &ldquo;<strong>Cancel</strong>&rdquo; in "
523 "the &ldquo;Add torrent&rdquo; dialog") +
524 u"</p></body></html>");
526 m_ui->checkPreallocateAll->setChecked(session->isPreallocationEnabled());
527 m_ui->checkAppendqB->setChecked(session->isAppendExtensionEnabled());
528 m_ui->checkRecursiveDownload->setChecked(pref->isRecursiveDownloadEnabled());
530 m_ui->comboSavingMode->setCurrentIndex(!session->isAutoTMMDisabledByDefault());
531 m_ui->comboTorrentCategoryChanged->setCurrentIndex(session->isDisableAutoTMMWhenCategoryChanged());
532 m_ui->comboCategoryChanged->setCurrentIndex(session->isDisableAutoTMMWhenCategorySavePathChanged());
533 m_ui->comboCategoryDefaultPathChanged->setCurrentIndex(session->isDisableAutoTMMWhenDefaultSavePathChanged());
535 m_ui->checkUseSubcategories->setChecked(session->isSubcategoriesEnabled());
536 m_ui->checkUseCategoryPaths->setChecked(session->useCategoryPathsInManualMode());
538 m_ui->textSavePath->setDialogCaption(tr("Choose a save directory"));
539 m_ui->textSavePath->setMode(FileSystemPathEdit::Mode::DirectorySave);
540 m_ui->textSavePath->setSelectedPath(session->savePath());
542 m_ui->checkUseDownloadPath->setChecked(session->isDownloadPathEnabled());
543 m_ui->textDownloadPath->setDialogCaption(tr("Choose a save directory"));
544 m_ui->textDownloadPath->setEnabled(m_ui->checkUseDownloadPath->isChecked());
545 m_ui->textDownloadPath->setMode(FileSystemPathEdit::Mode::DirectorySave);
546 m_ui->textDownloadPath->setSelectedPath(session->downloadPath());
548 const bool isExportDirEmpty = session->torrentExportDirectory().isEmpty();
549 m_ui->checkExportDir->setChecked(!isExportDirEmpty);
550 m_ui->textExportDir->setDialogCaption(tr("Choose export directory"));
551 m_ui->textExportDir->setEnabled(m_ui->checkExportDir->isChecked());
552 m_ui->textExportDir->setMode(FileSystemPathEdit::Mode::DirectorySave);
553 if (!isExportDirEmpty)
554 m_ui->textExportDir->setSelectedPath(session->torrentExportDirectory());
556 const bool isExportDirFinEmpty = session->finishedTorrentExportDirectory().isEmpty();
557 m_ui->checkExportDirFin->setChecked(!isExportDirFinEmpty);
558 m_ui->textExportDirFin->setDialogCaption(tr("Choose export directory"));
559 m_ui->textExportDirFin->setEnabled(m_ui->checkExportDirFin->isChecked());
560 m_ui->textExportDirFin->setMode(FileSystemPathEdit::Mode::DirectorySave);
561 if (!isExportDirFinEmpty)
562 m_ui->textExportDirFin->setSelectedPath(session->finishedTorrentExportDirectory());
564 auto *watchedFoldersModel = new WatchedFoldersModel(TorrentFilesWatcher::instance(), this);
565 connect(watchedFoldersModel, &QAbstractListModel::dataChanged, this, &ThisType::enableApplyButton);
566 m_ui->scanFoldersView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
567 m_ui->scanFoldersView->setModel(watchedFoldersModel);
568 connect(m_ui->scanFoldersView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &ThisType::handleWatchedFolderViewSelectionChanged);
569 connect(m_ui->scanFoldersView, &QTreeView::doubleClicked, this, &ThisType::editWatchedFolderOptions);
571 m_ui->groupExcludedFileNames->setChecked(session->isExcludedFileNamesEnabled());
572 m_ui->textExcludedFileNames->setPlainText(session->excludedFileNames().join(u'\n'));
574 m_ui->groupMailNotification->setChecked(pref->isMailNotificationEnabled());
575 m_ui->senderEmailTxt->setText(pref->getMailNotificationSender());
576 m_ui->lineEditDestEmail->setText(pref->getMailNotificationEmail());
577 m_ui->lineEditSmtpServer->setText(pref->getMailNotificationSMTP());
578 m_ui->checkSmtpSSL->setChecked(pref->getMailNotificationSMTPSSL());
579 m_ui->groupMailNotifAuth->setChecked(pref->getMailNotificationSMTPAuth());
580 m_ui->mailNotifUsername->setText(pref->getMailNotificationSMTPUsername());
581 m_ui->mailNotifPassword->setText(pref->getMailNotificationSMTPPassword());
583 m_ui->groupBoxRunOnAdded->setChecked(pref->isAutoRunOnTorrentAddedEnabled());
584 m_ui->groupBoxRunOnFinished->setChecked(pref->isAutoRunOnTorrentFinishedEnabled());
585 m_ui->lineEditRunOnAdded->setText(pref->getAutoRunOnTorrentAddedProgram());
586 m_ui->lineEditRunOnFinished->setText(pref->getAutoRunOnTorrentFinishedProgram());
587 #if defined(Q_OS_WIN)
588 m_ui->autoRunConsole->setChecked(pref->isAutoRunConsoleEnabled());
589 #else
590 m_ui->autoRunConsole->hide();
591 #endif
592 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
593 .arg(tr("Supported parameters (case sensitive):")
594 , tr("%N: Torrent name")
595 , tr("%L: Category")
596 , tr("%G: Tags (separated by comma)")
597 , tr("%F: Content path (same as root path for multifile torrent)")
598 , tr("%R: Root path (first torrent subdirectory path)")
599 , tr("%D: Save path")
600 , tr("%C: Number of files")
601 , tr("%Z: Torrent size (bytes)"))
602 .arg(tr("%T: Current tracker")
603 , tr("%I: Info hash v1 (or '-' if unavailable)")
604 , tr("%J: Info hash v2 (or '-' if unavailable)")
605 , tr("%K: Torrent ID (either sha-1 info hash for v1 torrent or truncated sha-256 info hash for v2/hybrid torrent)")
606 , tr("Tip: Encapsulate parameter with quotation marks to avoid text being cut off at whitespace (e.g., \"%N\")"));
607 m_ui->labelAutoRunParam->setText(autoRunStr);
609 connect(m_ui->checkAdditionDialog, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
610 connect(m_ui->checkAdditionDialogFront, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
612 connect(m_ui->contentLayoutComboBox, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
614 connect(m_ui->checkAddToQueueTop, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
615 connect(m_ui->checkStartPaused, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
616 connect(m_ui->checkStartPaused, &QAbstractButton::toggled, this, [this](const bool checked)
618 m_ui->stopConditionLabel->setEnabled(!checked);
619 m_ui->stopConditionComboBox->setEnabled(!checked);
621 connect(m_ui->stopConditionComboBox, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
622 connect(m_ui->deleteTorrentBox, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
623 connect(m_ui->deleteCancelledTorrentBox, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
625 connect(m_ui->checkPreallocateAll, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
626 connect(m_ui->checkAppendqB, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
627 connect(m_ui->checkRecursiveDownload, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
629 connect(m_ui->comboSavingMode, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
630 connect(m_ui->comboTorrentCategoryChanged, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
631 connect(m_ui->comboCategoryChanged, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
632 connect(m_ui->comboCategoryDefaultPathChanged, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
634 connect(m_ui->checkUseSubcategories, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
635 connect(m_ui->checkUseCategoryPaths, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
637 connect(m_ui->textSavePath, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
638 connect(m_ui->textDownloadPath, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
640 connect(m_ui->checkExportDir, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
641 connect(m_ui->checkExportDir, &QAbstractButton::toggled, m_ui->textExportDir, &QWidget::setEnabled);
642 connect(m_ui->checkExportDirFin, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
643 connect(m_ui->checkExportDirFin, &QAbstractButton::toggled, m_ui->textExportDirFin, &QWidget::setEnabled);
644 connect(m_ui->textExportDir, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
645 connect(m_ui->textExportDirFin, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
646 connect(m_ui->checkUseDownloadPath, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
647 connect(m_ui->checkUseDownloadPath, &QAbstractButton::toggled, m_ui->textDownloadPath, &QWidget::setEnabled);
649 connect(m_ui->addWatchedFolderButton, &QAbstractButton::clicked, this, &ThisType::enableApplyButton);
651 connect(m_ui->groupExcludedFileNames, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
652 connect(m_ui->textExcludedFileNames, &QPlainTextEdit::textChanged, this, &ThisType::enableApplyButton);
653 connect(m_ui->removeWatchedFolderButton, &QAbstractButton::clicked, this, &ThisType::enableApplyButton);
655 connect(m_ui->groupMailNotification, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
656 connect(m_ui->senderEmailTxt, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
657 connect(m_ui->lineEditDestEmail, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
658 connect(m_ui->lineEditSmtpServer, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
659 connect(m_ui->checkSmtpSSL, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
660 connect(m_ui->groupMailNotifAuth, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
661 connect(m_ui->mailNotifUsername, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
662 connect(m_ui->mailNotifPassword, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
664 connect(m_ui->groupBoxRunOnAdded, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
665 connect(m_ui->lineEditRunOnAdded, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
666 connect(m_ui->groupBoxRunOnFinished, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
667 connect(m_ui->lineEditRunOnFinished, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
668 connect(m_ui->autoRunConsole, &QCheckBox::toggled, this, &ThisType::enableApplyButton);
671 void OptionsDialog::saveDownloadsTabOptions() const
673 auto *pref = Preferences::instance();
674 auto *session = BitTorrent::Session::instance();
676 AddNewTorrentDialog::setEnabled(useAdditionDialog());
677 AddNewTorrentDialog::setTopLevel(m_ui->checkAdditionDialogFront->isChecked());
679 session->setTorrentContentLayout(static_cast<BitTorrent::TorrentContentLayout>(m_ui->contentLayoutComboBox->currentIndex()));
681 session->setAddTorrentToQueueTop(m_ui->checkAddToQueueTop->isChecked());
682 session->setAddTorrentPaused(addTorrentsInPause());
683 session->setTorrentStopCondition(m_ui->stopConditionComboBox->currentData().value<BitTorrent::Torrent::StopCondition>());
684 TorrentFileGuard::setAutoDeleteMode(!m_ui->deleteTorrentBox->isChecked() ? TorrentFileGuard::Never
685 : !m_ui->deleteCancelledTorrentBox->isChecked() ? TorrentFileGuard::IfAdded
686 : TorrentFileGuard::Always);
688 session->setPreallocationEnabled(preAllocateAllFiles());
689 session->setAppendExtensionEnabled(m_ui->checkAppendqB->isChecked());
690 pref->setRecursiveDownloadEnabled(m_ui->checkRecursiveDownload->isChecked());
692 session->setAutoTMMDisabledByDefault(m_ui->comboSavingMode->currentIndex() == 0);
693 session->setDisableAutoTMMWhenCategoryChanged(m_ui->comboTorrentCategoryChanged->currentIndex() == 1);
694 session->setDisableAutoTMMWhenCategorySavePathChanged(m_ui->comboCategoryChanged->currentIndex() == 1);
695 session->setDisableAutoTMMWhenDefaultSavePathChanged(m_ui->comboCategoryDefaultPathChanged->currentIndex() == 1);
697 session->setSubcategoriesEnabled(m_ui->checkUseSubcategories->isChecked());
698 session->setUseCategoryPathsInManualMode(m_ui->checkUseCategoryPaths->isChecked());
700 session->setSavePath(Path(m_ui->textSavePath->selectedPath()));
701 session->setDownloadPathEnabled(m_ui->checkUseDownloadPath->isChecked());
702 session->setDownloadPath(m_ui->textDownloadPath->selectedPath());
703 session->setTorrentExportDirectory(getTorrentExportDir());
704 session->setFinishedTorrentExportDirectory(getFinishedTorrentExportDir());
706 auto *watchedFoldersModel = static_cast<WatchedFoldersModel *>(m_ui->scanFoldersView->model());
707 watchedFoldersModel->apply();
709 session->setExcludedFileNamesEnabled(m_ui->groupExcludedFileNames->isChecked());
710 session->setExcludedFileNames(m_ui->textExcludedFileNames->toPlainText().split(u'\n', Qt::SkipEmptyParts));
712 pref->setMailNotificationEnabled(m_ui->groupMailNotification->isChecked());
713 pref->setMailNotificationSender(m_ui->senderEmailTxt->text());
714 pref->setMailNotificationEmail(m_ui->lineEditDestEmail->text());
715 pref->setMailNotificationSMTP(m_ui->lineEditSmtpServer->text());
716 pref->setMailNotificationSMTPSSL(m_ui->checkSmtpSSL->isChecked());
717 pref->setMailNotificationSMTPAuth(m_ui->groupMailNotifAuth->isChecked());
718 pref->setMailNotificationSMTPUsername(m_ui->mailNotifUsername->text());
719 pref->setMailNotificationSMTPPassword(m_ui->mailNotifPassword->text());
721 pref->setAutoRunOnTorrentAddedEnabled(m_ui->groupBoxRunOnAdded->isChecked());
722 pref->setAutoRunOnTorrentAddedProgram(m_ui->lineEditRunOnAdded->text().trimmed());
723 pref->setAutoRunOnTorrentFinishedEnabled(m_ui->groupBoxRunOnFinished->isChecked());
724 pref->setAutoRunOnTorrentFinishedProgram(m_ui->lineEditRunOnFinished->text().trimmed());
725 #if defined(Q_OS_WIN)
726 pref->setAutoRunConsoleEnabled(m_ui->autoRunConsole->isChecked());
727 #endif
730 void OptionsDialog::loadConnectionTabOptions()
732 const auto *session = BitTorrent::Session::instance();
734 m_ui->comboProtocol->setCurrentIndex(static_cast<int>(session->btProtocol()));
735 m_ui->spinPort->setValue(session->port());
736 m_ui->checkUPnP->setChecked(Net::PortForwarder::instance()->isEnabled());
738 int intValue = session->maxConnections();
739 if (intValue > 0)
741 // enable
742 m_ui->checkMaxConnections->setChecked(true);
743 m_ui->spinMaxConnec->setEnabled(true);
744 m_ui->spinMaxConnec->setValue(intValue);
746 else
748 // disable
749 m_ui->checkMaxConnections->setChecked(false);
750 m_ui->spinMaxConnec->setEnabled(false);
752 intValue = session->maxConnectionsPerTorrent();
753 if (intValue > 0)
755 // enable
756 m_ui->checkMaxConnectionsPerTorrent->setChecked(true);
757 m_ui->spinMaxConnecPerTorrent->setEnabled(true);
758 m_ui->spinMaxConnecPerTorrent->setValue(intValue);
760 else
762 // disable
763 m_ui->checkMaxConnectionsPerTorrent->setChecked(false);
764 m_ui->spinMaxConnecPerTorrent->setEnabled(false);
766 intValue = session->maxUploads();
767 if (intValue > 0)
769 // enable
770 m_ui->checkMaxUploads->setChecked(true);
771 m_ui->spinMaxUploads->setEnabled(true);
772 m_ui->spinMaxUploads->setValue(intValue);
774 else
776 // disable
777 m_ui->checkMaxUploads->setChecked(false);
778 m_ui->spinMaxUploads->setEnabled(false);
780 intValue = session->maxUploadsPerTorrent();
781 if (intValue > 0)
783 // enable
784 m_ui->checkMaxUploadsPerTorrent->setChecked(true);
785 m_ui->spinMaxUploadsPerTorrent->setEnabled(true);
786 m_ui->spinMaxUploadsPerTorrent->setValue(intValue);
788 else
790 // disable
791 m_ui->checkMaxUploadsPerTorrent->setChecked(false);
792 m_ui->spinMaxUploadsPerTorrent->setEnabled(false);
795 #if defined(QBT_USES_LIBTORRENT2) && TORRENT_USE_I2P
796 m_ui->textI2PHost->setText(session->I2PAddress());
797 m_ui->spinI2PPort->setValue(session->I2PPort());
798 m_ui->checkI2PMixed->setChecked(session->I2PMixedMode());
799 m_ui->groupI2P->setChecked(session->isI2PEnabled());
800 #else
801 m_ui->groupI2P->hide();
802 #endif
804 const auto *proxyConfigManager = Net::ProxyConfigurationManager::instance();
805 const Net::ProxyConfiguration proxyConf = proxyConfigManager->proxyConfiguration();
807 m_ui->comboProxyType->addItem(tr("(None)"), QVariant::fromValue(Net::ProxyType::None));
808 m_ui->comboProxyType->addItem(tr("SOCKS4"), QVariant::fromValue(Net::ProxyType::SOCKS4));
809 m_ui->comboProxyType->addItem(tr("SOCKS5"), QVariant::fromValue(Net::ProxyType::SOCKS5));
810 m_ui->comboProxyType->addItem(tr("HTTP"), QVariant::fromValue(Net::ProxyType::HTTP));
811 m_ui->comboProxyType->setCurrentIndex(m_ui->comboProxyType->findData(QVariant::fromValue(proxyConf.type)));
812 adjustProxyOptions();
814 m_ui->textProxyIP->setText(proxyConf.ip);
815 m_ui->spinProxyPort->setValue(proxyConf.port);
816 m_ui->textProxyUsername->setText(proxyConf.username);
817 m_ui->textProxyPassword->setText(proxyConf.password);
818 m_ui->checkProxyAuth->setChecked(proxyConf.authEnabled);
819 m_ui->checkProxyHostnameLookup->setChecked(proxyConf.hostnameLookupEnabled);
821 m_ui->checkProxyPeerConnections->setChecked(session->isProxyPeerConnectionsEnabled());
822 m_ui->checkProxyBitTorrent->setChecked(Preferences::instance()->useProxyForBT());
823 m_ui->checkProxyRSS->setChecked(Preferences::instance()->useProxyForRSS());
824 m_ui->checkProxyMisc->setChecked(Preferences::instance()->useProxyForGeneralPurposes());
826 m_ui->checkIPFilter->setChecked(session->isIPFilteringEnabled());
827 m_ui->textFilterPath->setDialogCaption(tr("Choose an IP filter file"));
828 m_ui->textFilterPath->setEnabled(m_ui->checkIPFilter->isChecked());
829 m_ui->textFilterPath->setFileNameFilter(tr("All supported filters") + u" (*.dat *.p2p *.p2b);;.dat (*.dat);;.p2p (*.p2p);;.p2b (*.p2b)");
830 m_ui->textFilterPath->setSelectedPath(session->IPFilterFile());
832 m_ui->IpFilterRefreshBtn->setIcon(UIThemeManager::instance()->getIcon(u"view-refresh"_s));
833 m_ui->IpFilterRefreshBtn->setEnabled(m_ui->checkIPFilter->isChecked());
834 m_ui->checkIpFilterTrackers->setChecked(session->isTrackerFilteringEnabled());
836 connect(m_ui->comboProtocol, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
837 connect(m_ui->spinPort, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
838 connect(m_ui->checkUPnP, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
840 connect(m_ui->checkMaxConnections, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
841 connect(m_ui->checkMaxConnectionsPerTorrent, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
842 connect(m_ui->checkMaxUploads, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
843 connect(m_ui->checkMaxUploadsPerTorrent, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
844 connect(m_ui->spinMaxConnec, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
845 connect(m_ui->spinMaxConnecPerTorrent, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
846 connect(m_ui->spinMaxUploads, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
847 connect(m_ui->spinMaxUploadsPerTorrent, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
849 connect(m_ui->comboProxyType, qComboBoxCurrentIndexChanged, this, &ThisType::adjustProxyOptions);
850 connect(m_ui->comboProxyType, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
851 connect(m_ui->textProxyIP, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
852 connect(m_ui->spinProxyPort, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
854 #if defined(QBT_USES_LIBTORRENT2) && TORRENT_USE_I2P
855 connect(m_ui->textI2PHost, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
856 connect(m_ui->spinI2PPort, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
857 connect(m_ui->checkI2PMixed, &QCheckBox::toggled, this, &ThisType::enableApplyButton);
858 connect(m_ui->groupI2P, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
859 #endif
861 connect(m_ui->checkProxyBitTorrent, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
862 connect(m_ui->checkProxyBitTorrent, &QGroupBox::toggled, this, &ThisType::adjustProxyOptions);
863 connect(m_ui->checkProxyPeerConnections, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
864 connect(m_ui->checkProxyHostnameLookup, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
865 connect(m_ui->checkProxyRSS, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
866 connect(m_ui->checkProxyMisc, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
868 connect(m_ui->checkProxyAuth, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
869 connect(m_ui->textProxyUsername, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
870 connect(m_ui->textProxyPassword, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
872 connect(m_ui->checkIPFilter, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
873 connect(m_ui->checkIPFilter, &QAbstractButton::toggled, m_ui->textFilterPath, &QWidget::setEnabled);
874 connect(m_ui->checkIPFilter, &QAbstractButton::toggled, m_ui->IpFilterRefreshBtn, &QWidget::setEnabled);
875 connect(m_ui->textFilterPath, &FileSystemPathEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
876 connect(m_ui->checkIpFilterTrackers, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
879 void OptionsDialog::saveConnectionTabOptions() const
881 auto *session = BitTorrent::Session::instance();
883 session->setBTProtocol(static_cast<BitTorrent::BTProtocol>(m_ui->comboProtocol->currentIndex()));
884 session->setPort(getPort());
885 Net::PortForwarder::instance()->setEnabled(isUPnPEnabled());
887 session->setMaxConnections(getMaxConnections());
888 session->setMaxConnectionsPerTorrent(getMaxConnectionsPerTorrent());
889 session->setMaxUploads(getMaxUploads());
890 session->setMaxUploadsPerTorrent(getMaxUploadsPerTorrent());
892 #if defined(QBT_USES_LIBTORRENT2) && TORRENT_USE_I2P
893 session->setI2PEnabled(m_ui->groupI2P->isChecked());
894 session->setI2PAddress(m_ui->textI2PHost->text().trimmed());
895 session->setI2PPort(m_ui->spinI2PPort->value());
896 session->setI2PMixedMode(m_ui->checkI2PMixed->isChecked());
897 #endif
899 auto *proxyConfigManager = Net::ProxyConfigurationManager::instance();
900 Net::ProxyConfiguration proxyConf;
901 proxyConf.type = getProxyType();
902 proxyConf.ip = getProxyIp();
903 proxyConf.port = getProxyPort();
904 proxyConf.authEnabled = m_ui->checkProxyAuth->isChecked();
905 proxyConf.username = getProxyUsername();
906 proxyConf.password = getProxyPassword();
907 proxyConf.hostnameLookupEnabled = m_ui->checkProxyHostnameLookup->isChecked();
908 proxyConfigManager->setProxyConfiguration(proxyConf);
910 Preferences::instance()->setUseProxyForBT(m_ui->checkProxyBitTorrent->isChecked());
911 Preferences::instance()->setUseProxyForRSS(m_ui->checkProxyRSS->isChecked());
912 Preferences::instance()->setUseProxyForGeneralPurposes(m_ui->checkProxyMisc->isChecked());
914 session->setProxyPeerConnectionsEnabled(m_ui->checkProxyPeerConnections->isChecked());
916 // IPFilter
917 session->setIPFilteringEnabled(isIPFilteringEnabled());
918 session->setTrackerFilteringEnabled(m_ui->checkIpFilterTrackers->isChecked());
919 session->setIPFilterFile(m_ui->textFilterPath->selectedPath());
922 void OptionsDialog::loadSpeedTabOptions()
924 const auto *pref = Preferences::instance();
925 const auto *session = BitTorrent::Session::instance();
927 m_ui->labelGlobalRate->setPixmap(UIThemeManager::instance()->getScaledPixmap(u"slow_off"_s, Utils::Gui::mediumIconSize(this).height()));
928 m_ui->spinUploadLimit->setValue(session->globalUploadSpeedLimit() / 1024);
929 m_ui->spinDownloadLimit->setValue(session->globalDownloadSpeedLimit() / 1024);
931 m_ui->labelAltRate->setPixmap(UIThemeManager::instance()->getScaledPixmap(u"slow"_s, Utils::Gui::mediumIconSize(this).height()));
932 m_ui->spinUploadLimitAlt->setValue(session->altGlobalUploadSpeedLimit() / 1024);
933 m_ui->spinDownloadLimitAlt->setValue(session->altGlobalDownloadSpeedLimit() / 1024);
935 m_ui->comboBoxScheduleDays->addItems(translatedWeekdayNames());
937 m_ui->groupBoxSchedule->setChecked(session->isBandwidthSchedulerEnabled());
938 m_ui->timeEditScheduleFrom->setTime(pref->getSchedulerStartTime());
939 m_ui->timeEditScheduleTo->setTime(pref->getSchedulerEndTime());
940 m_ui->comboBoxScheduleDays->setCurrentIndex(static_cast<int>(pref->getSchedulerDays()));
942 m_ui->checkLimituTPConnections->setChecked(session->isUTPRateLimited());
943 m_ui->checkLimitTransportOverhead->setChecked(session->includeOverheadInLimits());
944 m_ui->checkLimitLocalPeerRate->setChecked(!session->ignoreLimitsOnLAN());
946 connect(m_ui->spinUploadLimit, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
947 connect(m_ui->spinDownloadLimit, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
949 connect(m_ui->spinUploadLimitAlt, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
950 connect(m_ui->spinDownloadLimitAlt, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
952 connect(m_ui->groupBoxSchedule, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
953 connect(m_ui->timeEditScheduleFrom, &QDateTimeEdit::timeChanged, this, &ThisType::enableApplyButton);
954 connect(m_ui->timeEditScheduleTo, &QDateTimeEdit::timeChanged, this, &ThisType::enableApplyButton);
955 connect(m_ui->comboBoxScheduleDays, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
957 connect(m_ui->checkLimituTPConnections, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
958 connect(m_ui->checkLimitTransportOverhead, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
959 connect(m_ui->checkLimitLocalPeerRate, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
962 void OptionsDialog::saveSpeedTabOptions() const
964 auto *pref = Preferences::instance();
965 auto *session = BitTorrent::Session::instance();
967 session->setGlobalUploadSpeedLimit(m_ui->spinUploadLimit->value() * 1024);
968 session->setGlobalDownloadSpeedLimit(m_ui->spinDownloadLimit->value() * 1024);
970 session->setAltGlobalUploadSpeedLimit(m_ui->spinUploadLimitAlt->value() * 1024);
971 session->setAltGlobalDownloadSpeedLimit(m_ui->spinDownloadLimitAlt->value() * 1024);
973 session->setBandwidthSchedulerEnabled(m_ui->groupBoxSchedule->isChecked());
974 pref->setSchedulerStartTime(m_ui->timeEditScheduleFrom->time());
975 pref->setSchedulerEndTime(m_ui->timeEditScheduleTo->time());
976 pref->setSchedulerDays(static_cast<Scheduler::Days>(m_ui->comboBoxScheduleDays->currentIndex()));
978 session->setUTPRateLimited(m_ui->checkLimituTPConnections->isChecked());
979 session->setIncludeOverheadInLimits(m_ui->checkLimitTransportOverhead->isChecked());
980 session->setIgnoreLimitsOnLAN(!m_ui->checkLimitLocalPeerRate->isChecked());
983 void OptionsDialog::loadBittorrentTabOptions()
985 const auto *session = BitTorrent::Session::instance();
987 m_ui->checkDHT->setChecked(session->isDHTEnabled());
988 m_ui->checkPeX->setChecked(session->isPeXEnabled());
989 m_ui->checkLSD->setChecked(session->isLSDEnabled());
990 m_ui->comboEncryption->setCurrentIndex(session->encryption());
991 m_ui->checkAnonymousMode->setChecked(session->isAnonymousModeEnabled());
993 m_ui->spinBoxMaxActiveCheckingTorrents->setValue(session->maxActiveCheckingTorrents());
995 m_ui->checkEnableQueueing->setChecked(session->isQueueingSystemEnabled());
996 m_ui->spinMaxActiveDownloads->setValue(session->maxActiveDownloads());
997 m_ui->spinMaxActiveUploads->setValue(session->maxActiveUploads());
998 m_ui->spinMaxActiveTorrents->setValue(session->maxActiveTorrents());
1000 m_ui->checkIgnoreSlowTorrentsForQueueing->setChecked(session->ignoreSlowTorrentsForQueueing());
1001 const QString slowTorrentsExplanation = u"<html><body><p>"
1002 + tr("A torrent will be considered slow if its download and upload rates stay below these values for \"Torrent inactivity timer\" seconds")
1003 + u"</p></body></html>";
1004 m_ui->labelDownloadRateForSlowTorrents->setToolTip(slowTorrentsExplanation);
1005 m_ui->labelUploadRateForSlowTorrents->setToolTip(slowTorrentsExplanation);
1006 m_ui->labelSlowTorrentInactivityTimer->setToolTip(slowTorrentsExplanation);
1007 m_ui->spinDownloadRateForSlowTorrents->setValue(session->downloadRateForSlowTorrents());
1008 m_ui->spinUploadRateForSlowTorrents->setValue(session->uploadRateForSlowTorrents());
1009 m_ui->spinSlowTorrentsInactivityTimer->setValue(session->slowTorrentsInactivityTimer());
1011 if (session->globalMaxRatio() >= 0.)
1013 // Enable
1014 m_ui->checkMaxRatio->setChecked(true);
1015 m_ui->spinMaxRatio->setEnabled(true);
1016 m_ui->comboRatioLimitAct->setEnabled(true);
1017 m_ui->spinMaxRatio->setValue(session->globalMaxRatio());
1019 else
1021 // Disable
1022 m_ui->checkMaxRatio->setChecked(false);
1023 m_ui->spinMaxRatio->setEnabled(false);
1025 if (session->globalMaxSeedingMinutes() >= 0)
1027 // Enable
1028 m_ui->checkMaxSeedingMinutes->setChecked(true);
1029 m_ui->spinMaxSeedingMinutes->setEnabled(true);
1030 m_ui->spinMaxSeedingMinutes->setValue(session->globalMaxSeedingMinutes());
1032 else
1034 // Disable
1035 m_ui->checkMaxSeedingMinutes->setChecked(false);
1036 m_ui->spinMaxSeedingMinutes->setEnabled(false);
1038 m_ui->comboRatioLimitAct->setEnabled((session->globalMaxSeedingMinutes() >= 0) || (session->globalMaxRatio() >= 0.));
1040 const QHash<MaxRatioAction, int> actIndex =
1042 {Pause, 0},
1043 {Remove, 1},
1044 {DeleteFiles, 2},
1045 {EnableSuperSeeding, 3}
1047 m_ui->comboRatioLimitAct->setCurrentIndex(actIndex.value(session->maxRatioAction()));
1049 m_ui->checkEnableAddTrackers->setChecked(session->isAddTrackersEnabled());
1050 m_ui->textTrackers->setPlainText(session->additionalTrackers());
1052 connect(m_ui->checkDHT, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
1053 connect(m_ui->checkPeX, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
1054 connect(m_ui->checkLSD, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
1055 connect(m_ui->comboEncryption, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
1056 connect(m_ui->checkAnonymousMode, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
1058 connect(m_ui->spinBoxMaxActiveCheckingTorrents, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1060 connect(m_ui->checkEnableQueueing, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
1061 connect(m_ui->spinMaxActiveDownloads, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1062 connect(m_ui->spinMaxActiveUploads, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1063 connect(m_ui->spinMaxActiveTorrents, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1064 connect(m_ui->checkIgnoreSlowTorrentsForQueueing, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
1065 connect(m_ui->spinDownloadRateForSlowTorrents, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1066 connect(m_ui->spinUploadRateForSlowTorrents, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1067 connect(m_ui->spinSlowTorrentsInactivityTimer, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1069 connect(m_ui->checkMaxRatio, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
1070 connect(m_ui->checkMaxRatio, &QAbstractButton::toggled, this, &ThisType::toggleComboRatioLimitAct);
1071 connect(m_ui->spinMaxRatio, qOverload<double>(&QDoubleSpinBox::valueChanged),this, &ThisType::enableApplyButton);
1072 connect(m_ui->comboRatioLimitAct, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
1073 connect(m_ui->checkMaxSeedingMinutes, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
1074 connect(m_ui->checkMaxSeedingMinutes, &QAbstractButton::toggled, this, &ThisType::toggleComboRatioLimitAct);
1075 connect(m_ui->spinMaxSeedingMinutes, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1077 connect(m_ui->checkEnableAddTrackers, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
1078 connect(m_ui->textTrackers, &QPlainTextEdit::textChanged, this, &ThisType::enableApplyButton);
1081 void OptionsDialog::saveBittorrentTabOptions() const
1083 auto *session = BitTorrent::Session::instance();
1085 session->setDHTEnabled(isDHTEnabled());
1086 session->setPeXEnabled(m_ui->checkPeX->isChecked());
1087 session->setLSDEnabled(isLSDEnabled());
1088 session->setEncryption(getEncryptionSetting());
1089 session->setAnonymousModeEnabled(m_ui->checkAnonymousMode->isChecked());
1091 session->setMaxActiveCheckingTorrents(m_ui->spinBoxMaxActiveCheckingTorrents->value());
1092 // Queueing system
1093 session->setQueueingSystemEnabled(isQueueingSystemEnabled());
1094 session->setMaxActiveDownloads(m_ui->spinMaxActiveDownloads->value());
1095 session->setMaxActiveUploads(m_ui->spinMaxActiveUploads->value());
1096 session->setMaxActiveTorrents(m_ui->spinMaxActiveTorrents->value());
1097 session->setIgnoreSlowTorrentsForQueueing(m_ui->checkIgnoreSlowTorrentsForQueueing->isChecked());
1098 session->setDownloadRateForSlowTorrents(m_ui->spinDownloadRateForSlowTorrents->value());
1099 session->setUploadRateForSlowTorrents(m_ui->spinUploadRateForSlowTorrents->value());
1100 session->setSlowTorrentsInactivityTimer(m_ui->spinSlowTorrentsInactivityTimer->value());
1102 session->setGlobalMaxRatio(getMaxRatio());
1103 session->setGlobalMaxSeedingMinutes(getMaxSeedingMinutes());
1104 const QVector<MaxRatioAction> actIndex =
1106 Pause,
1107 Remove,
1108 DeleteFiles,
1109 EnableSuperSeeding
1111 session->setMaxRatioAction(actIndex.value(m_ui->comboRatioLimitAct->currentIndex()));
1113 session->setAddTrackersEnabled(m_ui->checkEnableAddTrackers->isChecked());
1114 session->setAdditionalTrackers(m_ui->textTrackers->toPlainText());
1117 void OptionsDialog::loadRSSTabOptions()
1119 const auto *rssSession = RSS::Session::instance();
1120 const auto *autoDownloader = RSS::AutoDownloader::instance();
1122 m_ui->checkRSSEnable->setChecked(rssSession->isProcessingEnabled());
1123 m_ui->spinRSSRefreshInterval->setValue(rssSession->refreshInterval());
1124 m_ui->spinRSSMaxArticlesPerFeed->setValue(rssSession->maxArticlesPerFeed());
1125 m_ui->checkRSSAutoDownloaderEnable->setChecked(autoDownloader->isProcessingEnabled());
1126 m_ui->textSmartEpisodeFilters->setPlainText(autoDownloader->smartEpisodeFilters().join(u'\n'));
1127 m_ui->checkSmartFilterDownloadRepacks->setChecked(autoDownloader->downloadRepacks());
1129 connect(m_ui->checkRSSEnable, &QCheckBox::toggled, this, &OptionsDialog::enableApplyButton);
1130 connect(m_ui->checkRSSAutoDownloaderEnable, &QCheckBox::toggled, this, &OptionsDialog::enableApplyButton);
1131 connect(m_ui->btnEditRules, &QPushButton::clicked, this, [this]()
1133 auto *downloader = new AutomatedRssDownloader(this);
1134 downloader->setAttribute(Qt::WA_DeleteOnClose);
1135 downloader->open();
1137 connect(m_ui->textSmartEpisodeFilters, &QPlainTextEdit::textChanged, this, &OptionsDialog::enableApplyButton);
1138 connect(m_ui->checkSmartFilterDownloadRepacks, &QCheckBox::toggled, this, &OptionsDialog::enableApplyButton);
1139 connect(m_ui->spinRSSRefreshInterval, qSpinBoxValueChanged, this, &OptionsDialog::enableApplyButton);
1140 connect(m_ui->spinRSSMaxArticlesPerFeed, qSpinBoxValueChanged, this, &OptionsDialog::enableApplyButton);
1143 void OptionsDialog::saveRSSTabOptions() const
1145 auto *rssSession = RSS::Session::instance();
1146 auto *autoDownloader = RSS::AutoDownloader::instance();
1148 rssSession->setProcessingEnabled(m_ui->checkRSSEnable->isChecked());
1149 rssSession->setRefreshInterval(m_ui->spinRSSRefreshInterval->value());
1150 rssSession->setMaxArticlesPerFeed(m_ui->spinRSSMaxArticlesPerFeed->value());
1151 autoDownloader->setProcessingEnabled(m_ui->checkRSSAutoDownloaderEnable->isChecked());
1152 autoDownloader->setSmartEpisodeFilters(m_ui->textSmartEpisodeFilters->toPlainText().split(u'\n', Qt::SkipEmptyParts));
1153 autoDownloader->setDownloadRepacks(m_ui->checkSmartFilterDownloadRepacks->isChecked());
1156 #ifndef DISABLE_WEBUI
1157 void OptionsDialog::loadWebUITabOptions()
1159 const auto *pref = Preferences::instance();
1161 m_ui->textWebUIHttpsCert->setMode(FileSystemPathEdit::Mode::FileOpen);
1162 m_ui->textWebUIHttpsCert->setFileNameFilter(tr("Certificate") + u" (*.cer *.crt *.pem)");
1163 m_ui->textWebUIHttpsCert->setDialogCaption(tr("Select certificate"));
1164 m_ui->textWebUIHttpsKey->setMode(FileSystemPathEdit::Mode::FileOpen);
1165 m_ui->textWebUIHttpsKey->setFileNameFilter(tr("Private key") + u" (*.key *.pem)");
1166 m_ui->textWebUIHttpsKey->setDialogCaption(tr("Select private key"));
1167 m_ui->textWebUIRootFolder->setMode(FileSystemPathEdit::Mode::DirectoryOpen);
1168 m_ui->textWebUIRootFolder->setDialogCaption(tr("Choose Alternative UI files location"));
1170 m_ui->checkWebUi->setChecked(pref->isWebUiEnabled());
1171 m_ui->textWebUiAddress->setText(pref->getWebUiAddress());
1172 m_ui->spinWebUiPort->setValue(pref->getWebUiPort());
1173 m_ui->checkWebUIUPnP->setChecked(pref->useUPnPForWebUIPort());
1174 m_ui->checkWebUiHttps->setChecked(pref->isWebUiHttpsEnabled());
1175 webUIHttpsCertChanged(pref->getWebUIHttpsCertificatePath());
1176 webUIHttpsKeyChanged(pref->getWebUIHttpsKeyPath());
1177 m_ui->textWebUiUsername->setText(pref->getWebUiUsername());
1178 m_ui->checkBypassLocalAuth->setChecked(!pref->isWebUiLocalAuthEnabled());
1179 m_ui->checkBypassAuthSubnetWhitelist->setChecked(pref->isWebUiAuthSubnetWhitelistEnabled());
1180 m_ui->IPSubnetWhitelistButton->setEnabled(m_ui->checkBypassAuthSubnetWhitelist->isChecked());
1181 m_ui->spinBanCounter->setValue(pref->getWebUIMaxAuthFailCount());
1182 m_ui->spinBanDuration->setValue(pref->getWebUIBanDuration().count());
1183 m_ui->spinSessionTimeout->setValue(pref->getWebUISessionTimeout());
1184 // Alternative UI
1185 m_ui->groupAltWebUI->setChecked(pref->isAltWebUiEnabled());
1186 m_ui->textWebUIRootFolder->setSelectedPath(pref->getWebUiRootFolder());
1187 // Security
1188 m_ui->checkClickjacking->setChecked(pref->isWebUiClickjackingProtectionEnabled());
1189 m_ui->checkCSRFProtection->setChecked(pref->isWebUiCSRFProtectionEnabled());
1190 m_ui->checkSecureCookie->setEnabled(pref->isWebUiHttpsEnabled());
1191 m_ui->checkSecureCookie->setChecked(pref->isWebUiSecureCookieEnabled());
1192 m_ui->groupHostHeaderValidation->setChecked(pref->isWebUIHostHeaderValidationEnabled());
1193 m_ui->textServerDomains->setText(pref->getServerDomains());
1194 // Custom HTTP headers
1195 m_ui->groupWebUIAddCustomHTTPHeaders->setChecked(pref->isWebUICustomHTTPHeadersEnabled());
1196 m_ui->textWebUICustomHTTPHeaders->setPlainText(pref->getWebUICustomHTTPHeaders());
1197 // Reverse proxy
1198 m_ui->groupEnableReverseProxySupport->setChecked(pref->isWebUIReverseProxySupportEnabled());
1199 m_ui->textTrustedReverseProxiesList->setText(pref->getWebUITrustedReverseProxiesList());
1200 // DynDNS
1201 m_ui->checkDynDNS->setChecked(pref->isDynDNSEnabled());
1202 m_ui->comboDNSService->setCurrentIndex(static_cast<int>(pref->getDynDNSService()));
1203 m_ui->domainNameTxt->setText(pref->getDynDomainName());
1204 m_ui->DNSUsernameTxt->setText(pref->getDynDNSUsername());
1205 m_ui->DNSPasswordTxt->setText(pref->getDynDNSPassword());
1207 connect(m_ui->checkWebUi, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
1208 connect(m_ui->textWebUiAddress, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
1209 connect(m_ui->spinWebUiPort, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1210 connect(m_ui->checkWebUIUPnP, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
1211 connect(m_ui->checkWebUiHttps, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
1212 connect(m_ui->textWebUIHttpsCert, &FileSystemPathLineEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
1213 connect(m_ui->textWebUIHttpsCert, &FileSystemPathLineEdit::selectedPathChanged, this, &OptionsDialog::webUIHttpsCertChanged);
1214 connect(m_ui->textWebUIHttpsKey, &FileSystemPathLineEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
1215 connect(m_ui->textWebUIHttpsKey, &FileSystemPathLineEdit::selectedPathChanged, this, &OptionsDialog::webUIHttpsKeyChanged);
1217 connect(m_ui->textWebUiUsername, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
1218 connect(m_ui->textWebUiPassword, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
1220 connect(m_ui->checkBypassLocalAuth, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
1221 connect(m_ui->checkBypassAuthSubnetWhitelist, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
1222 connect(m_ui->checkBypassAuthSubnetWhitelist, &QAbstractButton::toggled, m_ui->IPSubnetWhitelistButton, &QPushButton::setEnabled);
1223 connect(m_ui->spinBanCounter, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1224 connect(m_ui->spinBanDuration, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1225 connect(m_ui->spinSessionTimeout, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
1227 connect(m_ui->groupAltWebUI, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
1228 connect(m_ui->textWebUIRootFolder, &FileSystemPathLineEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
1230 connect(m_ui->checkClickjacking, &QCheckBox::toggled, this, &ThisType::enableApplyButton);
1231 connect(m_ui->checkCSRFProtection, &QCheckBox::toggled, this, &ThisType::enableApplyButton);
1232 connect(m_ui->checkWebUiHttps, &QGroupBox::toggled, m_ui->checkSecureCookie, &QWidget::setEnabled);
1233 connect(m_ui->checkSecureCookie, &QCheckBox::toggled, this, &ThisType::enableApplyButton);
1234 connect(m_ui->groupHostHeaderValidation, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
1235 connect(m_ui->textServerDomains, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
1237 connect(m_ui->groupWebUIAddCustomHTTPHeaders, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
1238 connect(m_ui->textWebUICustomHTTPHeaders, &QPlainTextEdit::textChanged, this, &OptionsDialog::enableApplyButton);
1240 connect(m_ui->groupEnableReverseProxySupport, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
1241 connect(m_ui->textTrustedReverseProxiesList, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
1243 connect(m_ui->checkDynDNS, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
1244 connect(m_ui->comboDNSService, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
1245 connect(m_ui->domainNameTxt, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
1246 connect(m_ui->DNSUsernameTxt, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
1247 connect(m_ui->DNSPasswordTxt, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
1250 void OptionsDialog::saveWebUITabOptions() const
1252 auto *pref = Preferences::instance();
1254 pref->setWebUiEnabled(isWebUiEnabled());
1255 pref->setWebUiAddress(m_ui->textWebUiAddress->text());
1256 pref->setWebUiPort(m_ui->spinWebUiPort->value());
1257 pref->setUPnPForWebUIPort(m_ui->checkWebUIUPnP->isChecked());
1258 pref->setWebUiHttpsEnabled(m_ui->checkWebUiHttps->isChecked());
1259 pref->setWebUIHttpsCertificatePath(m_ui->textWebUIHttpsCert->selectedPath());
1260 pref->setWebUIHttpsKeyPath(m_ui->textWebUIHttpsKey->selectedPath());
1261 pref->setWebUIMaxAuthFailCount(m_ui->spinBanCounter->value());
1262 pref->setWebUIBanDuration(std::chrono::seconds {m_ui->spinBanDuration->value()});
1263 pref->setWebUISessionTimeout(m_ui->spinSessionTimeout->value());
1264 // Authentication
1265 pref->setWebUiUsername(webUiUsername());
1266 if (!webUiPassword().isEmpty())
1267 pref->setWebUIPassword(Utils::Password::PBKDF2::generate(webUiPassword()));
1268 pref->setWebUiLocalAuthEnabled(!m_ui->checkBypassLocalAuth->isChecked());
1269 pref->setWebUiAuthSubnetWhitelistEnabled(m_ui->checkBypassAuthSubnetWhitelist->isChecked());
1270 // Alternative UI
1271 pref->setAltWebUiEnabled(m_ui->groupAltWebUI->isChecked());
1272 pref->setWebUiRootFolder(m_ui->textWebUIRootFolder->selectedPath());
1273 // Security
1274 pref->setWebUiClickjackingProtectionEnabled(m_ui->checkClickjacking->isChecked());
1275 pref->setWebUiCSRFProtectionEnabled(m_ui->checkCSRFProtection->isChecked());
1276 pref->setWebUiSecureCookieEnabled(m_ui->checkSecureCookie->isChecked());
1277 pref->setWebUIHostHeaderValidationEnabled(m_ui->groupHostHeaderValidation->isChecked());
1278 pref->setServerDomains(m_ui->textServerDomains->text());
1279 // Custom HTTP headers
1280 pref->setWebUICustomHTTPHeadersEnabled(m_ui->groupWebUIAddCustomHTTPHeaders->isChecked());
1281 pref->setWebUICustomHTTPHeaders(m_ui->textWebUICustomHTTPHeaders->toPlainText());
1282 // Reverse proxy
1283 pref->setWebUIReverseProxySupportEnabled(m_ui->groupEnableReverseProxySupport->isChecked());
1284 pref->setWebUITrustedReverseProxiesList(m_ui->textTrustedReverseProxiesList->text());
1285 // DynDNS
1286 pref->setDynDNSEnabled(m_ui->checkDynDNS->isChecked());
1287 pref->setDynDNSService(static_cast<DNS::Service>(m_ui->comboDNSService->currentIndex()));
1288 pref->setDynDomainName(m_ui->domainNameTxt->text());
1289 pref->setDynDNSUsername(m_ui->DNSUsernameTxt->text());
1290 pref->setDynDNSPassword(m_ui->DNSPasswordTxt->text());
1292 #endif // DISABLE_WEBUI
1294 void OptionsDialog::initializeLanguageCombo()
1296 // List language files
1297 const QDir langDir(u":/lang"_s);
1298 const QStringList langFiles = langDir.entryList(QStringList(u"qbittorrent_*.qm"_s), QDir::Files);
1299 for (const QString &langFile : langFiles)
1301 const QString localeStr = langFile.section(u"_"_s, 1, -1).section(u"."_s, 0, 0); // remove "qbittorrent_" and ".qm"
1302 m_ui->comboI18n->addItem(/*QIcon(":/icons/flags/"+country+".svg"), */ Utils::Misc::languageToLocalizedString(localeStr), localeStr);
1303 qDebug() << "Supported locale:" << localeStr;
1307 void OptionsDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous)
1309 if (!current)
1310 current = previous;
1311 m_ui->tabOption->setCurrentIndex(m_ui->tabSelection->row(current));
1314 void OptionsDialog::loadSplitterState()
1316 // width has been modified, use height as width reference instead
1317 const int width = m_ui->tabSelection->item(TAB_UI)->sizeHint().height() * 2;
1318 const QStringList defaultSizes = {QString::number(width), QString::number(m_ui->hsplitter->width() - width)};
1320 QList<int> splitterSizes;
1321 for (const QString &string : asConst(m_storeHSplitterSize.get(defaultSizes)))
1322 splitterSizes.append(string.toInt());
1324 m_ui->hsplitter->setSizes(splitterSizes);
1327 void OptionsDialog::showEvent(QShowEvent *e)
1329 QDialog::showEvent(e);
1331 loadSplitterState();
1334 void OptionsDialog::saveOptions() const
1336 auto *pref = Preferences::instance();
1338 saveBehaviorTabOptions();
1339 saveDownloadsTabOptions();
1340 saveConnectionTabOptions();
1341 saveSpeedTabOptions();
1342 saveBittorrentTabOptions();
1343 saveRSSTabOptions();
1344 #ifndef DISABLE_WEBUI
1345 saveWebUITabOptions();
1346 #endif
1347 m_advancedSettings->saveAdvancedSettings();
1349 // Assume that user changed multiple settings
1350 // so it's best to save immediately
1351 pref->apply();
1354 bool OptionsDialog::isIPFilteringEnabled() const
1356 return m_ui->checkIPFilter->isChecked();
1359 Net::ProxyType OptionsDialog::getProxyType() const
1361 return m_ui->comboProxyType->currentData().value<Net::ProxyType>();
1364 int OptionsDialog::getPort() const
1366 return m_ui->spinPort->value();
1369 void OptionsDialog::on_randomButton_clicked()
1371 // Range [1024: 65535]
1372 m_ui->spinPort->setValue(Utils::Random::rand(1024, 65535));
1375 int OptionsDialog::getEncryptionSetting() const
1377 return m_ui->comboEncryption->currentIndex();
1380 int OptionsDialog::getMaxActiveDownloads() const
1382 return m_ui->spinMaxActiveDownloads->value();
1385 int OptionsDialog::getMaxActiveUploads() const
1387 return m_ui->spinMaxActiveUploads->value();
1390 int OptionsDialog::getMaxActiveTorrents() const
1392 return m_ui->spinMaxActiveTorrents->value();
1395 bool OptionsDialog::isQueueingSystemEnabled() const
1397 return m_ui->checkEnableQueueing->isChecked();
1400 bool OptionsDialog::isDHTEnabled() const
1402 return m_ui->checkDHT->isChecked();
1405 bool OptionsDialog::isLSDEnabled() const
1407 return m_ui->checkLSD->isChecked();
1410 bool OptionsDialog::isUPnPEnabled() const
1412 return m_ui->checkUPnP->isChecked();
1415 // Return Share ratio
1416 qreal OptionsDialog::getMaxRatio() const
1418 if (m_ui->checkMaxRatio->isChecked())
1419 return m_ui->spinMaxRatio->value();
1420 return -1;
1423 // Return Seeding Minutes
1424 int OptionsDialog::getMaxSeedingMinutes() const
1426 if (m_ui->checkMaxSeedingMinutes->isChecked())
1427 return m_ui->spinMaxSeedingMinutes->value();
1428 return -1;
1431 // Return max connections number
1432 int OptionsDialog::getMaxConnections() const
1434 if (!m_ui->checkMaxConnections->isChecked())
1435 return -1;
1437 return m_ui->spinMaxConnec->value();
1440 int OptionsDialog::getMaxConnectionsPerTorrent() const
1442 if (!m_ui->checkMaxConnectionsPerTorrent->isChecked())
1443 return -1;
1445 return m_ui->spinMaxConnecPerTorrent->value();
1448 int OptionsDialog::getMaxUploads() const
1450 if (!m_ui->checkMaxUploads->isChecked())
1451 return -1;
1453 return m_ui->spinMaxUploads->value();
1456 int OptionsDialog::getMaxUploadsPerTorrent() const
1458 if (!m_ui->checkMaxUploadsPerTorrent->isChecked())
1459 return -1;
1461 return m_ui->spinMaxUploadsPerTorrent->value();
1464 void OptionsDialog::on_buttonBox_accepted()
1466 if (m_applyButton->isEnabled())
1468 if (!schedTimesOk())
1470 m_ui->tabSelection->setCurrentRow(TAB_SPEED);
1471 return;
1473 #ifndef DISABLE_WEBUI
1474 if (!webUIAuthenticationOk())
1476 m_ui->tabSelection->setCurrentRow(TAB_WEBUI);
1477 return;
1479 if (!isAlternativeWebUIPathValid())
1481 m_ui->tabSelection->setCurrentRow(TAB_WEBUI);
1482 return;
1484 #endif
1486 m_applyButton->setEnabled(false);
1487 saveOptions();
1490 accept();
1493 void OptionsDialog::applySettings()
1495 if (!schedTimesOk())
1497 m_ui->tabSelection->setCurrentRow(TAB_SPEED);
1498 return;
1500 #ifndef DISABLE_WEBUI
1501 if (!webUIAuthenticationOk())
1503 m_ui->tabSelection->setCurrentRow(TAB_WEBUI);
1504 return;
1506 if (!isAlternativeWebUIPathValid())
1508 m_ui->tabSelection->setCurrentRow(TAB_WEBUI);
1509 return;
1511 #endif
1513 m_applyButton->setEnabled(false);
1514 saveOptions();
1517 void OptionsDialog::on_buttonBox_rejected()
1519 reject();
1522 bool OptionsDialog::useAdditionDialog() const
1524 return m_ui->checkAdditionDialog->isChecked();
1527 void OptionsDialog::enableApplyButton()
1529 m_applyButton->setEnabled(true);
1532 void OptionsDialog::toggleComboRatioLimitAct()
1534 // Verify if the share action button must be enabled
1535 m_ui->comboRatioLimitAct->setEnabled(m_ui->checkMaxRatio->isChecked() || m_ui->checkMaxSeedingMinutes->isChecked());
1538 void OptionsDialog::adjustProxyOptions()
1540 const auto currentProxyType = m_ui->comboProxyType->currentData().value<Net::ProxyType>();
1541 const bool isAuthSupported = ((currentProxyType == Net::ProxyType::SOCKS5)
1542 || (currentProxyType == Net::ProxyType::HTTP));
1544 m_ui->checkProxyAuth->setEnabled(isAuthSupported);
1546 if (currentProxyType == Net::ProxyType::None)
1548 m_ui->labelProxyTypeIncompatible->setVisible(false);
1550 m_ui->lblProxyIP->setEnabled(false);
1551 m_ui->textProxyIP->setEnabled(false);
1552 m_ui->lblProxyPort->setEnabled(false);
1553 m_ui->spinProxyPort->setEnabled(false);
1555 m_ui->checkProxyHostnameLookup->setEnabled(false);
1556 m_ui->checkProxyRSS->setEnabled(false);
1557 m_ui->checkProxyMisc->setEnabled(false);
1558 m_ui->checkProxyBitTorrent->setEnabled(false);
1559 m_ui->checkProxyPeerConnections->setEnabled(false);
1561 else
1563 m_ui->lblProxyIP->setEnabled(true);
1564 m_ui->textProxyIP->setEnabled(true);
1565 m_ui->lblProxyPort->setEnabled(true);
1566 m_ui->spinProxyPort->setEnabled(true);
1568 m_ui->checkProxyBitTorrent->setEnabled(true);
1569 m_ui->checkProxyPeerConnections->setEnabled(true);
1571 if (currentProxyType == Net::ProxyType::SOCKS4)
1573 m_ui->labelProxyTypeIncompatible->setVisible(true);
1575 m_ui->checkProxyHostnameLookup->setEnabled(false);
1576 m_ui->checkProxyRSS->setEnabled(false);
1577 m_ui->checkProxyMisc->setEnabled(false);
1579 else
1581 // SOCKS5 or HTTP
1582 m_ui->labelProxyTypeIncompatible->setVisible(false);
1584 m_ui->checkProxyHostnameLookup->setEnabled(true);
1585 m_ui->checkProxyRSS->setEnabled(true);
1586 m_ui->checkProxyMisc->setEnabled(true);
1591 bool OptionsDialog::isSplashScreenDisabled() const
1593 return !m_ui->checkShowSplash->isChecked();
1596 #ifdef Q_OS_WIN
1597 bool OptionsDialog::WinStartup() const
1599 return m_ui->checkStartup->isChecked();
1601 #endif
1603 bool OptionsDialog::preAllocateAllFiles() const
1605 return m_ui->checkPreallocateAll->isChecked();
1608 bool OptionsDialog::addTorrentsInPause() const
1610 return m_ui->checkStartPaused->isChecked();
1613 // Proxy settings
1614 bool OptionsDialog::isProxyEnabled() const
1616 return m_ui->comboProxyType->currentIndex();
1619 QString OptionsDialog::getProxyIp() const
1621 return m_ui->textProxyIP->text().trimmed();
1624 unsigned short OptionsDialog::getProxyPort() const
1626 return m_ui->spinProxyPort->value();
1629 QString OptionsDialog::getProxyUsername() const
1631 QString username = m_ui->textProxyUsername->text().trimmed();
1632 return username;
1635 QString OptionsDialog::getProxyPassword() const
1637 QString password = m_ui->textProxyPassword->text();
1638 password = password.trimmed();
1639 return password;
1642 // Locale Settings
1643 QString OptionsDialog::getLocale() const
1645 return m_ui->comboI18n->itemData(m_ui->comboI18n->currentIndex(), Qt::UserRole).toString();
1648 void OptionsDialog::setLocale(const QString &localeStr)
1650 QString name;
1651 if (localeStr.startsWith(u"eo", Qt::CaseInsensitive))
1653 name = u"eo"_s;
1655 else if (localeStr.startsWith(u"ltg", Qt::CaseInsensitive))
1657 name = u"ltg"_s;
1659 else
1661 QLocale locale(localeStr);
1662 if (locale.language() == QLocale::Uzbek)
1663 name = u"uz@Latn"_s;
1664 else if (locale.language() == QLocale::Azerbaijani)
1665 name = u"az@latin"_s;
1666 else
1667 name = locale.name();
1669 // Attempt to find exact match
1670 int index = m_ui->comboI18n->findData(name, Qt::UserRole);
1671 if (index < 0)
1673 //Attempt to find a language match without a country
1674 int pos = name.indexOf(u'_');
1675 if (pos > -1)
1677 QString lang = name.left(pos);
1678 index = m_ui->comboI18n->findData(lang, Qt::UserRole);
1681 if (index < 0)
1683 // Unrecognized, use US English
1684 index = m_ui->comboI18n->findData(u"en"_s, Qt::UserRole);
1685 Q_ASSERT(index >= 0);
1687 m_ui->comboI18n->setCurrentIndex(index);
1690 Path OptionsDialog::getTorrentExportDir() const
1692 if (m_ui->checkExportDir->isChecked())
1693 return m_ui->textExportDir->selectedPath();
1694 return {};
1697 Path OptionsDialog::getFinishedTorrentExportDir() const
1699 if (m_ui->checkExportDirFin->isChecked())
1700 return m_ui->textExportDirFin->selectedPath();
1701 return {};
1704 void OptionsDialog::on_addWatchedFolderButton_clicked()
1706 Preferences *const pref = Preferences::instance();
1707 const Path dir {QFileDialog::getExistingDirectory(
1708 this, tr("Select folder to monitor"), pref->getScanDirsLastPath().parentPath().toString())};
1709 if (dir.isEmpty())
1710 return;
1712 auto *dialog = new WatchedFolderOptionsDialog({}, this);
1713 dialog->setAttribute(Qt::WA_DeleteOnClose);
1714 connect(dialog, &QDialog::accepted, this, [this, dialog, dir, pref]()
1718 auto *watchedFoldersModel = static_cast<WatchedFoldersModel *>(m_ui->scanFoldersView->model());
1719 watchedFoldersModel->addFolder(dir, dialog->watchedFolderOptions());
1721 pref->setScanDirsLastPath(dir);
1723 for (int i = 0; i < watchedFoldersModel->columnCount(); ++i)
1724 m_ui->scanFoldersView->resizeColumnToContents(i);
1726 enableApplyButton();
1728 catch (const RuntimeError &err)
1730 QMessageBox::critical(this, tr("Adding entry failed"), err.message());
1734 dialog->open();
1737 void OptionsDialog::on_editWatchedFolderButton_clicked()
1739 const QModelIndex selected
1740 = m_ui->scanFoldersView->selectionModel()->selectedIndexes().at(0);
1742 editWatchedFolderOptions(selected);
1745 void OptionsDialog::on_removeWatchedFolderButton_clicked()
1747 const QModelIndexList selected
1748 = m_ui->scanFoldersView->selectionModel()->selectedIndexes();
1750 for (const QModelIndex &index : selected)
1751 m_ui->scanFoldersView->model()->removeRow(index.row());
1754 void OptionsDialog::handleWatchedFolderViewSelectionChanged()
1756 const QModelIndexList selectedIndexes = m_ui->scanFoldersView->selectionModel()->selectedIndexes();
1757 m_ui->removeWatchedFolderButton->setEnabled(!selectedIndexes.isEmpty());
1758 m_ui->editWatchedFolderButton->setEnabled(selectedIndexes.count() == 1);
1761 void OptionsDialog::editWatchedFolderOptions(const QModelIndex &index)
1763 if (!index.isValid())
1764 return;
1766 auto *watchedFoldersModel = static_cast<WatchedFoldersModel *>(m_ui->scanFoldersView->model());
1767 auto *dialog = new WatchedFolderOptionsDialog(watchedFoldersModel->folderOptions(index.row()), this);
1768 dialog->setAttribute(Qt::WA_DeleteOnClose);
1769 connect(dialog, &QDialog::accepted, this, [this, dialog, index, watchedFoldersModel]()
1771 if (index.isValid())
1773 // The index could be invalidated while the dialog was displayed,
1774 // for example, if you deleted the folder using the Web API.
1775 watchedFoldersModel->setFolderOptions(index.row(), dialog->watchedFolderOptions());
1776 enableApplyButton();
1780 dialog->open();
1783 // Return Filter object to apply to BT session
1784 Path OptionsDialog::getFilter() const
1786 return m_ui->textFilterPath->selectedPath();
1789 #ifndef DISABLE_WEBUI
1790 void OptionsDialog::webUIHttpsCertChanged(const Path &path)
1792 const auto readResult = Utils::IO::readFile(path, Utils::Net::MAX_SSL_FILE_SIZE);
1793 const bool isCertValid = Utils::Net::isSSLCertificatesValid(readResult.value_or(QByteArray()));
1795 m_ui->textWebUIHttpsCert->setSelectedPath(path);
1796 m_ui->lblSslCertStatus->setPixmap(UIThemeManager::instance()->getScaledPixmap(
1797 (isCertValid ? u"security-high"_s : u"security-low"_s), 24));
1800 void OptionsDialog::webUIHttpsKeyChanged(const Path &path)
1802 const auto readResult = Utils::IO::readFile(path, Utils::Net::MAX_SSL_FILE_SIZE);
1803 const bool isKeyValid = Utils::Net::isSSLKeyValid(readResult.value_or(QByteArray()));
1805 m_ui->textWebUIHttpsKey->setSelectedPath(path);
1806 m_ui->lblSslKeyStatus->setPixmap(UIThemeManager::instance()->getScaledPixmap(
1807 (isKeyValid ? u"security-high"_s : u"security-low"_s), 24));
1810 bool OptionsDialog::isWebUiEnabled() const
1812 return m_ui->checkWebUi->isChecked();
1815 QString OptionsDialog::webUiUsername() const
1817 return m_ui->textWebUiUsername->text();
1820 QString OptionsDialog::webUiPassword() const
1822 return m_ui->textWebUiPassword->text();
1825 bool OptionsDialog::webUIAuthenticationOk()
1827 if (webUiUsername().length() < 3)
1829 QMessageBox::warning(this, tr("Length Error"), tr("The Web UI username must be at least 3 characters long."));
1830 return false;
1832 if (!webUiPassword().isEmpty() && (webUiPassword().length() < 6))
1834 QMessageBox::warning(this, tr("Length Error"), tr("The Web UI password must be at least 6 characters long."));
1835 return false;
1837 return true;
1840 bool OptionsDialog::isAlternativeWebUIPathValid()
1842 if (m_ui->groupAltWebUI->isChecked() && m_ui->textWebUIRootFolder->selectedPath().isEmpty())
1844 QMessageBox::warning(this, tr("Location Error"), tr("The alternative Web UI files location cannot be blank."));
1845 return false;
1847 return true;
1849 #endif
1851 void OptionsDialog::showConnectionTab()
1853 m_ui->tabSelection->setCurrentRow(TAB_CONNECTION);
1856 #ifndef DISABLE_WEBUI
1857 void OptionsDialog::on_registerDNSBtn_clicked()
1859 const auto service = static_cast<DNS::Service>(m_ui->comboDNSService->currentIndex());
1860 QDesktopServices::openUrl(Net::DNSUpdater::getRegistrationUrl(service));
1862 #endif
1864 void OptionsDialog::on_IpFilterRefreshBtn_clicked()
1866 if (m_refreshingIpFilter) return;
1867 m_refreshingIpFilter = true;
1868 // Updating program preferences
1869 BitTorrent::Session *const session = BitTorrent::Session::instance();
1870 session->setIPFilteringEnabled(true);
1871 session->setIPFilterFile({}); // forcing Session reload filter file
1872 session->setIPFilterFile(getFilter());
1873 connect(session, &BitTorrent::Session::IPFilterParsed, this, &OptionsDialog::handleIPFilterParsed);
1874 setCursor(QCursor(Qt::WaitCursor));
1877 void OptionsDialog::handleIPFilterParsed(bool error, int ruleCount)
1879 setCursor(QCursor(Qt::ArrowCursor));
1880 if (error)
1881 QMessageBox::warning(this, tr("Parsing error"), tr("Failed to parse the provided IP filter"));
1882 else
1883 QMessageBox::information(this, tr("Successfully refreshed"), tr("Successfully parsed the provided IP filter: %1 rules were applied.", "%1 is a number").arg(ruleCount));
1884 m_refreshingIpFilter = false;
1885 disconnect(BitTorrent::Session::instance(), &BitTorrent::Session::IPFilterParsed, this, &OptionsDialog::handleIPFilterParsed);
1888 bool OptionsDialog::schedTimesOk()
1890 if (m_ui->timeEditScheduleFrom->time() == m_ui->timeEditScheduleTo->time())
1892 QMessageBox::warning(this, tr("Time Error"), tr("The start time and the end time can't be the same."));
1893 return false;
1895 return true;
1898 void OptionsDialog::on_banListButton_clicked()
1900 auto *dialog = new BanListOptionsDialog(this);
1901 dialog->setAttribute(Qt::WA_DeleteOnClose);
1902 connect(dialog, &QDialog::accepted, this, &OptionsDialog::enableApplyButton);
1903 dialog->open();
1906 void OptionsDialog::on_IPSubnetWhitelistButton_clicked()
1908 auto *dialog = new IPSubnetWhitelistOptionsDialog(this);
1909 dialog->setAttribute(Qt::WA_DeleteOnClose);
1910 connect(dialog, &QDialog::accepted, this, &OptionsDialog::enableApplyButton);
1911 dialog->open();