33 #include <QActionGroup>
35 #include <QCloseEvent>
37 #include <QDesktopServices>
38 #include <QFileDialog>
39 #include <QFileSystemWatcher>
41 #include <QMessageBox>
44 #include <QPushButton>
51 #if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) && defined(QT_DBUS_LIB)
52 #include <QDBusConnection>
67 #include "base/version.h"
90 #include "ui_mainwindow.h"
97 #if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
101 using namespace std::chrono_literals;
105 #define SETTINGS_KEY(name) "GUI/" name
106 #define EXECUTIONLOG_SETTINGS_KEY(name) (SETTINGS_KEY("Log/") name)
107 #define NOTIFICATIONS_SETTINGS_KEY(name) (SETTINGS_KEY("Notifications/") name)
110 #if !defined(Q_OS_MACOS)
116 return str.startsWith(QLatin1String(
"magnet:"), Qt::CaseInsensitive)
118 || (!str.startsWith(QLatin1String(
"file:"), Qt::CaseInsensitive)
124 : QMainWindow(parent)
127 , m_storeDownloadTrackerFavicon(
SETTINGS_KEY(
"DownloadTrackerFavicon"))
131 #
if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) && defined(QT_DBUS_LIB)
139 setWindowTitle(
"qBittorrent " QBT_VERSION);
143 const QIcon appLogo(
UIThemeManager::instance()->getIcon(QLatin1String(
"qbittorrent"), QLatin1String(
"qbittorrent-tray")));
144 setWindowIcon(appLogo);
147 #if (defined(Q_OS_UNIX))
148 m_ui->actionOptions->setText(tr(
"Preferences"));
176 auto *lockMenu =
new QMenu(
this);
179 m_ui->actionLock->setMenu(lockMenu);
182 m_ui->actionLock->setVisible(
true);
196 qDebug(
"create tabWidget");
200 m_splitter =
new QSplitter(Qt::Horizontal,
this);
203 auto *hSplitter =
new QSplitter(Qt::Vertical,
this);
204 hSplitter->setChildrenCollapsible(
false);
205 hSplitter->setFrameShape(QFrame::NoFrame);
209 m_searchFilter->setPlaceholderText(tr(
"Filter torrent names..."));
215 QWidget *spacer =
new QWidget(
this);
216 spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
254 m_ui->centralWidgetLayout->addSpacing(8);
265 if (
action->isSeparator())
267 QWidget *spacer =
new QWidget(
this);
268 spacer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
269 spacer->setMinimumWidth(16);
275 QWidget *spacer =
new QWidget(
this);
276 spacer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
277 spacer->setMinimumWidth(8);
278 m_ui->toolBar->insertWidget(
m_ui->actionDownloadFromURL, spacer);
281 QWidget *spacer =
new QWidget(
this);
282 spacer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
283 spacer->setMinimumWidth(8);
284 m_ui->toolBar->addWidget(spacer);
299 connect(
m_ui->actionToggleVisibility, &QAction::triggered,
this, [
this]() { toggleVisibility(); });
304 #if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
305 connect(
m_ui->actionCheckForUpdates, &QAction::triggered,
this, [
this]() { checkProgramUpdate(true); });
308 if (pref->isUpdateCheckEnabled())
309 checkProgramUpdate(
false);
311 m_ui->actionCheckForUpdates->setVisible(
false);
316 m_ui->actionExit->setMenuRole(QAction::QuitRole);
317 m_ui->actionAbout->setMenuRole(QAction::AboutRole);
318 m_ui->actionCheckForUpdates->setMenuRole(QAction::ApplicationSpecificRole);
319 m_ui->actionOptions->setMenuRole(QAction::PreferencesRole);
334 setAcceptDrops(
true);
338 setUnifiedTitleAndToolBarOnMac(
true);
351 m_ui->actionInformationMessages->setChecked(flags.testFlag(
Log::INFO));
361 if (
m_ui->actionSearchWidget->isChecked())
365 auto *autoShutdownGroup =
new QActionGroup(
this);
366 autoShutdownGroup->setExclusive(
true);
367 autoShutdownGroup->addAction(
m_ui->actionAutoShutdownDisabled);
368 autoShutdownGroup->addAction(
m_ui->actionAutoExit);
369 autoShutdownGroup->addAction(
m_ui->actionAutoShutdown);
370 autoShutdownGroup->addAction(
m_ui->actionAutoSuspend);
371 autoShutdownGroup->addAction(
m_ui->actionAutoHibernate);
372 #if (!defined(Q_OS_UNIX) || defined(Q_OS_MACOS)) || defined(QT_DBUS_LIB)
377 m_ui->actionAutoShutdown->setDisabled(
true);
378 m_ui->actionAutoSuspend->setDisabled(
true);
379 m_ui->actionAutoHibernate->setDisabled(
true);
383 if (!autoShutdownGroup->checkedAction())
384 m_ui->actionAutoShutdownDisabled->setChecked(
true);
418 showNotificationBalloon(tr(
"qBittorrent is minimized to tray"), tr(
"This behavior can be changed in the settings. You won't be reminded again."));
458 if (!pref->neverCheckFileAssoc() && (!Preferences::isTorrentFileAssocSet() || !Preferences::isMagnetLinkAssocSet()))
460 if (QMessageBox::question(
this, tr(
"Torrent file association"),
461 tr(
"qBittorrent is not the default application for opening torrent files or Magnet links.\nDo you want to make qBittorrent the default application for these?"),
462 QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes)
464 Preferences::setTorrentFileAssoc(
true);
465 Preferences::setMagnetLinkAssoc(
true);
469 pref->setNeverCheckFileAssoc();
474 setupDockClickHandler();
526 #if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) && defined(QT_DBUS_LIB)
527 int MainWindow::getNotificationTimeout()
const
529 return m_storeNotificationTimeOut.get(-1);
532 void MainWindow::setNotificationTimeout(
const int value)
534 m_storeNotificationTimeOut =
value;
554 m_ui->toolBar->setContextMenuPolicy(Qt::CustomContextMenu);
564 textPositionGroup->addAction(iconsOnly);
565 iconsOnly->setCheckable(
true);
566 textPositionGroup->addAction(textOnly);
567 textOnly->setCheckable(
true);
568 textPositionGroup->addAction(textBesideIcons);
569 textBesideIcons->setCheckable(
true);
570 textPositionGroup->addAction(textUnderIcons);
571 textUnderIcons->setCheckable(
true);
572 textPositionGroup->addAction(followSystemStyle);
573 followSystemStyle->setCheckable(
true);
576 if ((buttonStyle >= Qt::ToolButtonIconOnly) && (buttonStyle <= Qt::ToolButtonFollowStyle))
577 m_ui->toolBar->setToolButtonStyle(buttonStyle);
580 case Qt::ToolButtonIconOnly:
581 iconsOnly->setChecked(
true);
583 case Qt::ToolButtonTextOnly:
584 textOnly->setChecked(
true);
586 case Qt::ToolButtonTextBesideIcon:
587 textBesideIcons->setChecked(
true);
589 case Qt::ToolButtonTextUnderIcon:
590 textUnderIcons->setChecked(
true);
593 followSystemStyle->setChecked(
true);
600 cookieDialog->setAttribute(Qt::WA_DeleteOnClose);
601 cookieDialog->open();
611 m_ui->toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
617 m_ui->toolBar->setToolButtonStyle(Qt::ToolButtonTextOnly);
623 m_ui->toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
629 m_ui->toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
635 m_ui->toolBar->setToolButtonStyle(Qt::ToolButtonFollowStyle);
643 , tr(
"Please type the UI lock password:"), QLineEdit::Password, {}, &ok);
647 if (newPassword.size() < 3)
649 QMessageBox::warning(
this, tr(
"Invalid password"), tr(
"The password must be at least 3 characters long"));
659 const QMessageBox::StandardButton answer = QMessageBox::question(
this, tr(
"Clear the password")
660 , tr(
"Are you sure you want to clear the password?"), (QMessageBox::Yes | QMessageBox::No), QMessageBox::No);
661 if (answer == QMessageBox::Yes)
716 menu->setAttribute(Qt::WA_DeleteOnClose);
717 menu->addSeparator();
719 QAction *useRegexAct = menu->addAction(tr(
"Use regular expressions"));
720 useRegexAct->setCheckable(
true);
725 menu->popup(QCursor::pos());
763 QDesktopServices::openUrl(QUrl(
"http://doc.qbittorrent.org"));
773 qDebug(
"Changed tab to transfer list, refreshing the list");
782 qDebug(
"Changed tab to search engine, giving focus to search input");
808 #if (defined(Q_OS_WIN) || defined(Q_OS_MACOS))
809 if (m_programUpdateTimer)
810 m_programUpdateTimer->stop();
814 while (
auto *w = findChild<QWidget *>())
822 if (!mainGeo.isEmpty() && restoreGeometry(mainGeo))
825 if (splitterState.isEmpty())
866 showNotificationBalloon(tr(
"Download completed"), tr(
"'%1' has finished downloading.",
"e.g: xxx.avi has finished downloading.").arg(torrent->
name()));
873 , tr(
"An I/O error occurred for torrent '%1'.\n Reason: %2"
874 ,
"e.g: An error occurred for torrent 'xxx.avi'.\n Reason: disk is full.").arg(torrent->
name(), msg));
879 m_ui->actionCreateTorrent->setShortcut(QKeySequence::New);
880 m_ui->actionOpen->setShortcut(QKeySequence::Open);
881 m_ui->actionDelete->setShortcut(QKeySequence::Delete);
882 m_ui->actionDelete->setShortcutContext(Qt::WidgetShortcut);
883 m_ui->actionDownloadFromURL->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_O);
884 m_ui->actionExit->setShortcut(Qt::CTRL | Qt::Key_Q);
886 m_ui->actionCloseWindow->setShortcut(QKeySequence::Close);
888 m_ui->actionCloseWindow->setVisible(
false);
891 const auto *switchTransferShortcut =
new QShortcut((Qt::ALT | Qt::Key_1),
this);
893 const auto *switchSearchShortcut =
new QShortcut((Qt::ALT | Qt::Key_2),
this);
895 const auto *switchRSSShortcut =
new QShortcut((Qt::ALT | Qt::Key_3),
this);
897 const auto *switchExecutionLogShortcut =
new QShortcut((Qt::ALT | Qt::Key_4),
this);
899 const auto *switchSearchFilterShortcut =
new QShortcut(QKeySequence::Find,
m_transferListWidget);
902 m_ui->actionDocumentation->setShortcut(QKeySequence::HelpContents);
903 m_ui->actionOptions->setShortcut(Qt::ALT | Qt::Key_O);
904 m_ui->actionStatistics->setShortcut(Qt::CTRL | Qt::Key_I);
905 m_ui->actionStart->setShortcut(Qt::CTRL | Qt::Key_S);
906 m_ui->actionStartAll->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_S);
907 m_ui->actionPause->setShortcut(Qt::CTRL | Qt::Key_P);
908 m_ui->actionPauseAll->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_P);
909 m_ui->actionBottomQueuePos->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Minus);
910 m_ui->actionDecreaseQueuePos->setShortcut(Qt::CTRL | Qt::Key_Minus);
911 m_ui->actionIncreaseQueuePos->setShortcut(Qt::CTRL | Qt::Key_Plus);
912 m_ui->actionTopQueuePos->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Plus);
914 m_ui->actionMinimize->setShortcut(Qt::CTRL + Qt::Key_M);
915 addAction(
m_ui->actionMinimize);
929 m_ui->actionSearchWidget->setChecked(
true);
940 m_ui->actionRSSReader->setChecked(
true);
951 m_ui->actionExecutionLogs->setChecked(
true);
965 const auto torrentID = torrent->
id();
967 QMessageBox *confirmBox =
new QMessageBox(QMessageBox::Question, tr(
"Recursive download confirmation")
968 , tr(
"The torrent '%1' contains torrent files, do you want to proceed with their download?").arg(torrent->
name())
969 , QMessageBox::NoButton,
this);
970 confirmBox->setAttribute(Qt::WA_DeleteOnClose);
971 confirmBox->setModal(
true);
973 const QPushButton *yes = confirmBox->addButton(tr(
"Yes"), QMessageBox::YesRole);
974 confirmBox->addButton(tr(
"No"), QMessageBox::NoRole);
975 const QPushButton *never = confirmBox->addButton(tr(
"Never"), QMessageBox::NoRole);
976 connect(confirmBox, &QMessageBox::buttonClicked,
this, [torrentID, yes, never](
const QAbstractButton *button)
990 , tr(
"Couldn't download file at URL '%1', reason: %2.").arg(url, reason));
996 dialog->setAttribute(Qt::WA_DeleteOnClose);
1014 void MainWindow::on_actionCloseWindow_triggered()
1025 if (isMinimized() || !isVisible())
1027 if (
m_tabs->currentIndex() == 0)
1029 return m_tabs->currentWidget();
1044 , tr(
"Please type the UI lock password:"), QLineEdit::Password, {}, &ok);
1045 if (!ok)
return false;
1052 QMessageBox::warning(
this, tr(
"Invalid password"), tr(
"The password is invalid"));
1079 case QSystemTrayIcon::Trigger:
1086 setWindowState((windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
1125 qDebug(
"** Show Event **");
1151 if (
event->matches(QKeySequence::Paste))
1153 const QMimeData *mimeData {QGuiApplication::clipboard()->mimeData()};
1155 if (mimeData->hasText())
1158 const QStringList lines {mimeData->text().split(
'\n', Qt::SkipEmptyParts)};
1160 for (QString line : lines)
1162 line = line.trimmed();
1167 if (useTorrentAdditionDialog)
1177 QMainWindow::keyPressEvent(
event);
1192 const bool goToSystrayOnExit = pref->
closeToTray();
1196 QTimer::singleShot(0,
this, &QWidget::hide);
1199 showNotificationBalloon(tr(
"qBittorrent is closed to tray"), tr(
"This behavior can be changed in the settings. You won't be reminded again."));
1212 QMessageBox confirmBox(QMessageBox::Question, tr(
"Exiting qBittorrent"),
1214 tr(
"Some files are currently transferring.") +
'\n' + tr(
"Are you sure you want to quit qBittorrent?"),
1215 QMessageBox::NoButton,
this);
1216 QPushButton *noBtn = confirmBox.addButton(tr(
"&No"), QMessageBox::NoRole);
1217 confirmBox.addButton(tr(
"&Yes"), QMessageBox::YesRole);
1218 QPushButton *alwaysBtn = confirmBox.addButton(tr(
"&Always Yes"), QMessageBox::YesRole);
1219 confirmBox.setDefaultButton(noBtn);
1221 if (!confirmBox.clickedButton() || (confirmBox.clickedButton() == noBtn))
1228 if (confirmBox.clickedButton() == alwaysBtn)
1238 m_systrayIcon->setToolTip(tr(
"qBittorrent is shutting down..."));
1270 case QEvent::WindowStateChange:
1272 qDebug(
"Window change event");
1276 qDebug(
"minimisation");
1280 qDebug() <<
"Has active window:" << (qApp->activeWindow() !=
nullptr);
1282 bool hasModalWindow =
false;
1283 for (QWidget *widget :
asConst(QApplication::allWidgets()))
1285 if (widget->isModal())
1287 hasModalWindow =
true;
1292 if (!hasModalWindow)
1294 qDebug(
"Minimize to Tray enabled, hiding!");
1296 QTimer::singleShot(0,
this, &QWidget::hide);
1299 showNotificationBalloon(tr(
"qBittorrent is minimized to tray"), tr(
"This behavior can be changed in the settings. You won't be reminded again."));
1308 case QEvent::ToolBarChange:
1310 qDebug(
"MAC: Received a toolbar change event!");
1311 bool ret = QMainWindow::event(
e);
1313 qDebug(
"MAC: new toolbar visibility is %d", !
m_ui->actionTopToolBar->isChecked());
1314 m_ui->actionTopToolBar->toggle();
1323 return QMainWindow::event(
e);
1329 event->acceptProposedAction();
1333 if (
event->mimeData()->hasUrls())
1335 for (
const QUrl &url :
asConst(
event->mimeData()->urls()))
1340 files << ((url.scheme().compare(
"file", Qt::CaseInsensitive) == 0)
1347 files =
event->mimeData()->text().split(
'\n');
1351 QStringList torrentFiles, otherFiles;
1355 torrentFiles <<
file;
1364 if (useTorrentAdditionDialog)
1369 if (!torrentFiles.isEmpty())
return;
1385 for (
const QString &mime :
asConst(
event->mimeData()->formats()))
1386 qDebug(
"mimeData: %s", mime.toLocal8Bit().data());
1387 if (
event->mimeData()->hasFormat(
"text/plain") ||
event->mimeData()->hasFormat(
"text/uri-list"))
1388 event->acceptProposedAction();
1395 static bool dockClickHandler(
id self,
SEL cmd, ...)
1400 if (dockMainWindowHandle && !dockMainWindowHandle->isVisible())
1408 void MainWindow::setupDockClickHandler()
1410 dockMainWindowHandle =
this;
1429 const QStringList pathsList =
1430 QFileDialog::getOpenFileNames(
this, tr(
"Open Torrent Files"), pref->
getMainLastDir(),
1433 if (pathsList.isEmpty())
1438 for (
const QString &
file : pathsList)
1440 if (useTorrentAdditionDialog)
1448 topDir = topDir.left(topDir.lastIndexOf(
'/'));
1473 setStatusBar(
nullptr);
1507 m_ui->actionLock->setVisible(
false);
1514 m_ui->toolBar->setVisible(
true);
1520 m_ui->toolBar->setVisible(
false);
1547 if (!
m_ui->actionDecreaseQueuePos->isVisible())
1550 m_ui->actionDecreaseQueuePos->setVisible(
true);
1551 m_ui->actionIncreaseQueuePos->setVisible(
true);
1552 m_ui->actionTopQueuePos->setVisible(
true);
1553 m_ui->actionBottomQueuePos->setVisible(
true);
1562 if (
m_ui->actionDecreaseQueuePos->isVisible())
1565 m_ui->actionDecreaseQueuePos->setVisible(
false);
1566 m_ui->actionIncreaseQueuePos->setVisible(
false);
1567 m_ui->actionTopQueuePos->setVisible(
false);
1568 m_ui->actionBottomQueuePos->setVisible(
false);
1579 #if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
1580 if (pref->isUpdateCheckEnabled())
1582 if (!m_programUpdateTimer)
1584 m_programUpdateTimer =
new QTimer(
this);
1585 m_programUpdateTimer->setInterval(24h);
1586 m_programUpdateTimer->setSingleShot(
true);
1587 connect(m_programUpdateTimer, &QTimer::timeout,
this, [
this]() { checkProgramUpdate(
false); });
1588 m_programUpdateTimer->start();
1593 delete m_programUpdateTimer;
1594 m_programUpdateTimer =
nullptr;
1598 qDebug(
"GUI settings loaded");
1619 const auto toolTip = QString::fromLatin1(
"%1\n%2").arg(
1628 setWindowTitle(tr(
"[D: %1, U: %2] qBittorrent %3",
"D = Download; U = Upload; %3 is qBittorrent version")
1649 #if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) && defined(QT_DBUS_LIB)
1651 , QLatin1String(
"/org/freedesktop/Notifications")
1652 , QDBusConnection::sessionBus());
1663 const QVariantMap hints {{QLatin1String(
"desktop-entry"), QLatin1String(
"org.qbittorrent.qBittorrent")}};
1664 QDBusPendingReply<uint> reply = notifications.
Notify(QLatin1String(
"qBittorrent"), 0
1665 , QLatin1String(
"qbittorrent"), title, msg, {}, hints, getNotificationTimeout());
1667 reply.waitForFinished();
1668 if (!reply.isError())
1670 #elif defined(Q_OS_MACOS)
1687 for (
const QString &url : urlList)
1689 if (useTorrentAdditionDialog)
1708 if (QSystemTrayIcon::isSystemTrayAvailable())
1726 QTimer::singleShot(std::chrono::seconds(2),
this, [
this, retries]()
1734 LogMsg(
"System tray icon is still not available after retries. Disabling it.",
Log::WARNING);
1751 m_ui->actionToggleVisibility->setText(isVisible() ? tr(
"Hide") : tr(
"Show"));
1780 m_ui->actionUseAlternativeSpeedLimits->setChecked(alternative);
1799 const bool isVisible =
static_cast<QAction *
>(sender())->isChecked();
1800 m_ui->toolBar->setVisible(isVisible);
1806 const bool isVisible =
static_cast<QAction *
>(sender())->isChecked();
1818 setWindowTitle(
"qBittorrent " QBT_VERSION);
1836 m_ui->actionSearchWidget->setChecked(
false);
1840 const QMessageBox::StandardButton buttonPressed = QMessageBox::question(
this, tr(
"Missing Python Runtime")
1841 , tr(
"Python is required to use the search engine but it does not seem to be installed.\nDo you want to install it now?")
1842 , (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes);
1843 if (buttonPressed == QMessageBox::Yes)
1846 QMessageBox::information(
this, tr(
"Missing Python Runtime")
1847 , tr(
"Python is required to use the search engine but it does not seem to be installed."));
1855 m_ui->actionSearchWidget->setChecked(
false);
1859 const QMessageBox::StandardButton buttonPressed = QMessageBox::question(
this, tr(
"Old Python Runtime")
1860 , tr(
"Your Python version (%1) is outdated. Minimum requirement: %2.\nDo you want to install a newer version now?")
1861 .arg(pyInfo.
version, QLatin1String(
"3.5.0"))
1862 , (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes);
1863 if (buttonPressed == QMessageBox::Yes)
1866 QMessageBox::information(
this, tr(
"Old Python Runtime")
1867 , tr(
"Your Python version (%1) is outdated. Please upgrade to latest version for search engines to work.\nMinimum requirement: %2.")
1868 .arg(pyInfo.
version, QLatin1String(
"3.5.0")));
1874 m_ui->actionSearchWidget->setChecked(
true);
1898 #if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
1899 void MainWindow::handleUpdateCheckFinished(
ProgramUpdater *updater,
const bool invokedByUser)
1901 m_ui->actionCheckForUpdates->setEnabled(
true);
1902 m_ui->actionCheckForUpdates->setText(tr(
"&Check for Updates"));
1903 m_ui->actionCheckForUpdates->setToolTip(tr(
"Check for program updates"));
1905 const auto cleanup = [
this, updater]()
1907 if (m_programUpdateTimer)
1908 m_programUpdateTimer->start();
1909 updater->deleteLater();
1913 if (!newVersion.isEmpty())
1915 const QString msg {tr(
"A new version is available.") +
"<br/>"
1916 + tr(
"Do you want to download %1?").arg(newVersion) +
"<br/><br/>"
1917 + QString::fromLatin1(
"<a href=\"https://www.qbittorrent.org/news.php\">%1</a>").arg(tr(
"Open changelog..."))};
1918 auto *msgBox =
new QMessageBox {QMessageBox::Question, tr(
"qBittorrent Update Available"), msg
1919 , (QMessageBox::Yes | QMessageBox::No),
this};
1920 msgBox->setAttribute(Qt::WA_DeleteOnClose);
1921 msgBox->setAttribute(Qt::WA_ShowWithoutActivating);
1922 msgBox->setDefaultButton(QMessageBox::Yes);
1923 connect(msgBox, &QMessageBox::buttonClicked,
this, [msgBox, updater](QAbstractButton *button)
1925 if (msgBox->buttonRole(button) == QMessageBox::YesRole)
1927 updater->updateProgram();
1930 connect(msgBox, &QDialog::finished,
this,
cleanup);
1937 auto *msgBox =
new QMessageBox {QMessageBox::Information, QLatin1String(
"qBittorrent")
1938 , tr(
"No updates available.\nYou are already using the latest version.")
1939 , QMessageBox::Ok,
this};
1940 msgBox->setAttribute(Qt::WA_DeleteOnClose);
1941 connect(msgBox, &QDialog::finished,
this,
cleanup);
1960 QDesktopServices::openUrl(QUrl(
"https://www.qbittorrent.org/donate"));
1971 setWindowState(windowState() | Qt::WindowMinimized);
1992 m_ui->actionNormalMessages->setEnabled(checked);
1993 m_ui->actionInformationMessages->setEnabled(checked);
1994 m_ui->actionWarningMessages->setEnabled(checked);
1995 m_ui->actionCriticalMessages->setEnabled(checked);
2037 qDebug() << Q_FUNC_INFO << enabled;
2043 qDebug() << Q_FUNC_INFO << enabled;
2049 qDebug() << Q_FUNC_INFO << enabled;
2055 qDebug() << Q_FUNC_INFO << enabled;
2066 #if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
2067 void MainWindow::checkProgramUpdate(
const bool invokedByUser)
2069 if (m_programUpdateTimer)
2070 m_programUpdateTimer->stop();
2072 m_ui->actionCheckForUpdates->setEnabled(
false);
2073 m_ui->actionCheckForUpdates->setText(tr(
"Checking for Updates..."));
2074 m_ui->actionCheckForUpdates->setToolTip(tr(
"Already checking for program updates in the background"));
2078 ,
this, [
this, invokedByUser, updater]()
2080 handleUpdateCheckFinished(updater, invokedByUser);
2087 void MainWindow::installPython()
2089 setCursor(QCursor(Qt::WaitCursor));
2091 #ifdef QBT_APP_64BIT
2092 const QString installerURL =
"https://www.python.org/ftp/python/3.8.10/python-3.8.10-amd64.exe";
2094 const QString installerURL =
"https://www.python.org/ftp/python/3.8.10/python-3.8.10.exe";
2098 ,
this, &MainWindow::pythonDownloadFinished);
2105 setCursor(QCursor(Qt::ArrowCursor));
2106 QMessageBox::warning(
2107 this, tr(
"Download error")
2108 , tr(
"Python setup could not be downloaded, reason: %1.\nPlease install it manually.")
2113 setCursor(QCursor(Qt::ArrowCursor));
2115 qDebug(
"Launching Python installer in passive mode...");
2117 const QString exePath = result.
filePath + QLatin1String(
".exe");
2118 QFile::rename(result.
filePath, exePath);
2122 installer.waitForFinished(10 * 60 * 1000);
2124 qDebug(
"Installer stdout: %s", installer.readAllStandardOutput().data());
2125 qDebug(
"Installer stderr: %s", installer.readAllStandardError().data());
2126 qDebug(
"Setup should be complete!");
2134 m_ui->actionSearchWidget->setChecked(
true);
QBITTORRENT_HAS_EXECINFO_H if(NOT QBITTORRENT_HAS_EXECINFO_H) message(FATAL_ERROR "execinfo.h header file not found.\n" "Please either disable the STACKTRACE feature or use a libc that has this header file
static void show(const QString &source, const BitTorrent::AddTorrentParams &inParams, QWidget *parent)
static QString getText(QWidget *parent, const QString &title, const QString &label, QLineEdit::EchoMode mode=QLineEdit::Normal, const QString &text={}, bool *ok=nullptr, bool excludeExtension=false, Qt::InputMethodHints inputMethodHints=Qt::ImhNone)
bool isAltGlobalSpeedLimitEnabled() const
static Session * instance()
void trackersAdded(Torrent *torrent, const QVector< TrackerEntry > &trackers)
void trackersChanged(Torrent *torrent)
void fullDiskError(Torrent *torrent, const QString &msg)
void trackersRemoved(Torrent *torrent, const QVector< TrackerEntry > &trackers)
bool hasRunningSeed() const
void loadTorrentFailed(const QString &error)
void setAltGlobalSpeedLimitEnabled(bool enabled)
bool hasActiveTorrents() const
void torrentAdded(Torrent *torrent)
void trackerError(Torrent *torrent, const QString &tracker)
const SessionStatus & status() const
bool hasUnfinishedTorrents() const
void speedLimitModeChanged(bool alternative)
void trackerSuccess(Torrent *torrent, const QString &tracker)
void torrentFinished(Torrent *torrent)
void recursiveTorrentDownloadPossible(Torrent *torrent)
bool addTorrent(const QString &source, const AddTorrentParams ¶ms=AddTorrentParams())
void downloadFromUrlFailed(const QString &url, const QString &reason)
void torrentsUpdated(const QVector< Torrent * > &torrents)
void trackerWarning(Torrent *torrent, const QString &tracker)
void trackerlessStateChanged(Torrent *torrent, bool trackerless)
virtual QString name() const =0
void urlsReadyToBeDownloaded(const QStringList &torrentURLs)
void addMessage(const QString &message, const Log::MsgType &type=Log::NORMAL)
static Logger * instance()
void handleDownloadFromUrlFailure(const QString &, const QString &) const
void showStatusBar(bool show)
void downloadFromURLList(const QStringList &urlList)
QPointer< AboutDialog > m_aboutDlg
void showNotificationBalloon(const QString &title, const QString &msg) const
PropertiesWidget * m_propertiesWidget
void toggleAlternativeSpeeds()
TransferListWidget * transferListWidget() const
SettingValue< bool > m_storeNotificationEnabled
void on_actionOptions_triggered()
void on_actionAutoHibernate_toggled(bool)
SettingValue< bool > m_storeNotificationTorrentAdded
void on_actionNormalMessages_triggered(bool checked)
QPointer< TorrentCreatorDialog > m_createTorrentDlg
void askRecursiveTorrentDownloadConfirmation(BitTorrent::Torrent *const torrent)
void on_actionAutoSuspend_toggled(bool)
void fullDiskError(BitTorrent::Torrent *const torrent, const QString &msg) const
void createKeyboardShortcuts()
PropertiesWidget * propertiesWidget() const
TransferListWidget * m_transferListWidget
void createTrayIconMenu()
void on_actionShowStatusbar_triggered()
void on_actionDonateMoney_triggered()
void finishedTorrent(BitTorrent::Torrent *const torrent) const
void on_actionOpen_triggered()
void closeEvent(QCloseEvent *) override
void toolbarMenuRequested(const QPoint &point)
void setExecutionLogEnabled(bool value)
void on_actionAbout_triggered()
void dragEnterEvent(QDragEnterEvent *event) override
Log::MsgTypes executionLogMsgTypes() const
void keyPressEvent(QKeyEvent *event) override
void setNotificationsEnabled(bool value)
void addToolbarContextMenu()
void on_actionCriticalMessages_triggered(bool checked)
QPointer< StatusBar > m_statusBar
void createTorrentTriggered(const QString &path={})
SettingValue< bool > m_storeExecutionLogEnabled
void clearUILockPassword()
void torrentNew(BitTorrent::Torrent *const torrent) const
SettingValue< bool > m_storeDownloadTrackerFavicon
void on_actionAutoExit_toggled(bool)
void on_actionSearchWidget_triggered()
void on_actionDocumentation_triggered() const
void updateAltSpeedsBtn(bool alternative)
QFileSystemWatcher * m_executableWatcher
void on_actionTopToolBar_triggered()
void tabChanged(int newTab)
void setTorrentAddedNotificationsEnabled(bool value)
QPointer< ExecutionLogWidget > m_executionLog
QPointer< OptionsDialog > m_options
QAction * m_queueSeparatorMenu
void showFilterContextMenu(const QPoint &)
void showConnectionSettings()
LineEdit * m_searchFilter
CachedSettingValue< Log::MsgTypes > m_storeExecutionLogTypes
bool m_displaySpeedInTitle
void on_actionInformationMessages_triggered(bool checked)
void updatePowerManagementState()
MainWindow(QWidget *parent=nullptr)
QPointer< QTabWidget > m_tabs
void addTorrentFailed(const QString &error) const
void displayExecutionLogTab()
void handleRSSUnreadCountUpdated(int count)
void reloadSessionStats()
QPointer< StatsDialog > m_statsDlg
void setExecutionLogMsgTypes(Log::MsgTypes value)
void on_actionAutoShutdown_toggled(bool)
bool isTorrentAddedNotificationsEnabled() const
QPointer< QSystemTrayIcon > m_systrayIcon
void on_actionExit_triggered()
void toolbarFollowSystem()
QPointer< DownloadFromURLDialog > m_downloadFromURLDialog
QPointer< SearchWidget > m_searchWidget
void showEvent(QShowEvent *) override
bool isDownloadTrackerFavicon() const
void on_actionRSSReader_triggered()
QWidget * currentTabWidget() const
bool defineUILockPassword()
void on_actionLock_triggered()
TransferListFiltersWidget * m_transferListFiltersWidget
void on_actionWarningMessages_triggered(bool checked)
void toggleVisibility(const QSystemTrayIcon::ActivationReason reason=QSystemTrayIcon::Trigger)
void on_actionSetGlobalSpeedLimits_triggered()
QPointer< RSSWidget > m_rssWidget
QAction * m_searchFilterAction
void displayTransferTab() const
void on_actionCreateTorrent_triggered()
QAction * m_queueSeparator
void on_actionDownloadFromURL_triggered()
bool isExecutionLogEnabled() const
void notifyOfUpdate(const QString &)
void on_actionStatistics_triggered()
void setDownloadTrackerFavicon(bool value)
void on_actionExecutionLogs_triggered(bool checked)
QPointer< QMenu > m_trayIconMenu
bool event(QEvent *e) override
void dropEvent(QDropEvent *event) override
void reloadTorrentStats(const QVector< BitTorrent::Torrent * > &torrents)
void createTrayIcon(int retries)
void on_actionSpeedInTitleBar_triggered()
bool isNotificationsEnabled() const
void systemTrayIconCreated()
static bool hasSupportedScheme(const QString &url)
DownloadHandler * download(const DownloadRequest &downloadRequest)
static DownloadManager * instance()
QDBusPendingReply< uint > Notify(const QString &app_name, uint id, const QString &icon, const QString &summary, const QString &body, const QStringList &actions, const QVariantMap &hints, int timeout)
void setActivityState(bool busy)
bool recursiveDownloadDisabled() const
bool shutdownqBTWhenDownloadsComplete() const
static Preferences * instance()
bool shutdownWhenDownloadsComplete() const
void setSuspendWhenDownloadsComplete(bool suspend)
void setCloseToTrayNotified(bool b)
void setConfirmOnExit(bool confirm)
bool preventFromSuspendWhenSeeding() const
void setShutdownqBTWhenDownloadsComplete(bool shutdown)
bool useAlternatingRowColors() const
bool isStatusbarDisplayed() const
QByteArray getMainGeometry() const
bool suspendWhenDownloadsComplete() const
bool isSearchEnabled() const
void setRegexAsFilteringPatternForTransferList(bool checked)
void setMinimizeToTrayNotified(bool b)
bool confirmOnExit() const
void setMainLastDir(const QString &path)
bool systemTrayEnabled() const
void showSpeedInTitleBar(bool show)
void setStatusbarDisplayed(bool displayed)
void setSystemTrayEnabled(bool enabled)
void setMainGeometry(const QByteArray &geometry)
void setUILocked(bool locked)
bool speedInTitleBar() const
void setUILockPassword(const QByteArray &password)
bool getRegexAsFilteringPatternForTransferList() const
bool isRSSWidgetEnabled() const
bool closeToTrayNotified() const
void setToolbarTextPosition(int position)
QByteArray getMainVSplitterState() const
void setShutdownWhenDownloadsComplete(bool shutdown)
QString getMainLastDir() const
bool isToolbarDisplayed() const
void setRSSWidgetVisible(bool enabled)
void setSearchEnabled(bool enabled)
bool minimizeToTray() const
void setToolbarDisplayed(bool displayed)
int getToolbarTextPosition() const
void setHibernateWhenDownloadsComplete(bool hibernate)
QByteArray getUILockPassword() const
bool preventFromSuspendWhenDownloading() const
bool minimizeToTrayNotified() const
void setMainVSplitterState(const QByteArray &state)
bool hibernateWhenDownloadsComplete() const
bool startMinimized() const
void checkForUpdates() const
void updateCheckFinished()
QString getNewVersion() const
static Session * instance()
T get(const T &defaultValue={}) const
void connectionButtonClicked()
void alternativeSpeedsButtonClicked()
int rowCount(const QModelIndex &parent={}) const override
static UIThemeManager * instance()
const char C_TORRENT_FILE_EXTENSION[]
constexpr std::add_const_t< T > & asConst(T &t) noexcept
flag icons free of to any person obtaining a copy of this software and associated documentation files(the "Software")
void LogMsg(const QString &message, const Log::MsgType &type)
#define NOTIFICATIONS_SETTINGS_KEY(name)
#define EXECUTIONLOG_SETTINGS_KEY(name)
#define SETTINGS_KEY(name)
void overrideDockClickHandler(bool(*dockClickHandler)(id, SEL,...))
void displayNotification(const QString &title, const QString &message)
void setBadgeLabelText(const QString &text)
QString toUniformPath(const QString &path)
bool forceRemove(const QString &filePath)
QString toNativePath(const QString &path)
T scaledSize(const QWidget *widget, const T &size)
QPoint screenCenter(const QWidget *w)
nonstd::expected< void, QString > saveToFile(const QString &path, const QByteArray &data)
QString friendlyUnit(qint64 bytes, bool isSpeed=false)
QByteArray generate(const QString &password)
bool verify(const QByteArray &secret, const QString &password)
bool isTorrentLink(const QString &str)
const std::chrono::seconds PREVENT_SUSPEND_INTERVAL
const int TIME_TRAY_BALLOON
T value(const QString &key, const T &defaultValue={})
file(GLOB QBT_TS_FILES "${qBittorrent_SOURCE_DIR}/src/lang/*.ts") set_source_files_properties($
quint64 payloadUploadRate
quint64 payloadDownloadRate
bool isSupportedVersion() const