2 * Bittorrent Client using Qt and libtorrent.
3 * Copyright (C) 2023-2024 Vladimir Golovnev <glassez@yandex.ru>
4 * Copyright (C) 2024 Jonathan Ketchker
5 * Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 * In addition, as a special exception, the copyright holders give permission to
22 * link this program with the OpenSSL project's "OpenSSL" library (or with
23 * modified versions of it that use the same license as the "OpenSSL" library),
24 * and distribute the linked executables. You must obey the GNU General Public
25 * License in all respects for all of the code used other than "OpenSSL". If you
26 * modify file(s), you may extend this exception to your version of the file(s),
27 * but you are not obligated to do so. If you do not wish to do so, delete this
28 * exception statement from your version.
31 #include "optionsdialog.h"
38 #include <QApplication>
40 #include <QDesktopServices>
41 #include <QDialogButtonBox>
43 #include <QFileDialog>
44 #include <QMessageBox>
45 #include <QSystemTrayIcon>
46 #include <QTranslator>
49 #include <QStyleFactory>
52 #include "base/bittorrent/session.h"
53 #include "base/bittorrent/sharelimitaction.h"
54 #include "base/exceptions.h"
55 #include "base/global.h"
56 #include "base/net/portforwarder.h"
57 #include "base/net/proxyconfigurationmanager.h"
58 #include "base/path.h"
59 #include "base/preferences.h"
60 #include "base/rss/rss_autodownloader.h"
61 #include "base/rss/rss_session.h"
62 #include "base/torrentfileguard.h"
63 #include "base/torrentfileswatcher.h"
64 #include "base/utils/compare.h"
65 #include "base/utils/io.h"
66 #include "base/utils/misc.h"
67 #include "base/utils/net.h"
68 #include "base/utils/os.h"
69 #include "base/utils/password.h"
70 #include "base/utils/random.h"
71 #include "base/utils/sslkey.h"
72 #include "addnewtorrentdialog.h"
73 #include "advancedsettings.h"
74 #include "banlistoptionsdialog.h"
75 #include "interfaces/iguiapplication.h"
76 #include "ipsubnetwhitelistoptionsdialog.h"
77 #include "rss/automatedrssdownloader.h"
78 #include "ui_optionsdialog.h"
79 #include "uithemedialog.h"
80 #include "uithememanager.h"
82 #include "watchedfolderoptionsdialog.h"
83 #include "watchedfoldersmodel.h"
84 #include "webui/webui.h"
87 #include "base/net/dnsupdater.h"
90 #if defined Q_OS_MACOS || defined Q_OS_WIN
91 #include "base/utils/os.h"
92 #endif // defined Q_OS_MACOS || defined Q_OS_WIN
94 #define SETTINGS_KEY(name) u"OptionsDialog/" name
96 const int WEBUI_MIN_USERNAME_LENGTH
= 3;
97 const int WEBUI_MIN_PASSWORD_LENGTH
= 6;
101 QStringList
translatedWeekdayNames()
103 // return translated strings from Monday to Sunday in user selected locale
105 const QLocale locale
{Preferences::instance()->getLocale()};
106 const QDate date
{2018, 11, 5}; // Monday
108 for (int i
= 0; i
< 7; ++i
)
109 ret
.append(locale
.toString(date
.addDays(i
), u
"dddd"_s
));
113 class WheelEventEater final
: public QObject
116 using QObject::QObject
;
119 bool eventFilter(QObject
*, QEvent
*event
) override
121 return (event
->type() == QEvent::Wheel
);
125 bool isValidWebUIUsername(const QString
&username
)
127 return (username
.length() >= WEBUI_MIN_USERNAME_LENGTH
);
130 bool isValidWebUIPassword(const QString
&password
)
132 return (password
.length() >= WEBUI_MIN_PASSWORD_LENGTH
);
135 // Shortcuts for frequently used signals that have more than one overload. They would require
136 // type casts and that is why we declare required member pointer here instead.
137 void (QComboBox::*qComboBoxCurrentIndexChanged
)(int) = &QComboBox::currentIndexChanged
;
138 void (QSpinBox::*qSpinBoxValueChanged
)(int) = &QSpinBox::valueChanged
;
142 OptionsDialog::OptionsDialog(IGUIApplication
*app
, QWidget
*parent
)
143 : GUIApplicationComponent(app
, parent
)
144 , m_ui
{new Ui::OptionsDialog
}
145 , m_storeDialogSize
{SETTINGS_KEY(u
"Size"_s
)}
146 , m_storeHSplitterSize
{SETTINGS_KEY(u
"HorizontalSplitterSizes"_s
)}
147 , m_storeLastViewedPage
{SETTINGS_KEY(u
"LastViewedPage"_s
)}
150 m_applyButton
= m_ui
->buttonBox
->button(QDialogButtonBox::Apply
);
153 setWindowTitle(tr("Preferences"));
156 m_ui
->hsplitter
->setCollapsible(0, false);
157 m_ui
->hsplitter
->setCollapsible(1, false);
160 m_ui
->tabSelection
->item(TAB_UI
)->setIcon(UIThemeManager::instance()->getIcon(u
"preferences-desktop"_s
));
161 m_ui
->tabSelection
->item(TAB_BITTORRENT
)->setIcon(UIThemeManager::instance()->getIcon(u
"preferences-bittorrent"_s
, u
"preferences-system-network"_s
));
162 m_ui
->tabSelection
->item(TAB_CONNECTION
)->setIcon(UIThemeManager::instance()->getIcon(u
"network-connect"_s
, u
"network-wired"_s
));
163 m_ui
->tabSelection
->item(TAB_DOWNLOADS
)->setIcon(UIThemeManager::instance()->getIcon(u
"download"_s
, u
"folder-download"_s
));
164 m_ui
->tabSelection
->item(TAB_SPEED
)->setIcon(UIThemeManager::instance()->getIcon(u
"speedometer"_s
, u
"chronometer"_s
));
165 m_ui
->tabSelection
->item(TAB_RSS
)->setIcon(UIThemeManager::instance()->getIcon(u
"application-rss"_s
, u
"application-rss+xml"_s
));
167 m_ui
->tabSelection
->item(TAB_WEBUI
)->setHidden(true);
169 m_ui
->tabSelection
->item(TAB_WEBUI
)->setIcon(UIThemeManager::instance()->getIcon(u
"preferences-webui"_s
, u
"network-server"_s
));
171 m_ui
->tabSelection
->item(TAB_ADVANCED
)->setIcon(UIThemeManager::instance()->getIcon(u
"preferences-advanced"_s
, u
"preferences-other"_s
));
173 // set uniform size for all icons
175 for (int i
= 0; i
< m_ui
->tabSelection
->count(); ++i
)
176 maxHeight
= std::max(maxHeight
, m_ui
->tabSelection
->visualItemRect(m_ui
->tabSelection
->item(i
)).size().height());
177 for (int i
= 0; i
< m_ui
->tabSelection
->count(); ++i
)
179 const QSize
size(std::numeric_limits
<int>::max(), static_cast<int>(maxHeight
* 1.2));
180 m_ui
->tabSelection
->item(i
)->setSizeHint(size
);
183 connect(m_ui
->tabSelection
, &QListWidget::currentItemChanged
, this, &ThisType::changePage
);
186 loadBehaviorTabOptions();
187 loadDownloadsTabOptions();
188 loadConnectionTabOptions();
189 loadSpeedTabOptions();
190 loadBittorrentTabOptions();
192 #ifndef DISABLE_WEBUI
193 loadWebUITabOptions();
196 // Load Advanced settings
197 m_advancedSettings
= new AdvancedSettings(app
, m_ui
->tabAdvancedPage
);
198 m_ui
->advPageLayout
->addWidget(m_advancedSettings
);
199 connect(m_advancedSettings
, &AdvancedSettings::settingsChanged
, this, &ThisType::enableApplyButton
);
201 // setup apply button
202 m_applyButton
->setEnabled(false);
203 connect(m_applyButton
, &QPushButton::clicked
, this, [this]
206 m_applyButton
->setEnabled(false);
209 // disable mouse wheel event on widgets to avoid misselection
210 auto *wheelEventEater
= new WheelEventEater(this);
211 for (QComboBox
*widget
: asConst(findChildren
<QComboBox
*>()))
212 widget
->installEventFilter(wheelEventEater
);
213 for (QSpinBox
*widget
: asConst(findChildren
<QSpinBox
*>()))
214 widget
->installEventFilter(wheelEventEater
);
216 m_ui
->tabSelection
->setCurrentRow(m_storeLastViewedPage
);
218 if (const QSize dialogSize
= m_storeDialogSize
; dialogSize
.isValid())
222 OptionsDialog::~OptionsDialog()
224 // save dialog states
225 m_storeDialogSize
= size();
227 QStringList hSplitterSizes
;
228 for (const int size
: asConst(m_ui
->hsplitter
->sizes()))
229 hSplitterSizes
.append(QString::number(size
));
230 m_storeHSplitterSize
= hSplitterSizes
;
232 m_storeLastViewedPage
= m_ui
->tabSelection
->currentRow();
237 void OptionsDialog::loadBehaviorTabOptions()
239 const auto *pref
= Preferences::instance();
240 const auto *session
= BitTorrent::Session::instance();
242 initializeLanguageCombo();
243 setLocale(pref
->getLocale());
245 initializeStyleCombo();
246 initializeColorSchemeOptions();
248 m_ui
->checkUseCustomTheme
->setChecked(Preferences::instance()->useCustomUITheme());
249 m_ui
->customThemeFilePath
->setSelectedPath(Preferences::instance()->customUIThemePath());
250 m_ui
->customThemeFilePath
->setMode(FileSystemPathEdit::Mode::FileOpen
);
251 m_ui
->customThemeFilePath
->setDialogCaption(tr("Select qBittorrent UI Theme file"));
252 m_ui
->customThemeFilePath
->setFileNameFilter(tr("qBittorrent UI Theme file (*.qbtheme config.json)"));
253 #if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS))
254 m_ui
->checkUseSystemIcon
->setChecked(pref
->useSystemIcons());
256 m_ui
->checkUseSystemIcon
->setVisible(false);
259 m_ui
->confirmDeletion
->setChecked(pref
->confirmTorrentDeletion());
260 m_ui
->checkAltRowColors
->setChecked(pref
->useAlternatingRowColors());
261 m_ui
->checkHideZero
->setChecked(pref
->getHideZeroValues());
262 m_ui
->comboHideZero
->setCurrentIndex(pref
->getHideZeroComboValues());
263 m_ui
->comboHideZero
->setEnabled(m_ui
->checkHideZero
->isChecked());
265 m_ui
->actionTorrentDlOnDblClBox
->setItemData(0, TOGGLE_STOP
);
266 m_ui
->actionTorrentDlOnDblClBox
->setItemData(1, OPEN_DEST
);
267 m_ui
->actionTorrentDlOnDblClBox
->setItemData(2, PREVIEW_FILE
);
268 m_ui
->actionTorrentDlOnDblClBox
->setItemData(3, SHOW_OPTIONS
);
269 m_ui
->actionTorrentDlOnDblClBox
->setItemData(4, NO_ACTION
);
270 int actionDownloading
= pref
->getActionOnDblClOnTorrentDl();
271 if ((actionDownloading
< 0) || (actionDownloading
>= m_ui
->actionTorrentDlOnDblClBox
->count()))
272 actionDownloading
= TOGGLE_STOP
;
273 m_ui
->actionTorrentDlOnDblClBox
->setCurrentIndex(m_ui
->actionTorrentDlOnDblClBox
->findData(actionDownloading
));
275 m_ui
->actionTorrentFnOnDblClBox
->setItemData(0, TOGGLE_STOP
);
276 m_ui
->actionTorrentFnOnDblClBox
->setItemData(1, OPEN_DEST
);
277 m_ui
->actionTorrentFnOnDblClBox
->setItemData(2, PREVIEW_FILE
);
278 m_ui
->actionTorrentFnOnDblClBox
->setItemData(3, SHOW_OPTIONS
);
279 m_ui
->actionTorrentFnOnDblClBox
->setItemData(4, NO_ACTION
);
280 int actionSeeding
= pref
->getActionOnDblClOnTorrentFn();
281 if ((actionSeeding
< 0) || (actionSeeding
>= m_ui
->actionTorrentFnOnDblClBox
->count()))
282 actionSeeding
= OPEN_DEST
;
283 m_ui
->actionTorrentFnOnDblClBox
->setCurrentIndex(m_ui
->actionTorrentFnOnDblClBox
->findData(actionSeeding
));
285 m_ui
->checkBoxHideZeroStatusFilters
->setChecked(pref
->getHideZeroStatusFilters());
288 m_ui
->checkStartup
->setVisible(false);
290 m_ui
->checkShowSplash
->setChecked(!pref
->isSplashScreenDisabled());
291 m_ui
->checkProgramExitConfirm
->setChecked(pref
->confirmOnExit());
292 m_ui
->checkProgramAutoExitConfirm
->setChecked(!pref
->dontConfirmAutoExit());
294 m_ui
->windowStateComboBox
->addItem(tr("Normal"), QVariant::fromValue(WindowState::Normal
));
295 m_ui
->windowStateComboBox
->addItem(tr("Minimized"), QVariant::fromValue(WindowState::Minimized
));
297 m_ui
->windowStateComboBox
->addItem(tr("Hidden"), QVariant::fromValue(WindowState::Hidden
));
299 m_ui
->windowStateComboBox
->setCurrentIndex(m_ui
->windowStateComboBox
->findData(QVariant::fromValue(app()->startUpWindowState())));
301 #if !(defined(Q_OS_WIN) || defined(Q_OS_MACOS))
302 m_ui
->groupFileAssociation
->setVisible(false);
303 m_ui
->checkProgramUpdates
->setVisible(false);
307 // Disable systray integration if it is not supported by the system
308 if (!QSystemTrayIcon::isSystemTrayAvailable())
310 m_ui
->checkShowSystray
->setChecked(false);
311 m_ui
->checkShowSystray
->setEnabled(false);
312 m_ui
->checkShowSystray
->setToolTip(tr("Disabled due to failed to detect system tray presence"));
314 m_ui
->checkShowSystray
->setChecked(pref
->systemTrayEnabled());
315 m_ui
->checkMinimizeToSysTray
->setChecked(pref
->minimizeToTray());
316 m_ui
->checkCloseToSystray
->setChecked(pref
->closeToTray());
317 m_ui
->comboTrayIcon
->setCurrentIndex(static_cast<int>(pref
->trayIconStyle()));
321 m_ui
->checkStartup
->setChecked(pref
->WinStartup());
325 m_ui
->checkShowSystray
->setVisible(false);
326 m_ui
->checkAssociateTorrents
->setChecked(Utils::OS::isTorrentFileAssocSet());
327 m_ui
->checkAssociateTorrents
->setEnabled(!m_ui
->checkAssociateTorrents
->isChecked());
328 m_ui
->checkAssociateMagnetLinks
->setChecked(Utils::OS::isMagnetLinkAssocSet());
329 m_ui
->checkAssociateMagnetLinks
->setEnabled(!m_ui
->checkAssociateMagnetLinks
->isChecked());
332 #if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
333 m_ui
->checkProgramUpdates
->setChecked(pref
->isUpdateCheckEnabled());
336 m_ui
->checkPreventFromSuspendWhenDownloading
->setChecked(pref
->preventFromSuspendWhenDownloading());
337 m_ui
->checkPreventFromSuspendWhenSeeding
->setChecked(pref
->preventFromSuspendWhenSeeding());
339 m_ui
->textFileLogPath
->setDialogCaption(tr("Choose a save directory"));
340 m_ui
->textFileLogPath
->setMode(FileSystemPathEdit::Mode::DirectorySave
);
341 m_ui
->textFileLogPath
->setSelectedPath(app()->fileLoggerPath());
342 const bool fileLogBackup
= app()->isFileLoggerBackup();
343 m_ui
->checkFileLogBackup
->setChecked(fileLogBackup
);
344 m_ui
->spinFileLogSize
->setEnabled(fileLogBackup
);
345 const bool fileLogDelete
= app()->isFileLoggerDeleteOld();
346 m_ui
->checkFileLogDelete
->setChecked(fileLogDelete
);
347 m_ui
->spinFileLogAge
->setEnabled(fileLogDelete
);
348 m_ui
->comboFileLogAgeType
->setEnabled(fileLogDelete
);
349 m_ui
->spinFileLogSize
->setValue(app()->fileLoggerMaxSize() / 1024);
350 m_ui
->spinFileLogAge
->setValue(app()->fileLoggerAge());
351 m_ui
->comboFileLogAgeType
->setCurrentIndex(app()->fileLoggerAgeType());
352 // Groupbox's check state must be initialized after some of its children if they are manually enabled/disabled
353 m_ui
->checkFileLog
->setChecked(app()->isFileLoggerEnabled());
355 m_ui
->checkBoxExternalIPStatusBar
->setChecked(pref
->isStatusbarExternalIPDisplayed());
356 m_ui
->checkBoxPerformanceWarning
->setChecked(session
->isPerformanceWarningEnabled());
358 connect(m_ui
->comboLanguage
, qComboBoxCurrentIndexChanged
, this, &ThisType::enableApplyButton
);
361 connect(m_ui
->comboStyle
, qComboBoxCurrentIndexChanged
, this, &ThisType::enableApplyButton
);
364 #ifdef QBT_HAS_COLORSCHEME_OPTION
365 connect(m_ui
->comboColorScheme
, qComboBoxCurrentIndexChanged
, this, &ThisType::enableApplyButton
);
368 #if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS))
369 connect(m_ui
->checkUseSystemIcon
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
371 connect(m_ui
->checkUseCustomTheme
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
372 connect(m_ui
->customThemeFilePath
, &FileSystemPathEdit::selectedPathChanged
, this, &ThisType::enableApplyButton
);
374 m_ui
->buttonCustomizeUITheme
->setEnabled(!m_ui
->checkUseCustomTheme
->isChecked());
375 connect(m_ui
->checkUseCustomTheme
, &QGroupBox::toggled
, this, [this]
377 m_ui
->buttonCustomizeUITheme
->setEnabled(!m_ui
->checkUseCustomTheme
->isChecked());
379 connect(m_ui
->buttonCustomizeUITheme
, &QPushButton::clicked
, this, [this]
381 auto *dialog
= new UIThemeDialog(this);
382 dialog
->setAttribute(Qt::WA_DeleteOnClose
);
386 connect(m_ui
->confirmDeletion
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
387 connect(m_ui
->checkAltRowColors
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
388 connect(m_ui
->checkHideZero
, &QAbstractButton::toggled
, m_ui
->comboHideZero
, &QWidget::setEnabled
);
389 connect(m_ui
->checkHideZero
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
390 connect(m_ui
->comboHideZero
, qComboBoxCurrentIndexChanged
, this, &ThisType::enableApplyButton
);
391 connect(m_ui
->actionTorrentDlOnDblClBox
, qComboBoxCurrentIndexChanged
, this, &ThisType::enableApplyButton
);
392 connect(m_ui
->actionTorrentFnOnDblClBox
, qComboBoxCurrentIndexChanged
, this, &ThisType::enableApplyButton
);
393 connect(m_ui
->checkBoxHideZeroStatusFilters
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
396 connect(m_ui
->checkStartup
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
398 connect(m_ui
->checkShowSplash
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
399 connect(m_ui
->checkProgramExitConfirm
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
400 connect(m_ui
->checkProgramAutoExitConfirm
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
401 connect(m_ui
->checkShowSystray
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
402 connect(m_ui
->checkMinimizeToSysTray
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
403 connect(m_ui
->checkCloseToSystray
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
404 connect(m_ui
->comboTrayIcon
, qComboBoxCurrentIndexChanged
, this, &ThisType::enableApplyButton
);
405 connect(m_ui
->windowStateComboBox
, qComboBoxCurrentIndexChanged
, this, &ThisType::enableApplyButton
);
407 connect(m_ui
->checkPreventFromSuspendWhenDownloading
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
408 connect(m_ui
->checkPreventFromSuspendWhenSeeding
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
410 #if defined(Q_OS_MACOS)
411 connect(m_ui
->checkAssociateTorrents
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
412 connect(m_ui
->checkAssociateMagnetLinks
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
415 #if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
416 connect(m_ui
->checkProgramUpdates
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
420 m_ui
->assocPanel
->hide();
424 m_ui
->defaultProgramPanel
->hide();
427 #if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) && !defined(QBT_USES_DBUS)
428 m_ui
->checkPreventFromSuspendWhenDownloading
->setDisabled(true);
429 m_ui
->checkPreventFromSuspendWhenSeeding
->setDisabled(true);
432 connect(m_ui
->checkFileLog
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
433 connect(m_ui
->textFileLogPath
, &FileSystemPathEdit::selectedPathChanged
, this, &ThisType::enableApplyButton
);
434 connect(m_ui
->checkFileLogBackup
, &QAbstractButton::toggled
, m_ui
->spinFileLogSize
, &QWidget::setEnabled
);
435 connect(m_ui
->checkFileLogBackup
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
436 connect(m_ui
->checkFileLogDelete
, &QAbstractButton::toggled
, m_ui
->comboFileLogAgeType
, &QWidget::setEnabled
);
437 connect(m_ui
->checkFileLogDelete
, &QAbstractButton::toggled
, m_ui
->spinFileLogAge
, &QWidget::setEnabled
);
438 connect(m_ui
->checkFileLogDelete
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
439 connect(m_ui
->spinFileLogSize
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
440 connect(m_ui
->spinFileLogAge
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
441 connect(m_ui
->comboFileLogAgeType
, qComboBoxCurrentIndexChanged
, this, &ThisType::enableApplyButton
);
443 connect(m_ui
->checkBoxExternalIPStatusBar
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
444 connect(m_ui
->checkBoxPerformanceWarning
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
447 void OptionsDialog::saveBehaviorTabOptions() const
449 auto *pref
= Preferences::instance();
450 auto *session
= BitTorrent::Session::instance();
452 // Load the translation
453 const QString locale
= getLocale();
454 if (pref
->getLocale() != locale
)
456 auto *translator
= new QTranslator
;
457 if (translator
->load(u
":/lang/qbittorrent_"_s
+ locale
))
458 qDebug("%s locale recognized, using translation.", qUtf8Printable(locale
));
460 qDebug("%s locale unrecognized, using default (en).", qUtf8Printable(locale
));
461 qApp
->installTranslator(translator
);
463 pref
->setLocale(locale
);
466 if (const QVariant systemStyle
= m_ui
->comboStyle
->currentData(); systemStyle
.isValid())
467 pref
->setStyle(systemStyle
.toString());
469 pref
->setStyle(m_ui
->comboStyle
->currentText());
472 #ifdef QBT_HAS_COLORSCHEME_OPTION
473 UIThemeManager::instance()->setColorScheme(m_ui
->comboColorScheme
->currentData().value
<ColorScheme
>());
476 #if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS))
477 pref
->useSystemIcons(m_ui
->checkUseSystemIcon
->isChecked());
479 pref
->setUseCustomUITheme(m_ui
->checkUseCustomTheme
->isChecked());
480 pref
->setCustomUIThemePath(m_ui
->customThemeFilePath
->selectedPath());
482 pref
->setConfirmTorrentDeletion(m_ui
->confirmDeletion
->isChecked());
483 pref
->setAlternatingRowColors(m_ui
->checkAltRowColors
->isChecked());
484 pref
->setHideZeroValues(m_ui
->checkHideZero
->isChecked());
485 pref
->setHideZeroComboValues(m_ui
->comboHideZero
->currentIndex());
487 pref
->setActionOnDblClOnTorrentDl(m_ui
->actionTorrentDlOnDblClBox
->currentData().toInt());
488 pref
->setActionOnDblClOnTorrentFn(m_ui
->actionTorrentFnOnDblClBox
->currentData().toInt());
490 pref
->setHideZeroStatusFilters(m_ui
->checkBoxHideZeroStatusFilters
->isChecked());
492 pref
->setSplashScreenDisabled(isSplashScreenDisabled());
493 pref
->setConfirmOnExit(m_ui
->checkProgramExitConfirm
->isChecked());
494 pref
->setDontConfirmAutoExit(!m_ui
->checkProgramAutoExitConfirm
->isChecked());
497 pref
->setWinStartup(WinStartup());
501 pref
->setSystemTrayEnabled(m_ui
->checkShowSystray
->isChecked());
502 pref
->setTrayIconStyle(TrayIcon::Style(m_ui
->comboTrayIcon
->currentIndex()));
503 pref
->setCloseToTray(m_ui
->checkCloseToSystray
->isChecked());
504 pref
->setMinimizeToTray(m_ui
->checkMinimizeToSysTray
->isChecked());
508 if (m_ui
->checkAssociateTorrents
->isChecked())
510 Utils::OS::setTorrentFileAssoc();
511 m_ui
->checkAssociateTorrents
->setChecked(Utils::OS::isTorrentFileAssocSet());
512 m_ui
->checkAssociateTorrents
->setEnabled(!m_ui
->checkAssociateTorrents
->isChecked());
514 if (m_ui
->checkAssociateMagnetLinks
->isChecked())
516 Utils::OS::setMagnetLinkAssoc();
517 m_ui
->checkAssociateMagnetLinks
->setChecked(Utils::OS::isMagnetLinkAssocSet());
518 m_ui
->checkAssociateMagnetLinks
->setEnabled(!m_ui
->checkAssociateMagnetLinks
->isChecked());
522 #if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
523 pref
->setUpdateCheckEnabled(m_ui
->checkProgramUpdates
->isChecked());
526 pref
->setPreventFromSuspendWhenDownloading(m_ui
->checkPreventFromSuspendWhenDownloading
->isChecked());
527 pref
->setPreventFromSuspendWhenSeeding(m_ui
->checkPreventFromSuspendWhenSeeding
->isChecked());
529 app()->setFileLoggerPath(m_ui
->textFileLogPath
->selectedPath());
530 app()->setFileLoggerBackup(m_ui
->checkFileLogBackup
->isChecked());
531 app()->setFileLoggerMaxSize(m_ui
->spinFileLogSize
->value() * 1024);
532 app()->setFileLoggerAge(m_ui
->spinFileLogAge
->value());
533 app()->setFileLoggerAgeType(m_ui
->comboFileLogAgeType
->currentIndex());
534 app()->setFileLoggerDeleteOld(m_ui
->checkFileLogDelete
->isChecked());
535 app()->setFileLoggerEnabled(m_ui
->checkFileLog
->isChecked());
537 app()->setStartUpWindowState(m_ui
->windowStateComboBox
->currentData().value
<WindowState
>());
539 pref
->setStatusbarExternalIPDisplayed(m_ui
->checkBoxExternalIPStatusBar
->isChecked());
540 session
->setPerformanceWarningEnabled(m_ui
->checkBoxPerformanceWarning
->isChecked());
543 void OptionsDialog::loadDownloadsTabOptions()
545 const auto *pref
= Preferences::instance();
546 const auto *session
= BitTorrent::Session::instance();
548 m_ui
->checkAdditionDialog
->setChecked(pref
->isAddNewTorrentDialogEnabled());
549 m_ui
->checkAdditionDialogFront
->setChecked(pref
->isAddNewTorrentDialogTopLevel());
551 m_ui
->contentLayoutComboBox
->setCurrentIndex(static_cast<int>(session
->torrentContentLayout()));
552 m_ui
->checkAddToQueueTop
->setChecked(session
->isAddTorrentToQueueTop());
553 m_ui
->checkAddStopped
->setChecked(session
->isAddTorrentStopped());
555 m_ui
->stopConditionComboBox
->setToolTip(
556 u
"<html><body><p><b>" + tr("None") + u
"</b> - " + tr("No stop condition is set.") + u
"</p><p><b>" +
557 tr("Metadata received") + u
"</b> - " + tr("Torrent will stop after metadata is received.") +
558 u
" <em>" + tr("Torrents that have metadata initially will be added as stopped.") + u
"</em></p><p><b>" +
559 tr("Files checked") + u
"</b> - " + tr("Torrent will stop after files are initially checked.") +
560 u
" <em>" + tr("This will also download metadata if it wasn't there initially.") + u
"</em></p></body></html>");
561 m_ui
->stopConditionComboBox
->setItemData(0, QVariant::fromValue(BitTorrent::Torrent::StopCondition::None
));
562 m_ui
->stopConditionComboBox
->setItemData(1, QVariant::fromValue(BitTorrent::Torrent::StopCondition::MetadataReceived
));
563 m_ui
->stopConditionComboBox
->setItemData(2, QVariant::fromValue(BitTorrent::Torrent::StopCondition::FilesChecked
));
564 m_ui
->stopConditionComboBox
->setCurrentIndex(m_ui
->stopConditionComboBox
->findData(QVariant::fromValue(session
->torrentStopCondition())));
565 m_ui
->stopConditionLabel
->setEnabled(!m_ui
->checkAddStopped
->isChecked());
566 m_ui
->stopConditionComboBox
->setEnabled(!m_ui
->checkAddStopped
->isChecked());
568 m_ui
->checkMergeTrackers
->setChecked(session
->isMergeTrackersEnabled());
569 m_ui
->checkConfirmMergeTrackers
->setEnabled(m_ui
->checkAdditionDialog
->isChecked());
570 m_ui
->checkConfirmMergeTrackers
->setChecked(m_ui
->checkConfirmMergeTrackers
->isEnabled() ? pref
->confirmMergeTrackers() : false);
571 connect(m_ui
->checkAdditionDialog
, &QGroupBox::toggled
, this, [this, pref
]
573 m_ui
->checkConfirmMergeTrackers
->setEnabled(m_ui
->checkAdditionDialog
->isChecked());
574 m_ui
->checkConfirmMergeTrackers
->setChecked(m_ui
->checkConfirmMergeTrackers
->isEnabled() ? pref
->confirmMergeTrackers() : false);
577 const TorrentFileGuard::AutoDeleteMode autoDeleteMode
= TorrentFileGuard::autoDeleteMode();
578 m_ui
->deleteTorrentBox
->setChecked(autoDeleteMode
!= TorrentFileGuard::Never
);
579 m_ui
->deleteCancelledTorrentBox
->setChecked(autoDeleteMode
== TorrentFileGuard::Always
);
580 m_ui
->deleteTorrentWarningIcon
->setPixmap(QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical
).pixmap(16, 16));
581 m_ui
->deleteTorrentWarningIcon
->hide();
582 m_ui
->deleteTorrentWarningLabel
->hide();
583 m_ui
->deleteTorrentWarningLabel
->setToolTip(u
"<html><body><p>" +
584 tr("By enabling these options, you can <strong>irrevocably lose</strong> your .torrent files!") +
586 tr("When these options are enabled, qBittorrent will <strong>delete</strong> .torrent files "
587 "after they were successfully (the first option) or not (the second option) added to its "
588 "download queue. This will be applied <strong>not only</strong> to the files opened via "
589 "“Add torrent” menu action but to those opened via <strong>file type association</strong> as well") +
591 tr("If you enable the second option (“Also when addition is cancelled”) the "
592 ".torrent file <strong>will be deleted</strong> even if you press “<strong>Cancel</strong>” in "
593 "the “Add torrent” dialog") +
594 u
"</p></body></html>");
596 m_ui
->checkPreallocateAll
->setChecked(session
->isPreallocationEnabled());
597 m_ui
->checkAppendqB
->setChecked(session
->isAppendExtensionEnabled());
598 m_ui
->checkUnwantedFolder
->setChecked(session
->isUnwantedFolderEnabled());
599 m_ui
->checkRecursiveDownload
->setChecked(pref
->isRecursiveDownloadEnabled());
601 m_ui
->comboSavingMode
->setCurrentIndex(!session
->isAutoTMMDisabledByDefault());
602 m_ui
->comboTorrentCategoryChanged
->setCurrentIndex(session
->isDisableAutoTMMWhenCategoryChanged());
603 m_ui
->comboCategoryChanged
->setCurrentIndex(session
->isDisableAutoTMMWhenCategorySavePathChanged());
604 m_ui
->comboCategoryDefaultPathChanged
->setCurrentIndex(session
->isDisableAutoTMMWhenDefaultSavePathChanged());
606 m_ui
->checkUseSubcategories
->setChecked(session
->isSubcategoriesEnabled());
607 m_ui
->checkUseCategoryPaths
->setChecked(session
->useCategoryPathsInManualMode());
609 m_ui
->textSavePath
->setDialogCaption(tr("Choose a save directory"));
610 m_ui
->textSavePath
->setMode(FileSystemPathEdit::Mode::DirectorySave
);
611 m_ui
->textSavePath
->setSelectedPath(session
->savePath());
613 m_ui
->checkUseDownloadPath
->setChecked(session
->isDownloadPathEnabled());
614 m_ui
->textDownloadPath
->setDialogCaption(tr("Choose a save directory"));
615 m_ui
->textDownloadPath
->setEnabled(m_ui
->checkUseDownloadPath
->isChecked());
616 m_ui
->textDownloadPath
->setMode(FileSystemPathEdit::Mode::DirectorySave
);
617 m_ui
->textDownloadPath
->setSelectedPath(session
->downloadPath());
619 const bool isExportDirEmpty
= session
->torrentExportDirectory().isEmpty();
620 m_ui
->checkExportDir
->setChecked(!isExportDirEmpty
);
621 m_ui
->textExportDir
->setDialogCaption(tr("Choose export directory"));
622 m_ui
->textExportDir
->setEnabled(m_ui
->checkExportDir
->isChecked());
623 m_ui
->textExportDir
->setMode(FileSystemPathEdit::Mode::DirectorySave
);
624 if (!isExportDirEmpty
)
625 m_ui
->textExportDir
->setSelectedPath(session
->torrentExportDirectory());
627 const bool isExportDirFinEmpty
= session
->finishedTorrentExportDirectory().isEmpty();
628 m_ui
->checkExportDirFin
->setChecked(!isExportDirFinEmpty
);
629 m_ui
->textExportDirFin
->setDialogCaption(tr("Choose export directory"));
630 m_ui
->textExportDirFin
->setEnabled(m_ui
->checkExportDirFin
->isChecked());
631 m_ui
->textExportDirFin
->setMode(FileSystemPathEdit::Mode::DirectorySave
);
632 if (!isExportDirFinEmpty
)
633 m_ui
->textExportDirFin
->setSelectedPath(session
->finishedTorrentExportDirectory());
635 auto *watchedFoldersModel
= new WatchedFoldersModel(TorrentFilesWatcher::instance(), this);
636 connect(watchedFoldersModel
, &QAbstractListModel::dataChanged
, this, &ThisType::enableApplyButton
);
637 m_ui
->scanFoldersView
->header()->setSectionResizeMode(QHeaderView::ResizeToContents
);
638 m_ui
->scanFoldersView
->setModel(watchedFoldersModel
);
639 connect(m_ui
->scanFoldersView
->selectionModel(), &QItemSelectionModel::selectionChanged
, this, &ThisType::handleWatchedFolderViewSelectionChanged
);
640 connect(m_ui
->scanFoldersView
, &QTreeView::doubleClicked
, this, &ThisType::editWatchedFolderOptions
);
642 m_ui
->groupExcludedFileNames
->setChecked(session
->isExcludedFileNamesEnabled());
643 m_ui
->textExcludedFileNames
->setPlainText(session
->excludedFileNames().join(u
'\n'));
645 m_ui
->groupMailNotification
->setChecked(pref
->isMailNotificationEnabled());
646 m_ui
->senderEmailTxt
->setText(pref
->getMailNotificationSender());
647 m_ui
->lineEditDestEmail
->setText(pref
->getMailNotificationEmail());
648 m_ui
->lineEditSmtpServer
->setText(pref
->getMailNotificationSMTP());
649 m_ui
->checkSmtpSSL
->setChecked(pref
->getMailNotificationSMTPSSL());
650 m_ui
->groupMailNotifAuth
->setChecked(pref
->getMailNotificationSMTPAuth());
651 m_ui
->mailNotifUsername
->setText(pref
->getMailNotificationSMTPUsername());
652 m_ui
->mailNotifPassword
->setText(pref
->getMailNotificationSMTPPassword());
654 m_ui
->groupBoxRunOnAdded
->setChecked(pref
->isAutoRunOnTorrentAddedEnabled());
655 m_ui
->groupBoxRunOnFinished
->setChecked(pref
->isAutoRunOnTorrentFinishedEnabled());
656 m_ui
->lineEditRunOnAdded
->setText(pref
->getAutoRunOnTorrentAddedProgram());
657 m_ui
->lineEditRunOnFinished
->setText(pref
->getAutoRunOnTorrentFinishedProgram());
658 #if defined(Q_OS_WIN)
659 m_ui
->autoRunConsole
->setChecked(pref
->isAutoRunConsoleEnabled());
661 m_ui
->autoRunConsole
->hide();
663 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
664 .arg(tr("Supported parameters (case sensitive):")
665 , tr("%N: Torrent name")
667 , tr("%G: Tags (separated by comma)")
668 , tr("%F: Content path (same as root path for multifile torrent)")
669 , tr("%R: Root path (first torrent subdirectory path)")
670 , tr("%D: Save path")
671 , tr("%C: Number of files")
672 , tr("%Z: Torrent size (bytes)"))
673 .arg(tr("%T: Current tracker")
674 , tr("%I: Info hash v1 (or '-' if unavailable)")
675 , tr("%J: Info hash v2 (or '-' if unavailable)")
676 , tr("%K: Torrent ID (either sha-1 info hash for v1 torrent or truncated sha-256 info hash for v2/hybrid torrent)")
677 , tr("Tip: Encapsulate parameter with quotation marks to avoid text being cut off at whitespace (e.g., \"%N\")"));
678 m_ui
->labelAutoRunParam
->setText(autoRunStr
);
680 connect(m_ui
->checkAdditionDialog
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
681 connect(m_ui
->checkAdditionDialogFront
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
683 connect(m_ui
->contentLayoutComboBox
, qComboBoxCurrentIndexChanged
, this, &ThisType::enableApplyButton
);
685 connect(m_ui
->checkAddToQueueTop
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
686 connect(m_ui
->checkAddStopped
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
687 connect(m_ui
->checkAddStopped
, &QAbstractButton::toggled
, this, [this](const bool checked
)
689 m_ui
->stopConditionLabel
->setEnabled(!checked
);
690 m_ui
->stopConditionComboBox
->setEnabled(!checked
);
692 connect(m_ui
->stopConditionComboBox
, qComboBoxCurrentIndexChanged
, this, &ThisType::enableApplyButton
);
693 connect(m_ui
->checkMergeTrackers
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
694 connect(m_ui
->checkConfirmMergeTrackers
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
695 connect(m_ui
->deleteTorrentBox
, &QGroupBox::toggled
, m_ui
->deleteTorrentWarningIcon
, &QWidget::setVisible
);
696 connect(m_ui
->deleteTorrentBox
, &QGroupBox::toggled
, m_ui
->deleteTorrentWarningLabel
, &QWidget::setVisible
);
697 connect(m_ui
->deleteTorrentBox
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
698 connect(m_ui
->deleteCancelledTorrentBox
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
700 connect(m_ui
->checkPreallocateAll
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
701 connect(m_ui
->checkAppendqB
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
702 connect(m_ui
->checkUnwantedFolder
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
703 connect(m_ui
->checkRecursiveDownload
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
705 connect(m_ui
->comboSavingMode
, qComboBoxCurrentIndexChanged
, this, &ThisType::enableApplyButton
);
706 connect(m_ui
->comboTorrentCategoryChanged
, qComboBoxCurrentIndexChanged
, this, &ThisType::enableApplyButton
);
707 connect(m_ui
->comboCategoryChanged
, qComboBoxCurrentIndexChanged
, this, &ThisType::enableApplyButton
);
708 connect(m_ui
->comboCategoryDefaultPathChanged
, qComboBoxCurrentIndexChanged
, this, &ThisType::enableApplyButton
);
710 connect(m_ui
->checkUseSubcategories
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
711 connect(m_ui
->checkUseCategoryPaths
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
713 connect(m_ui
->textSavePath
, &FileSystemPathEdit::selectedPathChanged
, this, &ThisType::enableApplyButton
);
714 connect(m_ui
->textDownloadPath
, &FileSystemPathEdit::selectedPathChanged
, this, &ThisType::enableApplyButton
);
716 connect(m_ui
->checkExportDir
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
717 connect(m_ui
->checkExportDir
, &QAbstractButton::toggled
, m_ui
->textExportDir
, &QWidget::setEnabled
);
718 connect(m_ui
->checkExportDirFin
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
719 connect(m_ui
->checkExportDirFin
, &QAbstractButton::toggled
, m_ui
->textExportDirFin
, &QWidget::setEnabled
);
720 connect(m_ui
->textExportDir
, &FileSystemPathEdit::selectedPathChanged
, this, &ThisType::enableApplyButton
);
721 connect(m_ui
->textExportDirFin
, &FileSystemPathEdit::selectedPathChanged
, this, &ThisType::enableApplyButton
);
722 connect(m_ui
->checkUseDownloadPath
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
723 connect(m_ui
->checkUseDownloadPath
, &QAbstractButton::toggled
, m_ui
->textDownloadPath
, &QWidget::setEnabled
);
725 connect(m_ui
->addWatchedFolderButton
, &QAbstractButton::clicked
, this, &ThisType::enableApplyButton
);
727 connect(m_ui
->groupExcludedFileNames
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
728 connect(m_ui
->textExcludedFileNames
, &QPlainTextEdit::textChanged
, this, &ThisType::enableApplyButton
);
729 connect(m_ui
->removeWatchedFolderButton
, &QAbstractButton::clicked
, this, &ThisType::enableApplyButton
);
731 connect(m_ui
->groupMailNotification
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
732 connect(m_ui
->senderEmailTxt
, &QLineEdit::textChanged
, this, &ThisType::enableApplyButton
);
733 connect(m_ui
->lineEditDestEmail
, &QLineEdit::textChanged
, this, &ThisType::enableApplyButton
);
734 connect(m_ui
->lineEditSmtpServer
, &QLineEdit::textChanged
, this, &ThisType::enableApplyButton
);
735 connect(m_ui
->checkSmtpSSL
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
736 connect(m_ui
->groupMailNotifAuth
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
737 connect(m_ui
->mailNotifUsername
, &QLineEdit::textChanged
, this, &ThisType::enableApplyButton
);
738 connect(m_ui
->mailNotifPassword
, &QLineEdit::textChanged
, this, &ThisType::enableApplyButton
);
739 connect(m_ui
->sendTestEmail
, &QPushButton::clicked
, this, [this]
741 app()->sendTestEmail();
742 QMessageBox::information(this, tr("Test email"), tr("Attempted to send email. Check your inbox to confirm success"));
745 connect(m_ui
->groupBoxRunOnAdded
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
746 connect(m_ui
->lineEditRunOnAdded
, &QLineEdit::textChanged
, this, &ThisType::enableApplyButton
);
747 connect(m_ui
->groupBoxRunOnFinished
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
748 connect(m_ui
->lineEditRunOnFinished
, &QLineEdit::textChanged
, this, &ThisType::enableApplyButton
);
749 connect(m_ui
->autoRunConsole
, &QCheckBox::toggled
, this, &ThisType::enableApplyButton
);
752 void OptionsDialog::saveDownloadsTabOptions() const
754 auto *pref
= Preferences::instance();
755 auto *session
= BitTorrent::Session::instance();
757 pref
->setAddNewTorrentDialogEnabled(useAdditionDialog());
758 pref
->setAddNewTorrentDialogTopLevel(m_ui
->checkAdditionDialogFront
->isChecked());
760 session
->setTorrentContentLayout(static_cast<BitTorrent::TorrentContentLayout
>(m_ui
->contentLayoutComboBox
->currentIndex()));
762 session
->setAddTorrentToQueueTop(m_ui
->checkAddToQueueTop
->isChecked());
763 session
->setAddTorrentStopped(addTorrentsStopped());
764 session
->setTorrentStopCondition(m_ui
->stopConditionComboBox
->currentData().value
<BitTorrent::Torrent::StopCondition
>());
765 TorrentFileGuard::setAutoDeleteMode(!m_ui
->deleteTorrentBox
->isChecked() ? TorrentFileGuard::Never
766 : !m_ui
->deleteCancelledTorrentBox
->isChecked() ? TorrentFileGuard::IfAdded
767 : TorrentFileGuard::Always
);
768 session
->setMergeTrackersEnabled(m_ui
->checkMergeTrackers
->isChecked());
769 if (m_ui
->checkConfirmMergeTrackers
->isEnabled())
770 pref
->setConfirmMergeTrackers(m_ui
->checkConfirmMergeTrackers
->isChecked());
772 session
->setPreallocationEnabled(preAllocateAllFiles());
773 session
->setAppendExtensionEnabled(m_ui
->checkAppendqB
->isChecked());
774 session
->setUnwantedFolderEnabled(m_ui
->checkUnwantedFolder
->isChecked());
775 pref
->setRecursiveDownloadEnabled(m_ui
->checkRecursiveDownload
->isChecked());
777 session
->setAutoTMMDisabledByDefault(m_ui
->comboSavingMode
->currentIndex() == 0);
778 session
->setDisableAutoTMMWhenCategoryChanged(m_ui
->comboTorrentCategoryChanged
->currentIndex() == 1);
779 session
->setDisableAutoTMMWhenCategorySavePathChanged(m_ui
->comboCategoryChanged
->currentIndex() == 1);
780 session
->setDisableAutoTMMWhenDefaultSavePathChanged(m_ui
->comboCategoryDefaultPathChanged
->currentIndex() == 1);
782 session
->setSubcategoriesEnabled(m_ui
->checkUseSubcategories
->isChecked());
783 session
->setUseCategoryPathsInManualMode(m_ui
->checkUseCategoryPaths
->isChecked());
785 session
->setSavePath(Path(m_ui
->textSavePath
->selectedPath()));
786 session
->setDownloadPathEnabled(m_ui
->checkUseDownloadPath
->isChecked());
787 session
->setDownloadPath(m_ui
->textDownloadPath
->selectedPath());
788 session
->setTorrentExportDirectory(getTorrentExportDir());
789 session
->setFinishedTorrentExportDirectory(getFinishedTorrentExportDir());
791 auto *watchedFoldersModel
= static_cast<WatchedFoldersModel
*>(m_ui
->scanFoldersView
->model());
792 watchedFoldersModel
->apply();
794 session
->setExcludedFileNamesEnabled(m_ui
->groupExcludedFileNames
->isChecked());
795 session
->setExcludedFileNames(m_ui
->textExcludedFileNames
->toPlainText().split(u
'\n', Qt::SkipEmptyParts
));
797 pref
->setMailNotificationEnabled(m_ui
->groupMailNotification
->isChecked());
798 pref
->setMailNotificationSender(m_ui
->senderEmailTxt
->text());
799 pref
->setMailNotificationEmail(m_ui
->lineEditDestEmail
->text());
800 pref
->setMailNotificationSMTP(m_ui
->lineEditSmtpServer
->text());
801 pref
->setMailNotificationSMTPSSL(m_ui
->checkSmtpSSL
->isChecked());
802 pref
->setMailNotificationSMTPAuth(m_ui
->groupMailNotifAuth
->isChecked());
803 pref
->setMailNotificationSMTPUsername(m_ui
->mailNotifUsername
->text());
804 pref
->setMailNotificationSMTPPassword(m_ui
->mailNotifPassword
->text());
806 pref
->setAutoRunOnTorrentAddedEnabled(m_ui
->groupBoxRunOnAdded
->isChecked());
807 pref
->setAutoRunOnTorrentAddedProgram(m_ui
->lineEditRunOnAdded
->text().trimmed());
808 pref
->setAutoRunOnTorrentFinishedEnabled(m_ui
->groupBoxRunOnFinished
->isChecked());
809 pref
->setAutoRunOnTorrentFinishedProgram(m_ui
->lineEditRunOnFinished
->text().trimmed());
810 #if defined(Q_OS_WIN)
811 pref
->setAutoRunConsoleEnabled(m_ui
->autoRunConsole
->isChecked());
815 void OptionsDialog::loadConnectionTabOptions()
817 const auto *session
= BitTorrent::Session::instance();
819 m_ui
->comboProtocol
->setCurrentIndex(static_cast<int>(session
->btProtocol()));
820 m_ui
->spinPort
->setValue(session
->port());
821 m_ui
->checkUPnP
->setChecked(Net::PortForwarder::instance()->isEnabled());
823 int intValue
= session
->maxConnections();
827 m_ui
->checkMaxConnections
->setChecked(true);
828 m_ui
->spinMaxConnec
->setEnabled(true);
829 m_ui
->spinMaxConnec
->setValue(intValue
);
834 m_ui
->checkMaxConnections
->setChecked(false);
835 m_ui
->spinMaxConnec
->setEnabled(false);
837 intValue
= session
->maxConnectionsPerTorrent();
841 m_ui
->checkMaxConnectionsPerTorrent
->setChecked(true);
842 m_ui
->spinMaxConnecPerTorrent
->setEnabled(true);
843 m_ui
->spinMaxConnecPerTorrent
->setValue(intValue
);
848 m_ui
->checkMaxConnectionsPerTorrent
->setChecked(false);
849 m_ui
->spinMaxConnecPerTorrent
->setEnabled(false);
851 intValue
= session
->maxUploads();
855 m_ui
->checkMaxUploads
->setChecked(true);
856 m_ui
->spinMaxUploads
->setEnabled(true);
857 m_ui
->spinMaxUploads
->setValue(intValue
);
862 m_ui
->checkMaxUploads
->setChecked(false);
863 m_ui
->spinMaxUploads
->setEnabled(false);
865 intValue
= session
->maxUploadsPerTorrent();
869 m_ui
->checkMaxUploadsPerTorrent
->setChecked(true);
870 m_ui
->spinMaxUploadsPerTorrent
->setEnabled(true);
871 m_ui
->spinMaxUploadsPerTorrent
->setValue(intValue
);
876 m_ui
->checkMaxUploadsPerTorrent
->setChecked(false);
877 m_ui
->spinMaxUploadsPerTorrent
->setEnabled(false);
880 #if defined(QBT_USES_LIBTORRENT2) && TORRENT_USE_I2P
881 m_ui
->textI2PHost
->setText(session
->I2PAddress());
882 m_ui
->spinI2PPort
->setValue(session
->I2PPort());
883 m_ui
->checkI2PMixed
->setChecked(session
->I2PMixedMode());
884 m_ui
->groupI2P
->setChecked(session
->isI2PEnabled());
886 m_ui
->groupI2P
->hide();
889 const auto *proxyConfigManager
= Net::ProxyConfigurationManager::instance();
890 const Net::ProxyConfiguration proxyConf
= proxyConfigManager
->proxyConfiguration();
892 m_ui
->comboProxyType
->addItem(tr("(None)"), QVariant::fromValue(Net::ProxyType::None
));
893 m_ui
->comboProxyType
->addItem(tr("SOCKS4"), QVariant::fromValue(Net::ProxyType::SOCKS4
));
894 m_ui
->comboProxyType
->addItem(tr("SOCKS5"), QVariant::fromValue(Net::ProxyType::SOCKS5
));
895 m_ui
->comboProxyType
->addItem(tr("HTTP"), QVariant::fromValue(Net::ProxyType::HTTP
));
896 m_ui
->comboProxyType
->setCurrentIndex(m_ui
->comboProxyType
->findData(QVariant::fromValue(proxyConf
.type
)));
897 adjustProxyOptions();
899 m_ui
->textProxyIP
->setText(proxyConf
.ip
);
900 m_ui
->spinProxyPort
->setValue(proxyConf
.port
);
901 m_ui
->textProxyUsername
->setText(proxyConf
.username
);
902 m_ui
->textProxyPassword
->setText(proxyConf
.password
);
903 m_ui
->checkProxyAuth
->setChecked(proxyConf
.authEnabled
);
904 m_ui
->checkProxyHostnameLookup
->setChecked(proxyConf
.hostnameLookupEnabled
);
906 m_ui
->checkProxyPeerConnections
->setChecked(session
->isProxyPeerConnectionsEnabled());
907 m_ui
->checkProxyBitTorrent
->setChecked(Preferences::instance()->useProxyForBT());
908 m_ui
->checkProxyRSS
->setChecked(Preferences::instance()->useProxyForRSS());
909 m_ui
->checkProxyMisc
->setChecked(Preferences::instance()->useProxyForGeneralPurposes());
911 m_ui
->checkIPFilter
->setChecked(session
->isIPFilteringEnabled());
912 m_ui
->textFilterPath
->setDialogCaption(tr("Choose an IP filter file"));
913 m_ui
->textFilterPath
->setEnabled(m_ui
->checkIPFilter
->isChecked());
914 m_ui
->textFilterPath
->setFileNameFilter(tr("All supported filters") + u
" (*.dat *.p2p *.p2b);;.dat (*.dat);;.p2p (*.p2p);;.p2b (*.p2b)");
915 m_ui
->textFilterPath
->setSelectedPath(session
->IPFilterFile());
917 m_ui
->IpFilterRefreshBtn
->setIcon(UIThemeManager::instance()->getIcon(u
"view-refresh"_s
));
918 m_ui
->IpFilterRefreshBtn
->setEnabled(m_ui
->checkIPFilter
->isChecked());
919 m_ui
->checkIpFilterTrackers
->setChecked(session
->isTrackerFilteringEnabled());
921 connect(m_ui
->comboProtocol
, qComboBoxCurrentIndexChanged
, this, &ThisType::enableApplyButton
);
922 connect(m_ui
->spinPort
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
923 connect(m_ui
->checkUPnP
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
925 connect(m_ui
->checkMaxConnections
, &QAbstractButton::toggled
, m_ui
->spinMaxConnec
, &QWidget::setEnabled
);
926 connect(m_ui
->checkMaxConnections
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
927 connect(m_ui
->checkMaxConnectionsPerTorrent
, &QAbstractButton::toggled
, m_ui
->spinMaxConnecPerTorrent
, &QWidget::setEnabled
);
928 connect(m_ui
->checkMaxConnectionsPerTorrent
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
929 connect(m_ui
->checkMaxUploads
, &QAbstractButton::toggled
, m_ui
->spinMaxUploads
, &QWidget::setEnabled
);
930 connect(m_ui
->checkMaxUploads
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
931 connect(m_ui
->checkMaxUploadsPerTorrent
, &QAbstractButton::toggled
, m_ui
->spinMaxUploadsPerTorrent
, &QWidget::setEnabled
);
932 connect(m_ui
->checkMaxUploadsPerTorrent
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
933 connect(m_ui
->spinMaxConnec
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
934 connect(m_ui
->spinMaxConnecPerTorrent
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
935 connect(m_ui
->spinMaxUploads
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
936 connect(m_ui
->spinMaxUploadsPerTorrent
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
938 connect(m_ui
->comboProxyType
, qComboBoxCurrentIndexChanged
, this, &ThisType::adjustProxyOptions
);
939 connect(m_ui
->comboProxyType
, qComboBoxCurrentIndexChanged
, this, &ThisType::enableApplyButton
);
940 connect(m_ui
->textProxyIP
, &QLineEdit::textChanged
, this, &ThisType::enableApplyButton
);
941 connect(m_ui
->spinProxyPort
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
943 #if defined(QBT_USES_LIBTORRENT2) && TORRENT_USE_I2P
944 connect(m_ui
->textI2PHost
, &QLineEdit::textChanged
, this, &ThisType::enableApplyButton
);
945 connect(m_ui
->spinI2PPort
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
946 connect(m_ui
->checkI2PMixed
, &QCheckBox::toggled
, this, &ThisType::enableApplyButton
);
947 connect(m_ui
->groupI2P
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
950 connect(m_ui
->checkProxyBitTorrent
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
951 connect(m_ui
->checkProxyBitTorrent
, &QGroupBox::toggled
, this, &ThisType::adjustProxyOptions
);
952 connect(m_ui
->checkProxyPeerConnections
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
953 connect(m_ui
->checkProxyHostnameLookup
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
954 connect(m_ui
->checkProxyRSS
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
955 connect(m_ui
->checkProxyMisc
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
957 connect(m_ui
->checkProxyAuth
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
958 connect(m_ui
->textProxyUsername
, &QLineEdit::textChanged
, this, &ThisType::enableApplyButton
);
959 connect(m_ui
->textProxyPassword
, &QLineEdit::textChanged
, this, &ThisType::enableApplyButton
);
961 connect(m_ui
->checkIPFilter
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
962 connect(m_ui
->checkIPFilter
, &QAbstractButton::toggled
, m_ui
->textFilterPath
, &QWidget::setEnabled
);
963 connect(m_ui
->checkIPFilter
, &QAbstractButton::toggled
, m_ui
->IpFilterRefreshBtn
, &QWidget::setEnabled
);
964 connect(m_ui
->textFilterPath
, &FileSystemPathEdit::selectedPathChanged
, this, &ThisType::enableApplyButton
);
965 connect(m_ui
->checkIpFilterTrackers
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
968 void OptionsDialog::saveConnectionTabOptions() const
970 auto *session
= BitTorrent::Session::instance();
972 session
->setBTProtocol(static_cast<BitTorrent::BTProtocol
>(m_ui
->comboProtocol
->currentIndex()));
973 session
->setPort(getPort());
974 Net::PortForwarder::instance()->setEnabled(isUPnPEnabled());
976 session
->setMaxConnections(getMaxConnections());
977 session
->setMaxConnectionsPerTorrent(getMaxConnectionsPerTorrent());
978 session
->setMaxUploads(getMaxUploads());
979 session
->setMaxUploadsPerTorrent(getMaxUploadsPerTorrent());
981 #if defined(QBT_USES_LIBTORRENT2) && TORRENT_USE_I2P
982 session
->setI2PEnabled(m_ui
->groupI2P
->isChecked());
983 session
->setI2PAddress(m_ui
->textI2PHost
->text().trimmed());
984 session
->setI2PPort(m_ui
->spinI2PPort
->value());
985 session
->setI2PMixedMode(m_ui
->checkI2PMixed
->isChecked());
988 auto *proxyConfigManager
= Net::ProxyConfigurationManager::instance();
989 Net::ProxyConfiguration proxyConf
;
990 proxyConf
.type
= getProxyType();
991 proxyConf
.ip
= getProxyIp();
992 proxyConf
.port
= getProxyPort();
993 proxyConf
.authEnabled
= m_ui
->checkProxyAuth
->isChecked();
994 proxyConf
.username
= getProxyUsername();
995 proxyConf
.password
= getProxyPassword();
996 proxyConf
.hostnameLookupEnabled
= m_ui
->checkProxyHostnameLookup
->isChecked();
997 proxyConfigManager
->setProxyConfiguration(proxyConf
);
999 Preferences::instance()->setUseProxyForBT(m_ui
->checkProxyBitTorrent
->isChecked());
1000 Preferences::instance()->setUseProxyForRSS(m_ui
->checkProxyRSS
->isChecked());
1001 Preferences::instance()->setUseProxyForGeneralPurposes(m_ui
->checkProxyMisc
->isChecked());
1003 session
->setProxyPeerConnectionsEnabled(m_ui
->checkProxyPeerConnections
->isChecked());
1006 session
->setIPFilteringEnabled(isIPFilteringEnabled());
1007 session
->setTrackerFilteringEnabled(m_ui
->checkIpFilterTrackers
->isChecked());
1008 session
->setIPFilterFile(m_ui
->textFilterPath
->selectedPath());
1011 void OptionsDialog::loadSpeedTabOptions()
1013 const auto *pref
= Preferences::instance();
1014 const auto *session
= BitTorrent::Session::instance();
1016 m_ui
->labelGlobalRate
->setPixmap(UIThemeManager::instance()->getScaledPixmap(u
"slow_off"_s
, Utils::Gui::mediumIconSize(this).height()));
1017 m_ui
->spinUploadLimit
->setValue(session
->globalUploadSpeedLimit() / 1024);
1018 m_ui
->spinDownloadLimit
->setValue(session
->globalDownloadSpeedLimit() / 1024);
1020 m_ui
->labelAltRate
->setPixmap(UIThemeManager::instance()->getScaledPixmap(u
"slow"_s
, Utils::Gui::mediumIconSize(this).height()));
1021 m_ui
->spinUploadLimitAlt
->setValue(session
->altGlobalUploadSpeedLimit() / 1024);
1022 m_ui
->spinDownloadLimitAlt
->setValue(session
->altGlobalDownloadSpeedLimit() / 1024);
1024 m_ui
->comboBoxScheduleDays
->addItems(translatedWeekdayNames());
1026 m_ui
->groupBoxSchedule
->setChecked(session
->isBandwidthSchedulerEnabled());
1027 m_ui
->timeEditScheduleFrom
->setTime(pref
->getSchedulerStartTime());
1028 m_ui
->timeEditScheduleTo
->setTime(pref
->getSchedulerEndTime());
1029 m_ui
->comboBoxScheduleDays
->setCurrentIndex(static_cast<int>(pref
->getSchedulerDays()));
1031 m_ui
->checkLimituTPConnections
->setChecked(session
->isUTPRateLimited());
1032 m_ui
->checkLimitTransportOverhead
->setChecked(session
->includeOverheadInLimits());
1033 m_ui
->checkLimitLocalPeerRate
->setChecked(!session
->ignoreLimitsOnLAN());
1035 connect(m_ui
->spinUploadLimit
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
1036 connect(m_ui
->spinDownloadLimit
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
1038 connect(m_ui
->spinUploadLimitAlt
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
1039 connect(m_ui
->spinDownloadLimitAlt
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
1041 connect(m_ui
->groupBoxSchedule
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
1042 connect(m_ui
->timeEditScheduleFrom
, &QDateTimeEdit::timeChanged
, this, &ThisType::enableApplyButton
);
1043 connect(m_ui
->timeEditScheduleTo
, &QDateTimeEdit::timeChanged
, this, &ThisType::enableApplyButton
);
1044 connect(m_ui
->comboBoxScheduleDays
, qComboBoxCurrentIndexChanged
, this, &ThisType::enableApplyButton
);
1046 connect(m_ui
->checkLimituTPConnections
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
1047 connect(m_ui
->checkLimitTransportOverhead
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
1048 connect(m_ui
->checkLimitLocalPeerRate
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
1051 void OptionsDialog::saveSpeedTabOptions() const
1053 auto *pref
= Preferences::instance();
1054 auto *session
= BitTorrent::Session::instance();
1056 session
->setGlobalUploadSpeedLimit(m_ui
->spinUploadLimit
->value() * 1024);
1057 session
->setGlobalDownloadSpeedLimit(m_ui
->spinDownloadLimit
->value() * 1024);
1059 session
->setAltGlobalUploadSpeedLimit(m_ui
->spinUploadLimitAlt
->value() * 1024);
1060 session
->setAltGlobalDownloadSpeedLimit(m_ui
->spinDownloadLimitAlt
->value() * 1024);
1062 session
->setBandwidthSchedulerEnabled(m_ui
->groupBoxSchedule
->isChecked());
1063 pref
->setSchedulerStartTime(m_ui
->timeEditScheduleFrom
->time());
1064 pref
->setSchedulerEndTime(m_ui
->timeEditScheduleTo
->time());
1065 pref
->setSchedulerDays(static_cast<Scheduler::Days
>(m_ui
->comboBoxScheduleDays
->currentIndex()));
1067 session
->setUTPRateLimited(m_ui
->checkLimituTPConnections
->isChecked());
1068 session
->setIncludeOverheadInLimits(m_ui
->checkLimitTransportOverhead
->isChecked());
1069 session
->setIgnoreLimitsOnLAN(!m_ui
->checkLimitLocalPeerRate
->isChecked());
1072 void OptionsDialog::loadBittorrentTabOptions()
1074 const auto *session
= BitTorrent::Session::instance();
1076 m_ui
->checkDHT
->setChecked(session
->isDHTEnabled());
1077 m_ui
->checkPeX
->setChecked(session
->isPeXEnabled());
1078 m_ui
->checkLSD
->setChecked(session
->isLSDEnabled());
1079 m_ui
->comboEncryption
->setCurrentIndex(session
->encryption());
1080 m_ui
->checkAnonymousMode
->setChecked(session
->isAnonymousModeEnabled());
1082 m_ui
->spinBoxMaxActiveCheckingTorrents
->setValue(session
->maxActiveCheckingTorrents());
1084 m_ui
->checkEnableQueueing
->setChecked(session
->isQueueingSystemEnabled());
1085 m_ui
->spinMaxActiveDownloads
->setValue(session
->maxActiveDownloads());
1086 m_ui
->spinMaxActiveUploads
->setValue(session
->maxActiveUploads());
1087 m_ui
->spinMaxActiveTorrents
->setValue(session
->maxActiveTorrents());
1089 m_ui
->checkIgnoreSlowTorrentsForQueueing
->setChecked(session
->ignoreSlowTorrentsForQueueing());
1090 const QString slowTorrentsExplanation
= u
"<html><body><p>"
1091 + tr("A torrent will be considered slow if its download and upload rates stay below these values for \"Torrent inactivity timer\" seconds")
1092 + u
"</p></body></html>";
1093 m_ui
->labelDownloadRateForSlowTorrents
->setToolTip(slowTorrentsExplanation
);
1094 m_ui
->labelUploadRateForSlowTorrents
->setToolTip(slowTorrentsExplanation
);
1095 m_ui
->labelSlowTorrentInactivityTimer
->setToolTip(slowTorrentsExplanation
);
1096 m_ui
->spinDownloadRateForSlowTorrents
->setValue(session
->downloadRateForSlowTorrents());
1097 m_ui
->spinUploadRateForSlowTorrents
->setValue(session
->uploadRateForSlowTorrents());
1098 m_ui
->spinSlowTorrentsInactivityTimer
->setValue(session
->slowTorrentsInactivityTimer());
1100 if (session
->globalMaxRatio() >= 0.)
1103 m_ui
->checkMaxRatio
->setChecked(true);
1104 m_ui
->spinMaxRatio
->setEnabled(true);
1105 m_ui
->comboRatioLimitAct
->setEnabled(true);
1106 m_ui
->spinMaxRatio
->setValue(session
->globalMaxRatio());
1111 m_ui
->checkMaxRatio
->setChecked(false);
1112 m_ui
->spinMaxRatio
->setEnabled(false);
1114 if (session
->globalMaxSeedingMinutes() >= 0)
1117 m_ui
->checkMaxSeedingMinutes
->setChecked(true);
1118 m_ui
->spinMaxSeedingMinutes
->setEnabled(true);
1119 m_ui
->spinMaxSeedingMinutes
->setValue(session
->globalMaxSeedingMinutes());
1124 m_ui
->checkMaxSeedingMinutes
->setChecked(false);
1125 m_ui
->spinMaxSeedingMinutes
->setEnabled(false);
1127 if (session
->globalMaxInactiveSeedingMinutes() >= 0)
1130 m_ui
->checkMaxInactiveSeedingMinutes
->setChecked(true);
1131 m_ui
->spinMaxInactiveSeedingMinutes
->setEnabled(true);
1132 m_ui
->spinMaxInactiveSeedingMinutes
->setValue(session
->globalMaxInactiveSeedingMinutes());
1137 m_ui
->checkMaxInactiveSeedingMinutes
->setChecked(false);
1138 m_ui
->spinMaxInactiveSeedingMinutes
->setEnabled(false);
1140 m_ui
->comboRatioLimitAct
->setEnabled((session
->globalMaxSeedingMinutes() >= 0) || (session
->globalMaxRatio() >= 0.) || (session
->globalMaxInactiveSeedingMinutes() >= 0));
1142 const QHash
<BitTorrent::ShareLimitAction
, int> actIndex
=
1144 {BitTorrent::ShareLimitAction::Stop
, 0},
1145 {BitTorrent::ShareLimitAction::Remove
, 1},
1146 {BitTorrent::ShareLimitAction::RemoveWithContent
, 2},
1147 {BitTorrent::ShareLimitAction::EnableSuperSeeding
, 3}
1149 m_ui
->comboRatioLimitAct
->setCurrentIndex(actIndex
.value(session
->shareLimitAction()));
1151 m_ui
->checkEnableAddTrackers
->setChecked(session
->isAddTrackersEnabled());
1152 m_ui
->textTrackers
->setPlainText(session
->additionalTrackers());
1154 connect(m_ui
->checkDHT
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
1155 connect(m_ui
->checkPeX
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
1156 connect(m_ui
->checkLSD
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
1157 connect(m_ui
->comboEncryption
, qComboBoxCurrentIndexChanged
, this, &ThisType::enableApplyButton
);
1158 connect(m_ui
->checkAnonymousMode
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
1160 connect(m_ui
->spinBoxMaxActiveCheckingTorrents
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
1162 connect(m_ui
->checkEnableQueueing
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
1163 connect(m_ui
->spinMaxActiveDownloads
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
1164 connect(m_ui
->spinMaxActiveUploads
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
1165 connect(m_ui
->spinMaxActiveTorrents
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
1166 connect(m_ui
->checkIgnoreSlowTorrentsForQueueing
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
1167 connect(m_ui
->spinDownloadRateForSlowTorrents
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
1168 connect(m_ui
->spinUploadRateForSlowTorrents
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
1169 connect(m_ui
->spinSlowTorrentsInactivityTimer
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
1171 connect(m_ui
->checkMaxRatio
, &QAbstractButton::toggled
, m_ui
->spinMaxRatio
, &QWidget::setEnabled
);
1172 connect(m_ui
->checkMaxRatio
, &QAbstractButton::toggled
, this, &ThisType::toggleComboRatioLimitAct
);
1173 connect(m_ui
->checkMaxRatio
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
1174 connect(m_ui
->spinMaxRatio
, qOverload
<double>(&QDoubleSpinBox::valueChanged
),this, &ThisType::enableApplyButton
);
1175 connect(m_ui
->comboRatioLimitAct
, qComboBoxCurrentIndexChanged
, this, &ThisType::enableApplyButton
);
1176 connect(m_ui
->checkMaxSeedingMinutes
, &QAbstractButton::toggled
, m_ui
->spinMaxSeedingMinutes
, &QWidget::setEnabled
);
1177 connect(m_ui
->checkMaxSeedingMinutes
, &QAbstractButton::toggled
, this, &ThisType::toggleComboRatioLimitAct
);
1178 connect(m_ui
->checkMaxSeedingMinutes
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
1179 connect(m_ui
->spinMaxSeedingMinutes
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
1180 connect(m_ui
->checkMaxInactiveSeedingMinutes
, &QAbstractButton::toggled
, m_ui
->spinMaxInactiveSeedingMinutes
, &QWidget::setEnabled
);
1181 connect(m_ui
->checkMaxInactiveSeedingMinutes
, &QAbstractButton::toggled
, this, &ThisType::toggleComboRatioLimitAct
);
1182 connect(m_ui
->checkMaxInactiveSeedingMinutes
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
1183 connect(m_ui
->spinMaxInactiveSeedingMinutes
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
1185 connect(m_ui
->checkEnableAddTrackers
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
1186 connect(m_ui
->textTrackers
, &QPlainTextEdit::textChanged
, this, &ThisType::enableApplyButton
);
1189 void OptionsDialog::saveBittorrentTabOptions() const
1191 auto *session
= BitTorrent::Session::instance();
1193 session
->setDHTEnabled(isDHTEnabled());
1194 session
->setPeXEnabled(m_ui
->checkPeX
->isChecked());
1195 session
->setLSDEnabled(isLSDEnabled());
1196 session
->setEncryption(getEncryptionSetting());
1197 session
->setAnonymousModeEnabled(m_ui
->checkAnonymousMode
->isChecked());
1199 session
->setMaxActiveCheckingTorrents(m_ui
->spinBoxMaxActiveCheckingTorrents
->value());
1201 session
->setQueueingSystemEnabled(isQueueingSystemEnabled());
1202 session
->setMaxActiveDownloads(m_ui
->spinMaxActiveDownloads
->value());
1203 session
->setMaxActiveUploads(m_ui
->spinMaxActiveUploads
->value());
1204 session
->setMaxActiveTorrents(m_ui
->spinMaxActiveTorrents
->value());
1205 session
->setIgnoreSlowTorrentsForQueueing(m_ui
->checkIgnoreSlowTorrentsForQueueing
->isChecked());
1206 session
->setDownloadRateForSlowTorrents(m_ui
->spinDownloadRateForSlowTorrents
->value());
1207 session
->setUploadRateForSlowTorrents(m_ui
->spinUploadRateForSlowTorrents
->value());
1208 session
->setSlowTorrentsInactivityTimer(m_ui
->spinSlowTorrentsInactivityTimer
->value());
1210 session
->setGlobalMaxRatio(getMaxRatio());
1211 session
->setGlobalMaxSeedingMinutes(getMaxSeedingMinutes());
1212 session
->setGlobalMaxInactiveSeedingMinutes(getMaxInactiveSeedingMinutes());
1213 const QList
<BitTorrent::ShareLimitAction
> actIndex
=
1215 BitTorrent::ShareLimitAction::Stop
,
1216 BitTorrent::ShareLimitAction::Remove
,
1217 BitTorrent::ShareLimitAction::RemoveWithContent
,
1218 BitTorrent::ShareLimitAction::EnableSuperSeeding
1220 session
->setShareLimitAction(actIndex
.value(m_ui
->comboRatioLimitAct
->currentIndex()));
1222 session
->setAddTrackersEnabled(m_ui
->checkEnableAddTrackers
->isChecked());
1223 session
->setAdditionalTrackers(m_ui
->textTrackers
->toPlainText());
1226 void OptionsDialog::loadRSSTabOptions()
1228 const auto *rssSession
= RSS::Session::instance();
1229 const auto *autoDownloader
= RSS::AutoDownloader::instance();
1231 m_ui
->checkRSSEnable
->setChecked(rssSession
->isProcessingEnabled());
1232 m_ui
->spinRSSRefreshInterval
->setValue(rssSession
->refreshInterval());
1233 m_ui
->spinRSSFetchDelay
->setValue(rssSession
->fetchDelay().count());
1234 m_ui
->spinRSSMaxArticlesPerFeed
->setValue(rssSession
->maxArticlesPerFeed());
1235 m_ui
->checkRSSAutoDownloaderEnable
->setChecked(autoDownloader
->isProcessingEnabled());
1236 m_ui
->textSmartEpisodeFilters
->setPlainText(autoDownloader
->smartEpisodeFilters().join(u
'\n'));
1237 m_ui
->checkSmartFilterDownloadRepacks
->setChecked(autoDownloader
->downloadRepacks());
1239 connect(m_ui
->checkRSSEnable
, &QCheckBox::toggled
, this, &OptionsDialog::enableApplyButton
);
1240 connect(m_ui
->checkRSSAutoDownloaderEnable
, &QCheckBox::toggled
, this, &OptionsDialog::enableApplyButton
);
1241 connect(m_ui
->btnEditRules
, &QPushButton::clicked
, this, [this]()
1243 auto *downloader
= new AutomatedRssDownloader(this);
1244 downloader
->setAttribute(Qt::WA_DeleteOnClose
);
1247 connect(m_ui
->textSmartEpisodeFilters
, &QPlainTextEdit::textChanged
, this, &OptionsDialog::enableApplyButton
);
1248 connect(m_ui
->checkSmartFilterDownloadRepacks
, &QCheckBox::toggled
, this, &OptionsDialog::enableApplyButton
);
1249 connect(m_ui
->spinRSSRefreshInterval
, qSpinBoxValueChanged
, this, &OptionsDialog::enableApplyButton
);
1250 connect(m_ui
->spinRSSFetchDelay
, qSpinBoxValueChanged
, this, &OptionsDialog::enableApplyButton
);
1251 connect(m_ui
->spinRSSMaxArticlesPerFeed
, qSpinBoxValueChanged
, this, &OptionsDialog::enableApplyButton
);
1254 void OptionsDialog::saveRSSTabOptions() const
1256 auto *rssSession
= RSS::Session::instance();
1257 auto *autoDownloader
= RSS::AutoDownloader::instance();
1259 rssSession
->setProcessingEnabled(m_ui
->checkRSSEnable
->isChecked());
1260 rssSession
->setRefreshInterval(m_ui
->spinRSSRefreshInterval
->value());
1261 rssSession
->setFetchDelay(std::chrono::seconds(m_ui
->spinRSSFetchDelay
->value()));
1262 rssSession
->setMaxArticlesPerFeed(m_ui
->spinRSSMaxArticlesPerFeed
->value());
1263 autoDownloader
->setProcessingEnabled(m_ui
->checkRSSAutoDownloaderEnable
->isChecked());
1264 autoDownloader
->setSmartEpisodeFilters(m_ui
->textSmartEpisodeFilters
->toPlainText().split(u
'\n', Qt::SkipEmptyParts
));
1265 autoDownloader
->setDownloadRepacks(m_ui
->checkSmartFilterDownloadRepacks
->isChecked());
1268 #ifndef DISABLE_WEBUI
1269 void OptionsDialog::loadWebUITabOptions()
1271 const auto *pref
= Preferences::instance();
1273 m_ui
->textWebUIHttpsCert
->setMode(FileSystemPathEdit::Mode::FileOpen
);
1274 m_ui
->textWebUIHttpsCert
->setFileNameFilter(tr("Certificate") + u
" (*.cer *.crt *.pem)");
1275 m_ui
->textWebUIHttpsCert
->setDialogCaption(tr("Select certificate"));
1276 m_ui
->textWebUIHttpsKey
->setMode(FileSystemPathEdit::Mode::FileOpen
);
1277 m_ui
->textWebUIHttpsKey
->setFileNameFilter(tr("Private key") + u
" (*.key *.pem)");
1278 m_ui
->textWebUIHttpsKey
->setDialogCaption(tr("Select private key"));
1279 m_ui
->textWebUIRootFolder
->setMode(FileSystemPathEdit::Mode::DirectoryOpen
);
1280 m_ui
->textWebUIRootFolder
->setDialogCaption(tr("Choose Alternative UI files location"));
1282 if (app()->webUI()->isErrored())
1283 m_ui
->labelWebUIError
->setText(tr("WebUI configuration failed. Reason: %1").arg(app()->webUI()->errorMessage()));
1285 m_ui
->labelWebUIError
->hide();
1287 m_ui
->checkWebUI
->setChecked(pref
->isWebUIEnabled());
1288 m_ui
->textWebUIAddress
->setText(pref
->getWebUIAddress());
1289 m_ui
->spinWebUIPort
->setValue(pref
->getWebUIPort());
1290 m_ui
->checkWebUIUPnP
->setChecked(pref
->useUPnPForWebUIPort());
1291 m_ui
->checkWebUIHttps
->setChecked(pref
->isWebUIHttpsEnabled());
1292 webUIHttpsCertChanged(pref
->getWebUIHttpsCertificatePath());
1293 webUIHttpsKeyChanged(pref
->getWebUIHttpsKeyPath());
1294 m_ui
->textWebUIUsername
->setText(pref
->getWebUIUsername());
1295 m_ui
->checkBypassLocalAuth
->setChecked(!pref
->isWebUILocalAuthEnabled());
1296 m_ui
->checkBypassAuthSubnetWhitelist
->setChecked(pref
->isWebUIAuthSubnetWhitelistEnabled());
1297 m_ui
->IPSubnetWhitelistButton
->setEnabled(m_ui
->checkBypassAuthSubnetWhitelist
->isChecked());
1298 m_ui
->spinBanCounter
->setValue(pref
->getWebUIMaxAuthFailCount());
1299 m_ui
->spinBanDuration
->setValue(pref
->getWebUIBanDuration().count());
1300 m_ui
->spinSessionTimeout
->setValue(pref
->getWebUISessionTimeout());
1302 m_ui
->groupAltWebUI
->setChecked(pref
->isAltWebUIEnabled());
1303 m_ui
->textWebUIRootFolder
->setSelectedPath(pref
->getWebUIRootFolder());
1305 m_ui
->checkClickjacking
->setChecked(pref
->isWebUIClickjackingProtectionEnabled());
1306 m_ui
->checkCSRFProtection
->setChecked(pref
->isWebUICSRFProtectionEnabled());
1307 m_ui
->checkSecureCookie
->setChecked(pref
->isWebUISecureCookieEnabled());
1308 m_ui
->groupHostHeaderValidation
->setChecked(pref
->isWebUIHostHeaderValidationEnabled());
1309 m_ui
->textServerDomains
->setText(pref
->getServerDomains());
1310 // Custom HTTP headers
1311 m_ui
->groupWebUIAddCustomHTTPHeaders
->setChecked(pref
->isWebUICustomHTTPHeadersEnabled());
1312 m_ui
->textWebUICustomHTTPHeaders
->setPlainText(pref
->getWebUICustomHTTPHeaders());
1314 m_ui
->groupEnableReverseProxySupport
->setChecked(pref
->isWebUIReverseProxySupportEnabled());
1315 m_ui
->textTrustedReverseProxiesList
->setText(pref
->getWebUITrustedReverseProxiesList());
1317 m_ui
->checkDynDNS
->setChecked(pref
->isDynDNSEnabled());
1318 m_ui
->comboDNSService
->setCurrentIndex(static_cast<int>(pref
->getDynDNSService()));
1319 m_ui
->domainNameTxt
->setText(pref
->getDynDomainName());
1320 m_ui
->DNSUsernameTxt
->setText(pref
->getDynDNSUsername());
1321 m_ui
->DNSPasswordTxt
->setText(pref
->getDynDNSPassword());
1323 connect(m_ui
->checkWebUI
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
1324 connect(m_ui
->textWebUIAddress
, &QLineEdit::textChanged
, this, &ThisType::enableApplyButton
);
1325 connect(m_ui
->spinWebUIPort
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
1326 connect(m_ui
->checkWebUIUPnP
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
1327 connect(m_ui
->checkWebUIHttps
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
1328 connect(m_ui
->textWebUIHttpsCert
, &FileSystemPathLineEdit::selectedPathChanged
, this, &ThisType::enableApplyButton
);
1329 connect(m_ui
->textWebUIHttpsCert
, &FileSystemPathLineEdit::selectedPathChanged
, this, &OptionsDialog::webUIHttpsCertChanged
);
1330 connect(m_ui
->textWebUIHttpsKey
, &FileSystemPathLineEdit::selectedPathChanged
, this, &ThisType::enableApplyButton
);
1331 connect(m_ui
->textWebUIHttpsKey
, &FileSystemPathLineEdit::selectedPathChanged
, this, &OptionsDialog::webUIHttpsKeyChanged
);
1333 connect(m_ui
->textWebUIUsername
, &QLineEdit::textChanged
, this, &ThisType::enableApplyButton
);
1334 connect(m_ui
->textWebUIPassword
, &QLineEdit::textChanged
, this, &ThisType::enableApplyButton
);
1336 connect(m_ui
->checkBypassLocalAuth
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
1337 connect(m_ui
->checkBypassAuthSubnetWhitelist
, &QAbstractButton::toggled
, this, &ThisType::enableApplyButton
);
1338 connect(m_ui
->checkBypassAuthSubnetWhitelist
, &QAbstractButton::toggled
, m_ui
->IPSubnetWhitelistButton
, &QWidget::setEnabled
);
1339 connect(m_ui
->spinBanCounter
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
1340 connect(m_ui
->spinBanDuration
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
1341 connect(m_ui
->spinSessionTimeout
, qSpinBoxValueChanged
, this, &ThisType::enableApplyButton
);
1343 connect(m_ui
->groupAltWebUI
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
1344 connect(m_ui
->textWebUIRootFolder
, &FileSystemPathLineEdit::selectedPathChanged
, this, &ThisType::enableApplyButton
);
1346 connect(m_ui
->checkClickjacking
, &QCheckBox::toggled
, this, &ThisType::enableApplyButton
);
1347 connect(m_ui
->checkCSRFProtection
, &QCheckBox::toggled
, this, &ThisType::enableApplyButton
);
1348 connect(m_ui
->checkSecureCookie
, &QCheckBox::toggled
, this, &ThisType::enableApplyButton
);
1349 connect(m_ui
->groupHostHeaderValidation
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
1350 connect(m_ui
->textServerDomains
, &QLineEdit::textChanged
, this, &ThisType::enableApplyButton
);
1352 connect(m_ui
->groupWebUIAddCustomHTTPHeaders
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
1353 connect(m_ui
->textWebUICustomHTTPHeaders
, &QPlainTextEdit::textChanged
, this, &OptionsDialog::enableApplyButton
);
1355 connect(m_ui
->groupEnableReverseProxySupport
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
1356 connect(m_ui
->textTrustedReverseProxiesList
, &QLineEdit::textChanged
, this, &ThisType::enableApplyButton
);
1358 connect(m_ui
->checkDynDNS
, &QGroupBox::toggled
, this, &ThisType::enableApplyButton
);
1359 connect(m_ui
->comboDNSService
, qComboBoxCurrentIndexChanged
, this, &ThisType::enableApplyButton
);
1360 connect(m_ui
->domainNameTxt
, &QLineEdit::textChanged
, this, &ThisType::enableApplyButton
);
1361 connect(m_ui
->DNSUsernameTxt
, &QLineEdit::textChanged
, this, &ThisType::enableApplyButton
);
1362 connect(m_ui
->DNSPasswordTxt
, &QLineEdit::textChanged
, this, &ThisType::enableApplyButton
);
1365 void OptionsDialog::saveWebUITabOptions() const
1367 auto *pref
= Preferences::instance();
1369 const bool webUIEnabled
= isWebUIEnabled();
1371 pref
->setWebUIEnabled(webUIEnabled
);
1372 pref
->setWebUIAddress(m_ui
->textWebUIAddress
->text());
1373 pref
->setWebUIPort(m_ui
->spinWebUIPort
->value());
1374 pref
->setUPnPForWebUIPort(m_ui
->checkWebUIUPnP
->isChecked());
1375 pref
->setWebUIHttpsEnabled(m_ui
->checkWebUIHttps
->isChecked());
1376 pref
->setWebUIHttpsCertificatePath(m_ui
->textWebUIHttpsCert
->selectedPath());
1377 pref
->setWebUIHttpsKeyPath(m_ui
->textWebUIHttpsKey
->selectedPath());
1378 pref
->setWebUIMaxAuthFailCount(m_ui
->spinBanCounter
->value());
1379 pref
->setWebUIBanDuration(std::chrono::seconds
{m_ui
->spinBanDuration
->value()});
1380 pref
->setWebUISessionTimeout(m_ui
->spinSessionTimeout
->value());
1382 if (const QString username
= webUIUsername(); isValidWebUIUsername(username
))
1383 pref
->setWebUIUsername(username
);
1384 if (const QString password
= webUIPassword(); isValidWebUIPassword(password
))
1385 pref
->setWebUIPassword(Utils::Password::PBKDF2::generate(password
));
1386 pref
->setWebUILocalAuthEnabled(!m_ui
->checkBypassLocalAuth
->isChecked());
1387 pref
->setWebUIAuthSubnetWhitelistEnabled(m_ui
->checkBypassAuthSubnetWhitelist
->isChecked());
1389 pref
->setAltWebUIEnabled(m_ui
->groupAltWebUI
->isChecked());
1390 pref
->setWebUIRootFolder(m_ui
->textWebUIRootFolder
->selectedPath());
1392 pref
->setWebUIClickjackingProtectionEnabled(m_ui
->checkClickjacking
->isChecked());
1393 pref
->setWebUICSRFProtectionEnabled(m_ui
->checkCSRFProtection
->isChecked());
1394 pref
->setWebUISecureCookieEnabled(m_ui
->checkSecureCookie
->isChecked());
1395 pref
->setWebUIHostHeaderValidationEnabled(m_ui
->groupHostHeaderValidation
->isChecked());
1396 pref
->setServerDomains(m_ui
->textServerDomains
->text());
1397 // Custom HTTP headers
1398 pref
->setWebUICustomHTTPHeadersEnabled(m_ui
->groupWebUIAddCustomHTTPHeaders
->isChecked());
1399 pref
->setWebUICustomHTTPHeaders(m_ui
->textWebUICustomHTTPHeaders
->toPlainText());
1401 pref
->setWebUIReverseProxySupportEnabled(m_ui
->groupEnableReverseProxySupport
->isChecked());
1402 pref
->setWebUITrustedReverseProxiesList(m_ui
->textTrustedReverseProxiesList
->text());
1404 pref
->setDynDNSEnabled(m_ui
->checkDynDNS
->isChecked());
1405 pref
->setDynDNSService(static_cast<DNS::Service
>(m_ui
->comboDNSService
->currentIndex()));
1406 pref
->setDynDomainName(m_ui
->domainNameTxt
->text());
1407 pref
->setDynDNSUsername(m_ui
->DNSUsernameTxt
->text());
1408 pref
->setDynDNSPassword(m_ui
->DNSPasswordTxt
->text());
1410 #endif // DISABLE_WEBUI
1412 void OptionsDialog::initializeLanguageCombo()
1414 // List language files
1415 const QStringList langFiles
= QDir(u
":/lang"_s
).entryList({u
"qbittorrent_*.qm"_s
}, QDir::Files
, QDir::Name
);
1416 for (const QString
&langFile
: langFiles
)
1418 const QString langCode
= QStringView(langFile
).sliced(12).chopped(3).toString(); // remove "qbittorrent_" and ".qm"
1419 m_ui
->comboLanguage
->addItem(Utils::Misc::languageToLocalizedString(langCode
), langCode
);
1423 void OptionsDialog::changePage(QListWidgetItem
*current
, QListWidgetItem
*previous
)
1427 m_ui
->tabOption
->setCurrentIndex(m_ui
->tabSelection
->row(current
));
1430 void OptionsDialog::loadSplitterState()
1432 // width has been modified, use height as width reference instead
1433 const int width
= m_ui
->tabSelection
->item(TAB_UI
)->sizeHint().height() * 2;
1434 const QStringList defaultSizes
= {QString::number(width
), QString::number(m_ui
->hsplitter
->width() - width
)};
1436 QList
<int> splitterSizes
;
1437 for (const QString
&string
: asConst(m_storeHSplitterSize
.get(defaultSizes
)))
1438 splitterSizes
.append(string
.toInt());
1440 m_ui
->hsplitter
->setSizes(splitterSizes
);
1443 void OptionsDialog::showEvent(QShowEvent
*e
)
1445 QDialog::showEvent(e
);
1447 loadSplitterState();
1450 void OptionsDialog::saveOptions() const
1452 auto *pref
= Preferences::instance();
1454 saveBehaviorTabOptions();
1455 saveDownloadsTabOptions();
1456 saveConnectionTabOptions();
1457 saveSpeedTabOptions();
1458 saveBittorrentTabOptions();
1459 saveRSSTabOptions();
1460 #ifndef DISABLE_WEBUI
1461 saveWebUITabOptions();
1463 m_advancedSettings
->saveAdvancedSettings();
1465 // Assume that user changed multiple settings
1466 // so it's best to save immediately
1470 bool OptionsDialog::isIPFilteringEnabled() const
1472 return m_ui
->checkIPFilter
->isChecked();
1475 Net::ProxyType
OptionsDialog::getProxyType() const
1477 return m_ui
->comboProxyType
->currentData().value
<Net::ProxyType
>();
1480 int OptionsDialog::getPort() const
1482 return m_ui
->spinPort
->value();
1485 void OptionsDialog::on_randomButton_clicked()
1487 // Range [1024: 65535]
1488 m_ui
->spinPort
->setValue(Utils::Random::rand(1024, 65535));
1491 int OptionsDialog::getEncryptionSetting() const
1493 return m_ui
->comboEncryption
->currentIndex();
1496 int OptionsDialog::getMaxActiveDownloads() const
1498 return m_ui
->spinMaxActiveDownloads
->value();
1501 int OptionsDialog::getMaxActiveUploads() const
1503 return m_ui
->spinMaxActiveUploads
->value();
1506 int OptionsDialog::getMaxActiveTorrents() const
1508 return m_ui
->spinMaxActiveTorrents
->value();
1511 bool OptionsDialog::isQueueingSystemEnabled() const
1513 return m_ui
->checkEnableQueueing
->isChecked();
1516 bool OptionsDialog::isDHTEnabled() const
1518 return m_ui
->checkDHT
->isChecked();
1521 bool OptionsDialog::isLSDEnabled() const
1523 return m_ui
->checkLSD
->isChecked();
1526 bool OptionsDialog::isUPnPEnabled() const
1528 return m_ui
->checkUPnP
->isChecked();
1531 // Return Share ratio
1532 qreal
OptionsDialog::getMaxRatio() const
1534 if (m_ui
->checkMaxRatio
->isChecked())
1535 return m_ui
->spinMaxRatio
->value();
1539 // Return Seeding Minutes
1540 int OptionsDialog::getMaxSeedingMinutes() const
1542 if (m_ui
->checkMaxSeedingMinutes
->isChecked())
1543 return m_ui
->spinMaxSeedingMinutes
->value();
1547 // Return Inactive Seeding Minutes
1548 int OptionsDialog::getMaxInactiveSeedingMinutes() const
1550 return m_ui
->checkMaxInactiveSeedingMinutes
->isChecked()
1551 ? m_ui
->spinMaxInactiveSeedingMinutes
->value()
1555 // Return max connections number
1556 int OptionsDialog::getMaxConnections() const
1558 if (!m_ui
->checkMaxConnections
->isChecked())
1561 return m_ui
->spinMaxConnec
->value();
1564 int OptionsDialog::getMaxConnectionsPerTorrent() const
1566 if (!m_ui
->checkMaxConnectionsPerTorrent
->isChecked())
1569 return m_ui
->spinMaxConnecPerTorrent
->value();
1572 int OptionsDialog::getMaxUploads() const
1574 if (!m_ui
->checkMaxUploads
->isChecked())
1577 return m_ui
->spinMaxUploads
->value();
1580 int OptionsDialog::getMaxUploadsPerTorrent() const
1582 if (!m_ui
->checkMaxUploadsPerTorrent
->isChecked())
1585 return m_ui
->spinMaxUploadsPerTorrent
->value();
1588 void OptionsDialog::on_buttonBox_accepted()
1590 if (m_applyButton
->isEnabled())
1592 if (!applySettings())
1595 m_applyButton
->setEnabled(false);
1601 bool OptionsDialog::applySettings()
1603 if (!schedTimesOk())
1605 m_ui
->tabSelection
->setCurrentRow(TAB_SPEED
);
1608 #ifndef DISABLE_WEBUI
1609 if (isWebUIEnabled() && !webUIAuthenticationOk())
1611 m_ui
->tabSelection
->setCurrentRow(TAB_WEBUI
);
1614 if (!isAlternativeWebUIPathValid())
1616 m_ui
->tabSelection
->setCurrentRow(TAB_WEBUI
);
1625 void OptionsDialog::on_buttonBox_rejected()
1630 bool OptionsDialog::useAdditionDialog() const
1632 return m_ui
->checkAdditionDialog
->isChecked();
1635 void OptionsDialog::enableApplyButton()
1637 m_applyButton
->setEnabled(true);
1640 void OptionsDialog::toggleComboRatioLimitAct()
1642 // Verify if the share action button must be enabled
1643 m_ui
->comboRatioLimitAct
->setEnabled(m_ui
->checkMaxRatio
->isChecked() || m_ui
->checkMaxSeedingMinutes
->isChecked() || m_ui
->checkMaxInactiveSeedingMinutes
->isChecked());
1646 void OptionsDialog::adjustProxyOptions()
1648 const auto currentProxyType
= m_ui
->comboProxyType
->currentData().value
<Net::ProxyType
>();
1649 const bool isAuthSupported
= ((currentProxyType
== Net::ProxyType::SOCKS5
)
1650 || (currentProxyType
== Net::ProxyType::HTTP
));
1652 m_ui
->checkProxyAuth
->setEnabled(isAuthSupported
);
1654 if (currentProxyType
== Net::ProxyType::None
)
1656 m_ui
->labelProxyTypeIncompatible
->setVisible(false);
1658 m_ui
->lblProxyIP
->setEnabled(false);
1659 m_ui
->textProxyIP
->setEnabled(false);
1660 m_ui
->lblProxyPort
->setEnabled(false);
1661 m_ui
->spinProxyPort
->setEnabled(false);
1663 m_ui
->checkProxyHostnameLookup
->setEnabled(false);
1664 m_ui
->checkProxyRSS
->setEnabled(false);
1665 m_ui
->checkProxyMisc
->setEnabled(false);
1666 m_ui
->checkProxyBitTorrent
->setEnabled(false);
1667 m_ui
->checkProxyPeerConnections
->setEnabled(false);
1671 m_ui
->lblProxyIP
->setEnabled(true);
1672 m_ui
->textProxyIP
->setEnabled(true);
1673 m_ui
->lblProxyPort
->setEnabled(true);
1674 m_ui
->spinProxyPort
->setEnabled(true);
1676 m_ui
->checkProxyBitTorrent
->setEnabled(true);
1677 m_ui
->checkProxyPeerConnections
->setEnabled(true);
1679 if (currentProxyType
== Net::ProxyType::SOCKS4
)
1681 m_ui
->labelProxyTypeIncompatible
->setVisible(true);
1683 m_ui
->checkProxyHostnameLookup
->setEnabled(false);
1684 m_ui
->checkProxyRSS
->setEnabled(false);
1685 m_ui
->checkProxyMisc
->setEnabled(false);
1690 m_ui
->labelProxyTypeIncompatible
->setVisible(false);
1692 m_ui
->checkProxyHostnameLookup
->setEnabled(true);
1693 m_ui
->checkProxyRSS
->setEnabled(true);
1694 m_ui
->checkProxyMisc
->setEnabled(true);
1699 bool OptionsDialog::isSplashScreenDisabled() const
1701 return !m_ui
->checkShowSplash
->isChecked();
1704 void OptionsDialog::initializeStyleCombo()
1707 m_ui
->labelStyleHint
->setText(tr("%1 is recommended for best compatibility with Windows dark mode"
1708 , "Fusion is recommended for best compatibility with Windows dark mode").arg(u
"Fusion"_s
));
1709 m_ui
->comboStyle
->addItem(tr("System", "System default Qt style"), u
"system"_s
);
1710 m_ui
->comboStyle
->setItemData(0, tr("Let Qt decide the style for this system"), Qt::ToolTipRole
);
1711 m_ui
->comboStyle
->insertSeparator(1);
1713 QStringList styleNames
= QStyleFactory::keys();
1714 std::sort(styleNames
.begin(), styleNames
.end(), Utils::Compare::NaturalLessThan
<Qt::CaseInsensitive
>());
1715 m_ui
->comboStyle
->addItems(styleNames
);
1717 const QString prefStyleName
= Preferences::instance()->getStyle();
1718 const QString selectedStyleName
= prefStyleName
.isEmpty() ? QApplication::style()->name() : prefStyleName
;
1719 m_ui
->comboStyle
->setCurrentIndex(m_ui
->comboStyle
->findText(selectedStyleName
, Qt::MatchFixedString
));
1721 m_ui
->labelStyle
->hide();
1722 m_ui
->comboStyle
->hide();
1723 m_ui
->labelStyleHint
->hide();
1724 m_ui
->UISettingsBoxLayout
->removeWidget(m_ui
->labelStyle
);
1725 m_ui
->UISettingsBoxLayout
->removeWidget(m_ui
->comboStyle
);
1726 m_ui
->UISettingsBoxLayout
->removeWidget(m_ui
->labelStyleHint
);
1730 void OptionsDialog::initializeColorSchemeOptions()
1732 #ifdef QBT_HAS_COLORSCHEME_OPTION
1733 m_ui
->comboColorScheme
->addItem(tr("Dark", "Dark color scheme"), QVariant::fromValue(ColorScheme::Dark
));
1734 m_ui
->comboColorScheme
->addItem(tr("Light", "Light color scheme"), QVariant::fromValue(ColorScheme::Light
));
1735 m_ui
->comboColorScheme
->addItem(tr("System", "System color scheme"), QVariant::fromValue(ColorScheme::System
));
1736 m_ui
->comboColorScheme
->setCurrentIndex(m_ui
->comboColorScheme
->findData(QVariant::fromValue(UIThemeManager::instance()->colorScheme())));
1738 m_ui
->labelColorScheme
->hide();
1739 m_ui
->comboColorScheme
->hide();
1740 m_ui
->UISettingsBoxLayout
->removeWidget(m_ui
->labelColorScheme
);
1741 m_ui
->UISettingsBoxLayout
->removeWidget(m_ui
->comboColorScheme
);
1742 m_ui
->UISettingsBoxLayout
->removeItem(m_ui
->spacerColorScheme
);
1747 bool OptionsDialog::WinStartup() const
1749 return m_ui
->checkStartup
->isChecked();
1753 bool OptionsDialog::preAllocateAllFiles() const
1755 return m_ui
->checkPreallocateAll
->isChecked();
1758 bool OptionsDialog::addTorrentsStopped() const
1760 return m_ui
->checkAddStopped
->isChecked();
1764 bool OptionsDialog::isProxyEnabled() const
1766 return m_ui
->comboProxyType
->currentIndex();
1769 QString
OptionsDialog::getProxyIp() const
1771 return m_ui
->textProxyIP
->text().trimmed();
1774 unsigned short OptionsDialog::getProxyPort() const
1776 return m_ui
->spinProxyPort
->value();
1779 QString
OptionsDialog::getProxyUsername() const
1781 QString username
= m_ui
->textProxyUsername
->text().trimmed();
1785 QString
OptionsDialog::getProxyPassword() const
1787 QString password
= m_ui
->textProxyPassword
->text();
1788 password
= password
.trimmed();
1793 QString
OptionsDialog::getLocale() const
1795 return m_ui
->comboLanguage
->itemData(m_ui
->comboLanguage
->currentIndex(), Qt::UserRole
).toString();
1798 void OptionsDialog::setLocale(const QString
&localeStr
)
1801 if (localeStr
.startsWith(u
"eo", Qt::CaseInsensitive
))
1805 else if (localeStr
.startsWith(u
"ltg", Qt::CaseInsensitive
))
1811 QLocale
locale(localeStr
);
1812 if (locale
.language() == QLocale::Uzbek
)
1813 name
= u
"uz@Latn"_s
;
1814 else if (locale
.language() == QLocale::Azerbaijani
)
1815 name
= u
"az@latin"_s
;
1817 name
= locale
.name();
1819 // Attempt to find exact match
1820 int index
= m_ui
->comboLanguage
->findData(name
, Qt::UserRole
);
1823 //Attempt to find a language match without a country
1824 int pos
= name
.indexOf(u
'_');
1827 QString lang
= name
.left(pos
);
1828 index
= m_ui
->comboLanguage
->findData(lang
, Qt::UserRole
);
1833 // Unrecognized, use US English
1834 index
= m_ui
->comboLanguage
->findData(u
"en"_s
, Qt::UserRole
);
1835 Q_ASSERT(index
>= 0);
1837 m_ui
->comboLanguage
->setCurrentIndex(index
);
1840 Path
OptionsDialog::getTorrentExportDir() const
1842 if (m_ui
->checkExportDir
->isChecked())
1843 return m_ui
->textExportDir
->selectedPath();
1847 Path
OptionsDialog::getFinishedTorrentExportDir() const
1849 if (m_ui
->checkExportDirFin
->isChecked())
1850 return m_ui
->textExportDirFin
->selectedPath();
1854 void OptionsDialog::on_addWatchedFolderButton_clicked()
1856 Preferences
*const pref
= Preferences::instance();
1857 const Path dir
{QFileDialog::getExistingDirectory(
1858 this, tr("Select folder to monitor"), pref
->getScanDirsLastPath().parentPath().toString())};
1862 auto *dialog
= new WatchedFolderOptionsDialog({}, this);
1863 dialog
->setAttribute(Qt::WA_DeleteOnClose
);
1864 connect(dialog
, &QDialog::accepted
, this, [this, dialog
, dir
, pref
]()
1868 auto *watchedFoldersModel
= static_cast<WatchedFoldersModel
*>(m_ui
->scanFoldersView
->model());
1869 watchedFoldersModel
->addFolder(dir
, dialog
->watchedFolderOptions());
1871 pref
->setScanDirsLastPath(dir
);
1873 for (int i
= 0; i
< watchedFoldersModel
->columnCount(); ++i
)
1874 m_ui
->scanFoldersView
->resizeColumnToContents(i
);
1876 enableApplyButton();
1878 catch (const RuntimeError
&err
)
1880 QMessageBox::critical(this, tr("Adding entry failed"), err
.message());
1887 void OptionsDialog::on_editWatchedFolderButton_clicked()
1889 const QModelIndex selected
1890 = m_ui
->scanFoldersView
->selectionModel()->selectedIndexes().at(0);
1892 editWatchedFolderOptions(selected
);
1895 void OptionsDialog::on_removeWatchedFolderButton_clicked()
1897 const QModelIndexList selected
1898 = m_ui
->scanFoldersView
->selectionModel()->selectedIndexes();
1900 for (const QModelIndex
&index
: selected
)
1901 m_ui
->scanFoldersView
->model()->removeRow(index
.row());
1904 void OptionsDialog::handleWatchedFolderViewSelectionChanged()
1906 const QModelIndexList selectedIndexes
= m_ui
->scanFoldersView
->selectionModel()->selectedIndexes();
1907 m_ui
->removeWatchedFolderButton
->setEnabled(!selectedIndexes
.isEmpty());
1908 m_ui
->editWatchedFolderButton
->setEnabled(selectedIndexes
.count() == 1);
1911 void OptionsDialog::editWatchedFolderOptions(const QModelIndex
&index
)
1913 if (!index
.isValid())
1916 auto *watchedFoldersModel
= static_cast<WatchedFoldersModel
*>(m_ui
->scanFoldersView
->model());
1917 auto *dialog
= new WatchedFolderOptionsDialog(watchedFoldersModel
->folderOptions(index
.row()), this);
1918 dialog
->setAttribute(Qt::WA_DeleteOnClose
);
1919 connect(dialog
, &QDialog::accepted
, this, [this, dialog
, index
, watchedFoldersModel
]()
1921 if (index
.isValid())
1923 // The index could be invalidated while the dialog was displayed,
1924 // for example, if you deleted the folder using the Web API.
1925 watchedFoldersModel
->setFolderOptions(index
.row(), dialog
->watchedFolderOptions());
1926 enableApplyButton();
1933 // Return Filter object to apply to BT session
1934 Path
OptionsDialog::getFilter() const
1936 return m_ui
->textFilterPath
->selectedPath();
1939 #ifndef DISABLE_WEBUI
1940 void OptionsDialog::webUIHttpsCertChanged(const Path
&path
)
1942 const auto readResult
= Utils::IO::readFile(path
, Utils::Net::MAX_SSL_FILE_SIZE
);
1943 const bool isCertValid
= Utils::Net::isSSLCertificatesValid(readResult
.value_or(QByteArray()));
1945 m_ui
->textWebUIHttpsCert
->setSelectedPath(path
);
1946 m_ui
->lblSslCertStatus
->setPixmap(UIThemeManager::instance()->getScaledPixmap(
1947 (isCertValid
? u
"security-high"_s
: u
"security-low"_s
), 24));
1950 void OptionsDialog::webUIHttpsKeyChanged(const Path
&path
)
1952 const auto readResult
= Utils::IO::readFile(path
, Utils::Net::MAX_SSL_FILE_SIZE
);
1953 const bool isKeyValid
= !Utils::SSLKey::load(readResult
.value_or(QByteArray())).isNull();
1955 m_ui
->textWebUIHttpsKey
->setSelectedPath(path
);
1956 m_ui
->lblSslKeyStatus
->setPixmap(UIThemeManager::instance()->getScaledPixmap(
1957 (isKeyValid
? u
"security-high"_s
: u
"security-low"_s
), 24));
1960 bool OptionsDialog::isWebUIEnabled() const
1962 return m_ui
->checkWebUI
->isChecked();
1965 QString
OptionsDialog::webUIUsername() const
1967 return m_ui
->textWebUIUsername
->text();
1970 QString
OptionsDialog::webUIPassword() const
1972 return m_ui
->textWebUIPassword
->text();
1975 bool OptionsDialog::webUIAuthenticationOk()
1977 if (!isValidWebUIUsername(webUIUsername()))
1979 QMessageBox::warning(this, tr("Length Error"), tr("The WebUI username must be at least 3 characters long."));
1983 const bool dontChangePassword
= webUIPassword().isEmpty() && !Preferences::instance()->getWebUIPassword().isEmpty();
1984 if (!isValidWebUIPassword(webUIPassword()) && !dontChangePassword
)
1986 QMessageBox::warning(this, tr("Length Error"), tr("The WebUI password must be at least 6 characters long."));
1992 bool OptionsDialog::isAlternativeWebUIPathValid()
1994 if (m_ui
->groupAltWebUI
->isChecked() && m_ui
->textWebUIRootFolder
->selectedPath().isEmpty())
1996 QMessageBox::warning(this, tr("Location Error"), tr("The alternative WebUI files location cannot be blank."));
2003 void OptionsDialog::showConnectionTab()
2005 m_ui
->tabSelection
->setCurrentRow(TAB_CONNECTION
);
2008 #ifndef DISABLE_WEBUI
2009 void OptionsDialog::on_registerDNSBtn_clicked()
2011 const auto service
= static_cast<DNS::Service
>(m_ui
->comboDNSService
->currentIndex());
2012 QDesktopServices::openUrl(Net::DNSUpdater::getRegistrationUrl(service
));
2016 void OptionsDialog::on_IpFilterRefreshBtn_clicked()
2018 if (m_refreshingIpFilter
) return;
2019 m_refreshingIpFilter
= true;
2020 // Updating program preferences
2021 BitTorrent::Session
*const session
= BitTorrent::Session::instance();
2022 session
->setIPFilteringEnabled(true);
2023 session
->setIPFilterFile({}); // forcing Session reload filter file
2024 session
->setIPFilterFile(getFilter());
2025 connect(session
, &BitTorrent::Session::IPFilterParsed
, this, &OptionsDialog::handleIPFilterParsed
);
2026 setCursor(QCursor(Qt::WaitCursor
));
2029 void OptionsDialog::handleIPFilterParsed(bool error
, int ruleCount
)
2031 setCursor(QCursor(Qt::ArrowCursor
));
2033 QMessageBox::warning(this, tr("Parsing error"), tr("Failed to parse the provided IP filter"));
2035 QMessageBox::information(this, tr("Successfully refreshed"), tr("Successfully parsed the provided IP filter: %1 rules were applied.", "%1 is a number").arg(ruleCount
));
2036 m_refreshingIpFilter
= false;
2037 disconnect(BitTorrent::Session::instance(), &BitTorrent::Session::IPFilterParsed
, this, &OptionsDialog::handleIPFilterParsed
);
2040 bool OptionsDialog::schedTimesOk()
2042 if (m_ui
->timeEditScheduleFrom
->time() == m_ui
->timeEditScheduleTo
->time())
2044 QMessageBox::warning(this, tr("Time Error"), tr("The start time and the end time can't be the same."));
2050 void OptionsDialog::on_banListButton_clicked()
2052 auto *dialog
= new BanListOptionsDialog(this);
2053 dialog
->setAttribute(Qt::WA_DeleteOnClose
);
2054 connect(dialog
, &QDialog::accepted
, this, &OptionsDialog::enableApplyButton
);
2058 void OptionsDialog::on_IPSubnetWhitelistButton_clicked()
2060 auto *dialog
= new IPSubnetWhitelistOptionsDialog(this);
2061 dialog
->setAttribute(Qt::WA_DeleteOnClose
);
2062 connect(dialog
, &QDialog::accepted
, this, &OptionsDialog::enableApplyButton
);