Some work about adaptive color scheme for Web UI (PR #19901)
http://[316:c51a:62a3:8b9::4]/d4708/qBittorrent/src/branch/adaptive-webui
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1648 lines
63 KiB
1648 lines
63 KiB
/* |
|
* Bittorrent Client using Qt4 and libtorrent. |
|
* Copyright (C) 2006 Christophe Dumez |
|
* |
|
* This program is free software; you can redistribute it and/or |
|
* modify it under the terms of the GNU General Public License |
|
* as published by the Free Software Foundation; either version 2 |
|
* of the License, or (at your option) any later version. |
|
* |
|
* This program is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU General Public License |
|
* along with this program; if not, write to the Free Software |
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
* |
|
* In addition, as a special exception, the copyright holders give permission to |
|
* link this program with the OpenSSL project's "OpenSSL" library (or with |
|
* modified versions of it that use the same license as the "OpenSSL" library), |
|
* and distribute the linked executables. You must obey the GNU General Public |
|
* License in all respects for all of the code used other than "OpenSSL". If you |
|
* modify file(s), you may extend this exception to your version of the file(s), |
|
* but you are not obligated to do so. If you do not wish to do so, delete this |
|
* exception statement from your version. |
|
* |
|
* Contact : chris@qbittorrent.org |
|
*/ |
|
|
|
#include <QtGlobal> |
|
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)) && defined(QT_DBUS_LIB) |
|
#include <QDBusConnection> |
|
#include "notifications.h" |
|
#endif |
|
|
|
#include <QFileDialog> |
|
#include <QFileSystemWatcher> |
|
#include <QMessageBox> |
|
#include <QTimer> |
|
#include <QDesktopServices> |
|
#include <QStatusBar> |
|
#include <QClipboard> |
|
#include <QCloseEvent> |
|
#include <QShortcut> |
|
#include <QScrollBar> |
|
#include <QMimeData> |
|
#include <QCryptographicHash> |
|
|
|
#include "mainwindow.h" |
|
#include "transferlistwidget.h" |
|
#include "base/utils/misc.h" |
|
#include "torrentcreatordlg.h" |
|
#include "downloadfromurldlg.h" |
|
#include "addnewtorrentdialog.h" |
|
#include "search/searchwidget.h" |
|
#include "rss_imp.h" |
|
#include "base/bittorrent/session.h" |
|
#include "base/bittorrent/sessionstatus.h" |
|
#include "base/bittorrent/torrenthandle.h" |
|
#include "about_imp.h" |
|
#include "trackerlogin.h" |
|
#include "options_imp.h" |
|
#include "speedlimitdlg.h" |
|
#include "base/preferences.h" |
|
#include "trackerlist.h" |
|
#include "peerlistwidget.h" |
|
#include "transferlistfilterswidget.h" |
|
#include "propertieswidget.h" |
|
#include "statusbar.h" |
|
#include "hidabletabwidget.h" |
|
#include "torrentimportdlg.h" |
|
#include "torrentmodel.h" |
|
#include "executionlog.h" |
|
#include "guiiconprovider.h" |
|
#include "base/logger.h" |
|
#include "autoexpandabledialog.h" |
|
#ifdef Q_OS_MAC |
|
void qt_mac_set_dock_menu(QMenu *menu); |
|
#endif |
|
#include "lineedit.h" |
|
#include "application.h" |
|
#if defined(Q_OS_WIN) || defined(Q_OS_MAC) |
|
#include "programupdater.h" |
|
#endif |
|
#include "powermanagement.h" |
|
#ifdef Q_OS_WIN |
|
#include "base/net/downloadmanager.h" |
|
#include "base/net/downloadhandler.h" |
|
#endif |
|
|
|
#define TIME_TRAY_BALLOON 5000 |
|
#define PREVENT_SUSPEND_INTERVAL 60000 |
|
|
|
/***************************************************** |
|
* * |
|
* GUI * |
|
* * |
|
*****************************************************/ |
|
|
|
// Constructor |
|
MainWindow::MainWindow(QWidget *parent) |
|
: QMainWindow(parent) |
|
, m_posInitialized(false) |
|
, force_exit(false) |
|
, unlockDlgShowing(false) |
|
, has_python(false) |
|
{ |
|
setupUi(this); |
|
|
|
Preferences* const pref = Preferences::instance(); |
|
ui_locked = pref->isUILocked(); |
|
setWindowTitle(QString("qBittorrent %1").arg(QString::fromUtf8(VERSION))); |
|
displaySpeedInTitle = pref->speedInTitleBar(); |
|
// Setting icons |
|
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)) |
|
if (Preferences::instance()->useSystemIconTheme()) |
|
setWindowIcon(QIcon::fromTheme("qbittorrent", QIcon(QString::fromUtf8(":/icons/skin/qbittorrent32.png")))); |
|
else |
|
#endif |
|
setWindowIcon(QIcon(QString::fromUtf8(":/icons/skin/qbittorrent32.png"))); |
|
|
|
addToolbarContextMenu(); |
|
|
|
actionOpen->setIcon(GuiIconProvider::instance()->getIcon("list-add")); |
|
actionDownload_from_URL->setIcon(GuiIconProvider::instance()->getIcon("insert-link")); |
|
actionSet_upload_limit->setIcon(QIcon(QString::fromUtf8(":/icons/skin/seeding.png"))); |
|
actionSet_download_limit->setIcon(QIcon(QString::fromUtf8(":/icons/skin/download.png"))); |
|
actionSet_global_upload_limit->setIcon(QIcon(QString::fromUtf8(":/icons/skin/seeding.png"))); |
|
actionSet_global_download_limit->setIcon(QIcon(QString::fromUtf8(":/icons/skin/download.png"))); |
|
actionCreate_torrent->setIcon(GuiIconProvider::instance()->getIcon("document-edit")); |
|
actionAbout->setIcon(GuiIconProvider::instance()->getIcon("help-about")); |
|
actionStatistics->setIcon(GuiIconProvider::instance()->getIcon("view-statistics")); |
|
actionDecreasePriority->setIcon(GuiIconProvider::instance()->getIcon("go-down")); |
|
actionBottomPriority->setIcon(GuiIconProvider::instance()->getIcon("go-bottom")); |
|
actionDelete->setIcon(GuiIconProvider::instance()->getIcon("list-remove")); |
|
actionDocumentation->setIcon(GuiIconProvider::instance()->getIcon("help-contents")); |
|
actionDonate_money->setIcon(GuiIconProvider::instance()->getIcon("wallet-open")); |
|
actionExit->setIcon(GuiIconProvider::instance()->getIcon("application-exit")); |
|
actionIncreasePriority->setIcon(GuiIconProvider::instance()->getIcon("go-up")); |
|
actionTopPriority->setIcon(GuiIconProvider::instance()->getIcon("go-top")); |
|
actionLock_qBittorrent->setIcon(GuiIconProvider::instance()->getIcon("object-locked")); |
|
actionOptions->setIcon(GuiIconProvider::instance()->getIcon("preferences-system")); |
|
actionPause->setIcon(GuiIconProvider::instance()->getIcon("media-playback-pause")); |
|
actionPause_All->setIcon(GuiIconProvider::instance()->getIcon("media-playback-pause")); |
|
actionStart->setIcon(GuiIconProvider::instance()->getIcon("media-playback-start")); |
|
actionStart_All->setIcon(GuiIconProvider::instance()->getIcon("media-playback-start")); |
|
action_Import_Torrent->setIcon(GuiIconProvider::instance()->getIcon("document-import")); |
|
menuAuto_Shutdown_on_downloads_completion->setIcon(GuiIconProvider::instance()->getIcon("application-exit")); |
|
|
|
QMenu *startAllMenu = new QMenu(this); |
|
startAllMenu->addAction(actionStart_All); |
|
actionStart->setMenu(startAllMenu); |
|
QMenu *pauseAllMenu = new QMenu(this); |
|
pauseAllMenu->addAction(actionPause_All); |
|
actionPause->setMenu(pauseAllMenu); |
|
QMenu *lockMenu = new QMenu(this); |
|
QAction *defineUiLockPasswdAct = lockMenu->addAction(tr("&Set Password")); |
|
connect(defineUiLockPasswdAct, SIGNAL(triggered()), this, SLOT(defineUILockPassword())); |
|
QAction *clearUiLockPasswdAct = lockMenu->addAction(tr("&Clear Password")); |
|
connect(clearUiLockPasswdAct, SIGNAL(triggered()), this, SLOT(clearUILockPassword())); |
|
actionLock_qBittorrent->setMenu(lockMenu); |
|
|
|
// Creating Bittorrent session |
|
connect(BitTorrent::Session::instance(), SIGNAL(fullDiskError(BitTorrent::TorrentHandle *const, QString)), this, SLOT(fullDiskError(BitTorrent::TorrentHandle *const, QString))); |
|
connect(BitTorrent::Session::instance(), SIGNAL(addTorrentFailed(const QString &)), this, SLOT(addTorrentFailed(const QString &))); |
|
connect(BitTorrent::Session::instance(), SIGNAL(torrentFinished(BitTorrent::TorrentHandle *const)), this, SLOT(finishedTorrent(BitTorrent::TorrentHandle *const))); |
|
connect(BitTorrent::Session::instance(), SIGNAL(trackerAuthenticationRequired(BitTorrent::TorrentHandle *const)), this, SLOT(trackerAuthenticationRequired(BitTorrent::TorrentHandle *const))); |
|
connect(BitTorrent::Session::instance(), SIGNAL(downloadFromUrlFailed(QString, QString)), this, SLOT(handleDownloadFromUrlFailure(QString, QString))); |
|
connect(BitTorrent::Session::instance(), SIGNAL(speedLimitModeChanged(bool)), this, SLOT(updateAltSpeedsBtn(bool))); |
|
connect(BitTorrent::Session::instance(), SIGNAL(recursiveTorrentDownloadPossible(BitTorrent::TorrentHandle *const)), this, SLOT(askRecursiveTorrentDownloadConfirmation(BitTorrent::TorrentHandle *const))); |
|
|
|
qDebug("create tabWidget"); |
|
tabs = new HidableTabWidget(this); |
|
connect(tabs, SIGNAL(currentChanged(int)), this, SLOT(tab_changed(int))); |
|
|
|
vSplitter = new QSplitter(Qt::Horizontal, this); |
|
//vSplitter->setChildrenCollapsible(false); |
|
|
|
hSplitter = new QSplitter(Qt::Vertical, this); |
|
hSplitter->setChildrenCollapsible(false); |
|
hSplitter->setFrameShape(QFrame::NoFrame); |
|
|
|
// Name filter |
|
search_filter = new LineEdit(this); |
|
searchFilterAct = toolBar->insertWidget(actionLock_qBittorrent, search_filter); |
|
search_filter->setPlaceholderText(tr("Filter torrent list...")); |
|
search_filter->setFixedWidth(200); |
|
|
|
QWidget *spacer = new QWidget(this); |
|
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); |
|
toolBar->insertWidget(searchFilterAct, spacer); |
|
|
|
// Transfer List tab |
|
transferList = new TransferListWidget(hSplitter, this); |
|
//transferList->setStyleSheet("QTreeView {border: none;}"); // borderless |
|
properties = new PropertiesWidget(hSplitter, this, transferList); |
|
transferListFilters = new TransferListFiltersWidget(vSplitter, transferList); |
|
hSplitter->addWidget(transferList); |
|
hSplitter->addWidget(properties); |
|
vSplitter->addWidget(transferListFilters); |
|
vSplitter->addWidget(hSplitter); |
|
vSplitter->setCollapsible(0, true); |
|
vSplitter->setCollapsible(1, false); |
|
tabs->addTab(vSplitter, GuiIconProvider::instance()->getIcon("folder-remote"), tr("Transfers")); |
|
|
|
connect(search_filter, SIGNAL(textChanged(QString)), transferList, SLOT(applyNameFilter(QString))); |
|
connect(hSplitter, SIGNAL(splitterMoved(int, int)), this, SLOT(writeSettings())); |
|
connect(vSplitter, SIGNAL(splitterMoved(int, int)), this, SLOT(writeSettings())); |
|
connect(BitTorrent::Session::instance(), SIGNAL(trackersChanged(BitTorrent::TorrentHandle *const)), properties, SLOT(loadTrackers(BitTorrent::TorrentHandle *const))); |
|
connect(BitTorrent::Session::instance(), SIGNAL(trackersAdded(BitTorrent::TorrentHandle *const, const QList<BitTorrent::TrackerEntry> &)), transferListFilters, SLOT(addTrackers(BitTorrent::TorrentHandle *const, const QList<BitTorrent::TrackerEntry> &))); |
|
connect(BitTorrent::Session::instance(), SIGNAL(trackersRemoved(BitTorrent::TorrentHandle *const, const QList<BitTorrent::TrackerEntry> &)), transferListFilters, SLOT(removeTrackers(BitTorrent::TorrentHandle *const, const QList<BitTorrent::TrackerEntry> &))); |
|
connect(BitTorrent::Session::instance(), SIGNAL(trackerlessStateChanged(BitTorrent::TorrentHandle *const, bool)), transferListFilters, SLOT(changeTrackerless(BitTorrent::TorrentHandle *const, bool))); |
|
connect(BitTorrent::Session::instance(), SIGNAL(trackerSuccess(BitTorrent::TorrentHandle *const, const QString &)), transferListFilters, SLOT(trackerSuccess(BitTorrent::TorrentHandle *const, const QString &))); |
|
connect(BitTorrent::Session::instance(), SIGNAL(trackerError(BitTorrent::TorrentHandle *const, const QString &)), transferListFilters, SLOT(trackerError(BitTorrent::TorrentHandle *const, const QString &))); |
|
connect(BitTorrent::Session::instance(), SIGNAL(trackerWarning(BitTorrent::TorrentHandle *const, const QString &)), transferListFilters, SLOT(trackerWarning(BitTorrent::TorrentHandle *const, const QString &))); |
|
|
|
centralWidgetLayout->addWidget(tabs); |
|
|
|
prioSeparator = toolBar->insertSeparator(actionTopPriority); |
|
prioSeparatorMenu = menu_Edit->insertSeparator(actionTopPriority); |
|
|
|
// Transfer list slots |
|
connect(actionStart, SIGNAL(triggered()), transferList, SLOT(startSelectedTorrents())); |
|
connect(actionStart_All, SIGNAL(triggered()), transferList, SLOT(resumeAllTorrents())); |
|
connect(actionPause, SIGNAL(triggered()), transferList, SLOT(pauseSelectedTorrents())); |
|
connect(actionPause_All, SIGNAL(triggered()), transferList, SLOT(pauseAllTorrents())); |
|
connect(actionDelete, SIGNAL(triggered()), transferList, SLOT(deleteSelectedTorrents())); |
|
connect(actionTopPriority, SIGNAL(triggered()), transferList, SLOT(topPrioSelectedTorrents())); |
|
connect(actionIncreasePriority, SIGNAL(triggered()), transferList, SLOT(increasePrioSelectedTorrents())); |
|
connect(actionDecreasePriority, SIGNAL(triggered()), transferList, SLOT(decreasePrioSelectedTorrents())); |
|
connect(actionBottomPriority, SIGNAL(triggered()), transferList, SLOT(bottomPrioSelectedTorrents())); |
|
connect(actionToggleVisibility, SIGNAL(triggered()), this, SLOT(toggleVisibility())); |
|
connect(actionMinimize, SIGNAL(triggered()), SLOT(minimizeWindow())); |
|
|
|
#if defined(Q_OS_WIN) || defined(Q_OS_MAC) |
|
programUpdateTimer.setInterval(60 * 60 * 1000); |
|
programUpdateTimer.setSingleShot(true); |
|
connect(&programUpdateTimer, SIGNAL(timeout()), SLOT(checkProgramUpdate())); |
|
connect(actionCheck_for_updates, SIGNAL(triggered()), SLOT(checkProgramUpdate())); |
|
#else |
|
actionCheck_for_updates->setVisible(false); |
|
#endif |
|
|
|
m_pwr = new PowerManagement(this); |
|
preventTimer = new QTimer(this); |
|
connect(preventTimer, SIGNAL(timeout()), SLOT(checkForActiveTorrents())); |
|
|
|
// Configure BT session according to options |
|
loadPreferences(false); |
|
|
|
connect(BitTorrent::Session::instance(), SIGNAL(torrentsUpdated()), this, SLOT(updateGUI())); |
|
|
|
// Accept drag 'n drops |
|
setAcceptDrops(true); |
|
createKeyboardShortcuts(); |
|
// Create status bar |
|
status_bar = new StatusBar(QMainWindow::statusBar()); |
|
connect(status_bar->connectionStatusButton(), SIGNAL(clicked()), SLOT(showConnectionSettings())); |
|
connect(actionUse_alternative_speed_limits, SIGNAL(triggered()), status_bar, SLOT(toggleAlternativeSpeeds())); |
|
|
|
#ifdef Q_OS_MAC |
|
setUnifiedTitleAndToolBarOnMac(true); |
|
#endif |
|
|
|
// View settings |
|
actionTop_tool_bar->setChecked(pref->isToolbarDisplayed()); |
|
actionSpeed_in_title_bar->setChecked(pref->speedInTitleBar()); |
|
actionRSS_Reader->setChecked(pref->isRSSEnabled()); |
|
actionSearch_engine->setChecked(pref->isSearchEnabled()); |
|
actionExecution_Logs->setChecked(pref->isExecutionLogEnabled()); |
|
displayRSSTab(actionRSS_Reader->isChecked()); |
|
on_actionExecution_Logs_triggered(actionExecution_Logs->isChecked()); |
|
if (actionSearch_engine->isChecked()) |
|
QTimer::singleShot(0, this, SLOT(on_actionSearch_engine_triggered())); |
|
|
|
// Auto shutdown actions |
|
QActionGroup *autoShutdownGroup = new QActionGroup(this); |
|
autoShutdownGroup->setExclusive(true); |
|
autoShutdownGroup->addAction(actionAutoShutdown_Disabled); |
|
autoShutdownGroup->addAction(actionAutoExit_qBittorrent); |
|
autoShutdownGroup->addAction(actionAutoShutdown_system); |
|
autoShutdownGroup->addAction(actionAutoSuspend_system); |
|
autoShutdownGroup->addAction(actionAutoHibernate_system); |
|
#if (!defined(Q_OS_UNIX) || defined(Q_OS_MAC)) || defined(QT_DBUS_LIB) |
|
actionAutoShutdown_system->setChecked(pref->shutdownWhenDownloadsComplete()); |
|
actionAutoSuspend_system->setChecked(pref->suspendWhenDownloadsComplete()); |
|
actionAutoHibernate_system->setChecked(pref->hibernateWhenDownloadsComplete()); |
|
#else |
|
actionAutoShutdown_system->setDisabled(true); |
|
actionAutoSuspend_system->setDisabled(true); |
|
actionAutoHibernate_system->setDisabled(true); |
|
#endif |
|
actionAutoExit_qBittorrent->setChecked(pref->shutdownqBTWhenDownloadsComplete()); |
|
|
|
if (!autoShutdownGroup->checkedAction()) |
|
actionAutoShutdown_Disabled->setChecked(true); |
|
|
|
// Load Window state and sizes |
|
readSettings(); |
|
|
|
if (systrayIcon) { |
|
if (!(pref->startMinimized() || ui_locked)) { |
|
show(); |
|
activateWindow(); |
|
raise(); |
|
} |
|
else if (pref->startMinimized()) { |
|
showMinimized(); |
|
if (pref->minimizeToTray()) |
|
hide(); |
|
} |
|
} |
|
else { |
|
// Make sure the Window is visible if we don't have a tray icon |
|
if (pref->startMinimized()) { |
|
showMinimized(); |
|
} |
|
else { |
|
show(); |
|
activateWindow(); |
|
raise(); |
|
} |
|
} |
|
|
|
properties->readSettings(); |
|
|
|
// Start watching the executable for updates |
|
executable_watcher = new QFileSystemWatcher(this); |
|
connect(executable_watcher, SIGNAL(fileChanged(QString)), this, SLOT(notifyOfUpdate(QString))); |
|
executable_watcher->addPath(qApp->applicationFilePath()); |
|
|
|
transferList->setFocus(); |
|
|
|
// Update the number of torrents (tab) |
|
updateNbTorrents(); |
|
connect(transferList->getSourceModel(), SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(updateNbTorrents())); |
|
connect(transferList->getSourceModel(), SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SLOT(updateNbTorrents())); |
|
|
|
qDebug("GUI Built"); |
|
#ifdef Q_OS_WIN |
|
if (!pref->neverCheckFileAssoc() && (!Preferences::isTorrentFileAssocSet() || !Preferences::isMagnetLinkAssocSet())) { |
|
if (QMessageBox::question(0, tr("Torrent file association"), |
|
tr("qBittorrent is not the default application to open torrent files or Magnet links.\nDo you want to associate qBittorrent to torrent files and Magnet links?"), |
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes) { |
|
Preferences::setTorrentFileAssoc(true); |
|
Preferences::setMagnetLinkAssoc(true); |
|
} |
|
else { |
|
pref->setNeverCheckFileAssoc(); |
|
} |
|
} |
|
#endif |
|
#ifdef Q_OS_MAC |
|
qt_mac_set_dock_menu(getTrayIconMenu()); |
|
#endif |
|
} |
|
|
|
MainWindow::~MainWindow() |
|
{ |
|
#ifdef Q_OS_MAC |
|
// Workaround to avoid bug http://bugreports.qt.nokia.com/browse/QTBUG-7305 |
|
setUnifiedTitleAndToolBarOnMac(false); |
|
#endif |
|
} |
|
|
|
void MainWindow::addToolbarContextMenu() |
|
{ |
|
const Preferences* const pref = Preferences::instance(); |
|
toolbarMenu = new QMenu(this); |
|
|
|
toolBar->setContextMenuPolicy(Qt::CustomContextMenu); |
|
connect(toolBar, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(toolbarMenuRequested(QPoint))); |
|
|
|
QAction *iconsOnly = new QAction(tr("Icons Only"), toolbarMenu); |
|
connect(iconsOnly, SIGNAL(triggered()), this, SLOT(toolbarIconsOnly())); |
|
QAction *textOnly = new QAction(tr("Text Only"), toolbarMenu); |
|
connect(textOnly, SIGNAL(triggered()), this, SLOT(toolbarTextOnly())); |
|
QAction *textBesideIcons = new QAction(tr("Text Alongside Icons"), toolbarMenu); |
|
connect(textBesideIcons, SIGNAL(triggered()), this, SLOT(toolbarTextBeside())); |
|
QAction *textUnderIcons = new QAction(tr("Text Under Icons"), toolbarMenu); |
|
connect(textUnderIcons, SIGNAL(triggered()), this, SLOT(toolbarTextUnder())); |
|
QAction *followSystemStyle = new QAction(tr("Follow System Style"), toolbarMenu); |
|
connect(followSystemStyle, SIGNAL(triggered()), this, SLOT(toolbarFollowSystem())); |
|
toolbarMenu->addAction(iconsOnly); |
|
toolbarMenu->addAction(textOnly); |
|
toolbarMenu->addAction(textBesideIcons); |
|
toolbarMenu->addAction(textUnderIcons); |
|
toolbarMenu->addAction(followSystemStyle); |
|
QActionGroup *textPositionGroup = new QActionGroup(toolbarMenu); |
|
textPositionGroup->addAction(iconsOnly); |
|
iconsOnly->setCheckable(true); |
|
textPositionGroup->addAction(textOnly); |
|
textOnly->setCheckable(true); |
|
textPositionGroup->addAction(textBesideIcons); |
|
textBesideIcons->setCheckable(true); |
|
textPositionGroup->addAction(textUnderIcons); |
|
textUnderIcons->setCheckable(true); |
|
textPositionGroup->addAction(followSystemStyle); |
|
followSystemStyle->setCheckable(true); |
|
|
|
const Qt::ToolButtonStyle buttonStyle = static_cast<Qt::ToolButtonStyle>(pref->getToolbarTextPosition()); |
|
if (buttonStyle >= Qt::ToolButtonIconOnly && buttonStyle <= Qt::ToolButtonFollowStyle) |
|
toolBar->setToolButtonStyle(buttonStyle); |
|
switch (buttonStyle) { |
|
case Qt::ToolButtonIconOnly: |
|
iconsOnly->setChecked(true); |
|
break; |
|
case Qt::ToolButtonTextOnly: |
|
textOnly->setChecked(true); |
|
break; |
|
case Qt::ToolButtonTextBesideIcon: |
|
textBesideIcons->setChecked(true); |
|
break; |
|
case Qt::ToolButtonTextUnderIcon: |
|
textUnderIcons->setChecked(true); |
|
break; |
|
default: |
|
followSystemStyle->setChecked(true); |
|
} |
|
} |
|
|
|
void MainWindow::toolbarMenuRequested(QPoint point) |
|
{ |
|
toolbarMenu->exec(toolBar->mapToGlobal(point)); |
|
} |
|
|
|
void MainWindow::toolbarIconsOnly() |
|
{ |
|
toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly); |
|
Preferences::instance()->setToolbarTextPosition(Qt::ToolButtonIconOnly); |
|
} |
|
|
|
void MainWindow::toolbarTextOnly() |
|
{ |
|
toolBar->setToolButtonStyle(Qt::ToolButtonTextOnly); |
|
Preferences::instance()->setToolbarTextPosition(Qt::ToolButtonTextOnly); |
|
} |
|
|
|
void MainWindow::toolbarTextBeside() |
|
{ |
|
toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); |
|
Preferences::instance()->setToolbarTextPosition(Qt::ToolButtonTextBesideIcon); |
|
} |
|
|
|
void MainWindow::toolbarTextUnder() |
|
{ |
|
toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); |
|
Preferences::instance()->setToolbarTextPosition(Qt::ToolButtonTextUnderIcon); |
|
} |
|
|
|
void MainWindow::toolbarFollowSystem() |
|
{ |
|
toolBar->setToolButtonStyle(Qt::ToolButtonFollowStyle); |
|
Preferences::instance()->setToolbarTextPosition(Qt::ToolButtonFollowStyle); |
|
} |
|
|
|
void MainWindow::defineUILockPassword() |
|
{ |
|
QString old_pass_md5 = Preferences::instance()->getUILockPasswordMD5(); |
|
if (old_pass_md5.isNull()) old_pass_md5 = ""; |
|
bool ok = false; |
|
QString new_clear_password = AutoExpandableDialog::getText(this, tr("UI lock password"), tr("Please type the UI lock password:"), QLineEdit::Password, old_pass_md5, &ok); |
|
if (ok) { |
|
new_clear_password = new_clear_password.trimmed(); |
|
if (new_clear_password.size() < 3) { |
|
QMessageBox::warning(this, tr("Invalid password"), tr("The password should contain at least 3 characters")); |
|
return; |
|
} |
|
if (new_clear_password != old_pass_md5) |
|
Preferences::instance()->setUILockPassword(new_clear_password); |
|
QMessageBox::information(this, tr("Password update"), tr("The UI lock password has been successfully updated")); |
|
} |
|
} |
|
|
|
void MainWindow::clearUILockPassword() |
|
{ |
|
QMessageBox::StandardButton answer = QMessageBox::question(this, tr("Clear the password"), tr("Are you sure you want to clear the password?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); |
|
if (answer == QMessageBox::Yes) |
|
Preferences::instance()->clearUILockPassword(); |
|
} |
|
|
|
void MainWindow::on_actionLock_qBittorrent_triggered() |
|
{ |
|
Preferences* const pref = Preferences::instance(); |
|
// Check if there is a password |
|
if (pref->getUILockPasswordMD5().isEmpty()) { |
|
// Ask for a password |
|
bool ok = false; |
|
QString clear_password = AutoExpandableDialog::getText(this, tr("UI lock password"), tr("Please type the UI lock password:"), QLineEdit::Password, "", &ok); |
|
if (!ok) return; |
|
pref->setUILockPassword(clear_password); |
|
} |
|
// Lock the interface |
|
ui_locked = true; |
|
pref->setUILocked(true); |
|
myTrayIconMenu->setEnabled(false); |
|
hide(); |
|
} |
|
|
|
void MainWindow::displayRSSTab(bool enable) |
|
{ |
|
if (enable) { |
|
// RSS tab |
|
if (!rssWidget) { |
|
rssWidget = new RSSImp(tabs); |
|
connect(rssWidget, SIGNAL(updateRSSCount(int)), this, SLOT(updateRSSTabLabel(int))); |
|
int index_tab = tabs->addTab(rssWidget, tr("RSS (%1)").arg(0)); |
|
tabs->setTabIcon(index_tab, GuiIconProvider::instance()->getIcon("application-rss+xml")); |
|
} |
|
} |
|
else if (rssWidget) { |
|
delete rssWidget; |
|
} |
|
|
|
} |
|
|
|
void MainWindow::updateRSSTabLabel(int count) |
|
{ |
|
tabs->setTabText(tabs->indexOf(rssWidget), tr("RSS (%1)").arg(count)); |
|
} |
|
|
|
void MainWindow::displaySearchTab(bool enable) |
|
{ |
|
Preferences::instance()->setSearchEnabled(enable); |
|
if (enable) { |
|
// RSS tab |
|
if (!searchEngine) { |
|
searchEngine = new SearchWidget(this); |
|
tabs->insertTab(1, searchEngine, GuiIconProvider::instance()->getIcon("edit-find"), tr("Search")); |
|
} |
|
} |
|
else if (searchEngine) { |
|
delete searchEngine; |
|
} |
|
|
|
} |
|
|
|
void MainWindow::updateNbTorrents() |
|
{ |
|
tabs->setTabText(0, tr("Transfers (%1)").arg(transferList->getSourceModel()->rowCount())); |
|
} |
|
|
|
void MainWindow::on_actionDocumentation_triggered() const |
|
{ |
|
QDesktopServices::openUrl(QUrl(QString::fromUtf8("http://doc.qbittorrent.org"))); |
|
} |
|
|
|
void MainWindow::tab_changed(int new_tab) |
|
{ |
|
Q_UNUSED(new_tab); |
|
// We cannot rely on the index new_tab |
|
// because the tab order is undetermined now |
|
if (tabs->currentWidget() == vSplitter) { |
|
qDebug("Changed tab to transfer list, refreshing the list"); |
|
properties->loadDynamicData(); |
|
searchFilterAct->setVisible(true); |
|
return; |
|
} |
|
else { |
|
searchFilterAct->setVisible(false); |
|
} |
|
if (tabs->currentWidget() == searchEngine) { |
|
qDebug("Changed tab to search engine, giving focus to search input"); |
|
searchEngine->giveFocusToSearchInput(); |
|
} |
|
} |
|
|
|
void MainWindow::writeSettings() |
|
{ |
|
Preferences* const pref = Preferences::instance(); |
|
pref->setMainGeometry(saveGeometry()); |
|
// Splitter size |
|
pref->setMainVSplitterState(vSplitter->saveState()); |
|
properties->saveSettings(); |
|
} |
|
|
|
void MainWindow::cleanup() |
|
{ |
|
writeSettings(); |
|
|
|
delete executable_watcher; |
|
if (systrayCreator) |
|
systrayCreator->stop(); |
|
if (preventTimer) |
|
preventTimer->stop(); |
|
#if (defined(Q_OS_WIN) || defined(Q_OS_MAC)) |
|
programUpdateTimer.stop(); |
|
#endif |
|
delete search_filter; |
|
delete searchFilterAct; |
|
delete tabs; // this seems enough to also delete all contained widgets |
|
delete status_bar; |
|
delete m_pwr; |
|
delete toolbarMenu; |
|
} |
|
|
|
void MainWindow::readSettings() |
|
{ |
|
const Preferences* const pref = Preferences::instance(); |
|
const QByteArray mainGeo = pref->getMainGeometry(); |
|
if (!mainGeo.isEmpty()) |
|
if (restoreGeometry(mainGeo)) |
|
m_posInitialized = true; |
|
const QByteArray splitterState = pref->getMainVSplitterState(); |
|
if (splitterState.isEmpty()) |
|
// Default sizes |
|
vSplitter->setSizes(QList<int>() << 120 << vSplitter->width() - 120); |
|
else |
|
vSplitter->restoreState(splitterState); |
|
} |
|
|
|
void MainWindow::balloonClicked() |
|
{ |
|
if (isHidden()) { |
|
if (ui_locked) { |
|
// Ask for UI lock password |
|
if (!unlockUI()) |
|
return; |
|
} |
|
show(); |
|
if (isMinimized()) |
|
showNormal(); |
|
} |
|
|
|
raise(); |
|
activateWindow(); |
|
} |
|
|
|
void MainWindow::addTorrentFailed(const QString &error) const |
|
{ |
|
showNotificationBaloon(tr("Error"), tr("Failed to add torrent: %1").arg(error)); |
|
} |
|
|
|
// called when a torrent has finished |
|
void MainWindow::finishedTorrent(BitTorrent::TorrentHandle *const torrent) const |
|
{ |
|
showNotificationBaloon(tr("Download completion"), tr("'%1' has finished downloading.", "e.g: xxx.avi has finished downloading.").arg(torrent->name())); |
|
} |
|
|
|
// Notification when disk is full |
|
void MainWindow::fullDiskError(BitTorrent::TorrentHandle *const torrent, QString msg) const |
|
{ |
|
showNotificationBaloon(tr("I/O Error", "i.e: Input/Output Error"), tr("An I/O error occurred for torrent '%1'.\n Reason: %2", "e.g: An error occurred for torrent 'xxx.avi'.\n Reason: disk is full.").arg(torrent->name()).arg(msg)); |
|
} |
|
|
|
void MainWindow::createKeyboardShortcuts() |
|
{ |
|
actionCreate_torrent->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+N"))); |
|
actionOpen->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+O"))); |
|
actionDownload_from_URL->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+Shift+O"))); |
|
actionExit->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+Q"))); |
|
|
|
QShortcut *switchTransferShortcut = new QShortcut(QKeySequence("Alt+1"), this); |
|
connect(switchTransferShortcut, SIGNAL(activated()), this, SLOT(displayTransferTab())); |
|
QShortcut *switchSearchShortcut = new QShortcut(QKeySequence("Alt+2"), this); |
|
connect(switchSearchShortcut, SIGNAL(activated()), this, SLOT(displaySearchTab())); |
|
QShortcut *switchSearchShortcut2 = new QShortcut(QKeySequence("Ctrl+F"), this); |
|
connect(switchSearchShortcut2, SIGNAL(activated()), this, SLOT(displaySearchTab())); |
|
QShortcut *switchRSSShortcut = new QShortcut(QKeySequence("Alt+3"), this); |
|
connect(switchRSSShortcut, SIGNAL(activated()), this, SLOT(displayRSSTab())); |
|
|
|
actionDocumentation->setShortcut(QKeySequence("F1")); |
|
actionOptions->setShortcut(QKeySequence(QString::fromUtf8("Alt+O"))); |
|
actionStart->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+S"))); |
|
actionStart_All->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+Shift+S"))); |
|
actionPause->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+P"))); |
|
actionPause_All->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+Shift+P"))); |
|
actionBottomPriority->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+Shift+-"))); |
|
actionDecreasePriority->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+-"))); |
|
actionIncreasePriority->setShortcut(QKeySequence(QString::fromUtf8("Ctrl++"))); |
|
actionTopPriority->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+Shift++"))); |
|
#ifdef Q_OS_MAC |
|
actionMinimize->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+M"))); |
|
addAction(actionMinimize); |
|
#endif |
|
} |
|
|
|
// Keyboard shortcuts slots |
|
void MainWindow::displayTransferTab() const |
|
{ |
|
tabs->setCurrentWidget(transferList); |
|
} |
|
|
|
void MainWindow::displaySearchTab() const |
|
{ |
|
if (searchEngine) |
|
tabs->setCurrentWidget(searchEngine); |
|
} |
|
|
|
void MainWindow::displayRSSTab() const |
|
{ |
|
if (rssWidget) |
|
tabs->setCurrentWidget(rssWidget); |
|
} |
|
|
|
// End of keyboard shortcuts slots |
|
|
|
void MainWindow::askRecursiveTorrentDownloadConfirmation(BitTorrent::TorrentHandle *const torrent) |
|
{ |
|
Preferences* const pref = Preferences::instance(); |
|
if (pref->recursiveDownloadDisabled()) return; |
|
// Get Torrent name |
|
QString torrent_name = torrent->name(); |
|
QMessageBox confirmBox(QMessageBox::Question, tr("Recursive download confirmation"), tr("The torrent '%1' contains torrent files, do you want to proceed with their download?").arg(torrent_name)); |
|
QPushButton *yes = confirmBox.addButton(tr("Yes"), QMessageBox::YesRole); |
|
/*QPushButton *no = */ confirmBox.addButton(tr("No"), QMessageBox::NoRole); |
|
QPushButton *never = confirmBox.addButton(tr("Never"), QMessageBox::NoRole); |
|
confirmBox.exec(); |
|
|
|
if (confirmBox.clickedButton() == yes) |
|
BitTorrent::Session::instance()->recursiveTorrentDownload(torrent->hash()); |
|
else if (confirmBox.clickedButton() == never) |
|
pref->disableRecursiveDownload(); |
|
} |
|
|
|
void MainWindow::handleDownloadFromUrlFailure(QString url, QString reason) const |
|
{ |
|
// Display a message box |
|
showNotificationBaloon(tr("URL download error"), tr("Couldn't download file at URL '%1', reason: %2.").arg(url).arg(reason)); |
|
} |
|
|
|
void MainWindow::on_actionSet_global_upload_limit_triggered() |
|
{ |
|
qDebug() << Q_FUNC_INFO; |
|
bool ok; |
|
int cur_limit = BitTorrent::Session::instance()->uploadRateLimit(); |
|
const long new_limit = SpeedLimitDialog::askSpeedLimit(&ok, tr("Global Upload Speed Limit"), cur_limit); |
|
if (ok) { |
|
qDebug("Setting global upload rate limit to %.1fKb/s", new_limit / 1024.); |
|
BitTorrent::Session::instance()->setUploadRateLimit(new_limit); |
|
if (new_limit <= 0) |
|
Preferences::instance()->setGlobalUploadLimit(-1); |
|
else |
|
Preferences::instance()->setGlobalUploadLimit(new_limit / 1024.); |
|
} |
|
} |
|
|
|
void MainWindow::on_actionSet_global_download_limit_triggered() |
|
{ |
|
qDebug() << Q_FUNC_INFO; |
|
bool ok; |
|
int cur_limit = BitTorrent::Session::instance()->downloadRateLimit(); |
|
const long new_limit = SpeedLimitDialog::askSpeedLimit(&ok, tr("Global Download Speed Limit"), cur_limit); |
|
if (ok) { |
|
qDebug("Setting global download rate limit to %.1fKb/s", new_limit / 1024.); |
|
BitTorrent::Session::instance()->setDownloadRateLimit(new_limit); |
|
if (new_limit <= 0) |
|
Preferences::instance()->setGlobalDownloadLimit(-1); |
|
else |
|
Preferences::instance()->setGlobalDownloadLimit(new_limit / 1024.); |
|
} |
|
} |
|
|
|
// Necessary if we want to close the window |
|
// in one time if "close to systray" is enabled |
|
void MainWindow::on_actionExit_triggered() |
|
{ |
|
// UI locking enforcement. |
|
if (isHidden() && ui_locked) { |
|
// Ask for UI lock password |
|
if (!unlockUI()) |
|
return; |
|
} |
|
|
|
force_exit = true; |
|
close(); |
|
} |
|
|
|
QWidget* MainWindow::getCurrentTabWidget() const |
|
{ |
|
if (isMinimized() || !isVisible()) |
|
return 0; |
|
if (tabs->currentIndex() == 0) |
|
return transferList; |
|
return tabs->currentWidget(); |
|
} |
|
|
|
void MainWindow::setTabText(int index, QString text) const |
|
{ |
|
tabs->setTabText(index, text); |
|
} |
|
|
|
bool MainWindow::unlockUI() |
|
{ |
|
if (unlockDlgShowing) |
|
return false; |
|
else |
|
unlockDlgShowing = true; |
|
|
|
bool ok = false; |
|
QString clear_password = AutoExpandableDialog::getText(this, tr("UI lock password"), tr("Please type the UI lock password:"), QLineEdit::Password, "", &ok); |
|
unlockDlgShowing = false; |
|
if (!ok) return false; |
|
Preferences* const pref = Preferences::instance(); |
|
QString real_pass_md5 = pref->getUILockPasswordMD5(); |
|
QCryptographicHash md5(QCryptographicHash::Md5); |
|
md5.addData(clear_password.toLocal8Bit()); |
|
QString password_md5 = md5.result().toHex(); |
|
if (real_pass_md5 == password_md5) { |
|
ui_locked = false; |
|
pref->setUILocked(false); |
|
myTrayIconMenu->setEnabled(true); |
|
return true; |
|
} |
|
QMessageBox::warning(this, tr("Invalid password"), tr("The password is invalid")); |
|
return false; |
|
} |
|
|
|
void MainWindow::notifyOfUpdate(QString) |
|
{ |
|
// Show restart message |
|
status_bar->showRestartRequired(); |
|
// Delete the executable watcher |
|
delete executable_watcher; |
|
executable_watcher = 0; |
|
} |
|
|
|
// Toggle Main window visibility |
|
void MainWindow::toggleVisibility(QSystemTrayIcon::ActivationReason e) |
|
{ |
|
if (e == QSystemTrayIcon::Trigger || e == QSystemTrayIcon::DoubleClick) { |
|
if (isHidden()) { |
|
if (ui_locked) { |
|
// Ask for UI lock password |
|
if (!unlockUI()) |
|
return; |
|
} |
|
// Make sure the window is not minimized |
|
setWindowState(windowState() & (~Qt::WindowMinimized | Qt::WindowActive)); |
|
// Then show it |
|
show(); |
|
raise(); |
|
activateWindow(); |
|
} |
|
else { |
|
hide(); |
|
} |
|
} |
|
} |
|
|
|
// Display About Dialog |
|
void MainWindow::on_actionAbout_triggered() |
|
{ |
|
//About dialog |
|
if (aboutDlg) |
|
aboutDlg->setFocus(); |
|
else |
|
aboutDlg = new about(this); |
|
} |
|
|
|
void MainWindow::on_actionStatistics_triggered() |
|
{ |
|
if (statsDlg) |
|
statsDlg->setFocus(); |
|
else |
|
statsDlg = new StatsDialog(this); |
|
} |
|
|
|
void MainWindow::showEvent(QShowEvent *e) |
|
{ |
|
qDebug("** Show Event **"); |
|
|
|
if (getCurrentTabWidget() == transferList) |
|
properties->loadDynamicData(); |
|
|
|
e->accept(); |
|
|
|
// Make sure the window is initially centered |
|
if (!m_posInitialized) { |
|
move(Utils::Misc::screenCenter(this)); |
|
m_posInitialized = true; |
|
} |
|
} |
|
|
|
// Called when we close the program |
|
void MainWindow::closeEvent(QCloseEvent *e) |
|
{ |
|
Preferences* const pref = Preferences::instance(); |
|
const bool goToSystrayOnExit = pref->closeToTray(); |
|
if (!force_exit && systrayIcon && goToSystrayOnExit && !this->isHidden()) { |
|
hide(); |
|
e->accept(); |
|
return; |
|
} |
|
|
|
if (pref->confirmOnExit() && BitTorrent::Session::instance()->hasActiveTorrents()) { |
|
if (e->spontaneous() || force_exit) { |
|
if (!isVisible()) |
|
show(); |
|
QMessageBox confirmBox(QMessageBox::Question, tr("Exiting qBittorrent"), |
|
tr("Some files are currently transferring.\nAre you sure you want to quit qBittorrent?"), |
|
QMessageBox::NoButton, this); |
|
QPushButton *noBtn = confirmBox.addButton(tr("&No"), QMessageBox::NoRole); |
|
confirmBox.addButton(tr("&Yes"), QMessageBox::YesRole); |
|
QPushButton *alwaysBtn = confirmBox.addButton(tr("&Always Yes"), QMessageBox::YesRole); |
|
confirmBox.setDefaultButton(noBtn); |
|
confirmBox.exec(); |
|
if (!confirmBox.clickedButton() || confirmBox.clickedButton() == noBtn) { |
|
// Cancel exit |
|
e->ignore(); |
|
force_exit = false; |
|
return; |
|
} |
|
if (confirmBox.clickedButton() == alwaysBtn) { |
|
// Remember choice |
|
Preferences::instance()->setConfirmOnExit(false); |
|
} |
|
} |
|
} |
|
|
|
//abort search if any |
|
if (searchEngine) delete searchEngine; |
|
|
|
hide(); |
|
// Hide tray icon |
|
if (systrayIcon) |
|
systrayIcon->hide(); |
|
// Accept exit |
|
e->accept(); |
|
qApp->exit(); |
|
} |
|
|
|
// Display window to create a torrent |
|
void MainWindow::on_actionCreate_torrent_triggered() |
|
{ |
|
if (createTorrentDlg) |
|
createTorrentDlg->setFocus(); |
|
else |
|
createTorrentDlg = new TorrentCreatorDlg(this); |
|
} |
|
|
|
bool MainWindow::event(QEvent * e) |
|
{ |
|
switch(e->type()) { |
|
case QEvent::WindowStateChange: { |
|
qDebug("Window change event"); |
|
//Now check to see if the window is minimised |
|
if (isMinimized()) { |
|
qDebug("minimisation"); |
|
if (systrayIcon && Preferences::instance()->minimizeToTray()) { |
|
qDebug("Has active window: %d", (int)(qApp->activeWindow() != 0)); |
|
// Check if there is a modal window |
|
bool has_modal_window = false; |
|
foreach (QWidget *widget, QApplication::allWidgets()) { |
|
if (widget->isModal()) { |
|
has_modal_window = true; |
|
break; |
|
} |
|
} |
|
// Iconify if there is no modal window |
|
if (!has_modal_window) { |
|
qDebug("Minimize to Tray enabled, hiding!"); |
|
e->ignore(); |
|
QTimer::singleShot(0, this, SLOT(hide())); |
|
return true; |
|
} |
|
} |
|
} |
|
break; |
|
} |
|
#ifdef Q_OS_MAC |
|
case QEvent::ToolBarChange: { |
|
qDebug("MAC: Received a toolbar change event!"); |
|
bool ret = QMainWindow::event(e); |
|
|
|
qDebug("MAC: new toolbar visibility is %d", !actionTop_tool_bar->isChecked()); |
|
actionTop_tool_bar->toggle(); |
|
Preferences::instance()->setToolbarDisplayed(actionTop_tool_bar->isChecked()); |
|
return ret; |
|
} |
|
#endif |
|
default: |
|
break; |
|
} |
|
return QMainWindow::event(e); |
|
} |
|
|
|
// Action executed when a file is dropped |
|
void MainWindow::dropEvent(QDropEvent *event) |
|
{ |
|
event->acceptProposedAction(); |
|
QStringList files; |
|
if (event->mimeData()->hasUrls()) { |
|
const QList<QUrl> urls = event->mimeData()->urls(); |
|
foreach (const QUrl &url, urls) { |
|
if (!url.isEmpty()) { |
|
if (url.scheme().compare("file", Qt::CaseInsensitive) == 0) |
|
files << url.toLocalFile(); |
|
else |
|
files << url.toString(); |
|
} |
|
} |
|
} |
|
else { |
|
files = event->mimeData()->text().split(QString::fromUtf8("\n")); |
|
} |
|
|
|
// Add file to download list |
|
const bool useTorrentAdditionDialog = Preferences::instance()->useAdditionDialog(); |
|
foreach (QString file, files) { |
|
qDebug("Dropped file %s on download list", qPrintable(file)); |
|
if (useTorrentAdditionDialog) |
|
AddNewTorrentDialog::show(file, this); |
|
else |
|
BitTorrent::Session::instance()->addTorrent(file); |
|
} |
|
} |
|
|
|
// Decode if we accept drag 'n drop or not |
|
void MainWindow::dragEnterEvent(QDragEnterEvent *event) |
|
{ |
|
foreach (const QString &mime, event->mimeData()->formats()) |
|
qDebug("mimeData: %s", mime.toLocal8Bit().data()); |
|
if (event->mimeData()->hasFormat(QString::fromUtf8("text/plain")) || event->mimeData()->hasFormat(QString::fromUtf8("text/uri-list"))) |
|
event->acceptProposedAction(); |
|
} |
|
|
|
/***************************************************** |
|
* * |
|
* Torrent * |
|
* * |
|
*****************************************************/ |
|
|
|
// Display a dialog to allow user to add |
|
// torrents to download list |
|
void MainWindow::on_actionOpen_triggered() |
|
{ |
|
Preferences* const pref = Preferences::instance(); |
|
// Open File Open Dialog |
|
// Note: it is possible to select more than one file |
|
const QStringList pathsList = |
|
QFileDialog::getOpenFileNames(0, tr("Open Torrent Files"), pref->getMainLastDir(), |
|
tr("Torrent Files") + QString::fromUtf8(" (*.torrent)")); |
|
const bool useTorrentAdditionDialog = Preferences::instance()->useAdditionDialog(); |
|
if (!pathsList.isEmpty()) { |
|
foreach (QString file, pathsList) { |
|
qDebug("Dropped file %s on download list", qPrintable(file)); |
|
if (useTorrentAdditionDialog) |
|
AddNewTorrentDialog::show(file, this); |
|
else |
|
BitTorrent::Session::instance()->addTorrent(file); |
|
} |
|
|
|
// Save last dir to remember it |
|
QStringList top_dir = Utils::Fs::fromNativePath(pathsList.at(0)).split("/"); |
|
top_dir.removeLast(); |
|
pref->setMainLastDir(Utils::Fs::fromNativePath(top_dir.join("/"))); |
|
} |
|
} |
|
|
|
void MainWindow::activate() |
|
{ |
|
if (!ui_locked || unlockUI()) { |
|
show(); |
|
activateWindow(); |
|
raise(); |
|
} |
|
} |
|
|
|
void MainWindow::optionsSaved() |
|
{ |
|
loadPreferences(); |
|
} |
|
|
|
// Load program preferences |
|
void MainWindow::loadPreferences(bool configure_session) |
|
{ |
|
Logger::instance()->addMessage(tr("Options were saved successfully.")); |
|
const Preferences* const pref = Preferences::instance(); |
|
const bool newSystrayIntegration = pref->systrayIntegration(); |
|
actionLock_qBittorrent->setVisible(newSystrayIntegration); |
|
if (newSystrayIntegration != (systrayIcon != 0)) { |
|
if (newSystrayIntegration) { |
|
// create the trayicon |
|
if (!QSystemTrayIcon::isSystemTrayAvailable()) { |
|
if (!configure_session) { // Program startup |
|
systrayCreator = new QTimer(this); |
|
connect(systrayCreator, SIGNAL(timeout()), this, SLOT(createSystrayDelayed())); |
|
systrayCreator->setSingleShot(true); |
|
systrayCreator->start(2000); |
|
qDebug("Info: System tray is unavailable, trying again later."); |
|
} |
|
else { |
|
qDebug("Warning: System tray is unavailable."); |
|
} |
|
} |
|
else { |
|
createTrayIcon(); |
|
} |
|
} |
|
else { |
|
// Destroy trayicon |
|
delete systrayIcon; |
|
delete myTrayIconMenu; |
|
} |
|
} |
|
// Reload systray icon |
|
if (newSystrayIntegration && systrayIcon) |
|
systrayIcon->setIcon(getSystrayIcon()); |
|
// General |
|
if (pref->isToolbarDisplayed()) { |
|
toolBar->setVisible(true); |
|
} |
|
else { |
|
// Clear search filter before hiding the top toolbar |
|
search_filter->clear(); |
|
toolBar->setVisible(false); |
|
} |
|
|
|
if (pref->preventFromSuspend()) { |
|
preventTimer->start(PREVENT_SUSPEND_INTERVAL); |
|
} |
|
else { |
|
preventTimer->stop(); |
|
m_pwr->setActivityState(false); |
|
} |
|
|
|
transferList->setAlternatingRowColors(pref->useAlternatingRowColors()); |
|
properties->getFilesList()->setAlternatingRowColors(pref->useAlternatingRowColors()); |
|
properties->getTrackerList()->setAlternatingRowColors(pref->useAlternatingRowColors()); |
|
properties->getPeerList()->setAlternatingRowColors(pref->useAlternatingRowColors()); |
|
|
|
// Queueing System |
|
if (pref->isQueueingSystemEnabled()) { |
|
if (!actionDecreasePriority->isVisible()) { |
|
transferList->hidePriorityColumn(false); |
|
actionDecreasePriority->setVisible(true); |
|
actionIncreasePriority->setVisible(true); |
|
actionTopPriority->setVisible(true); |
|
actionBottomPriority->setVisible(true); |
|
prioSeparator->setVisible(true); |
|
prioSeparatorMenu->setVisible(true); |
|
} |
|
} |
|
else { |
|
if (actionDecreasePriority->isVisible()) { |
|
transferList->hidePriorityColumn(true); |
|
actionDecreasePriority->setVisible(false); |
|
actionIncreasePriority->setVisible(false); |
|
actionTopPriority->setVisible(false); |
|
actionBottomPriority->setVisible(false); |
|
prioSeparator->setVisible(false); |
|
prioSeparatorMenu->setVisible(false); |
|
} |
|
} |
|
|
|
// Torrent properties |
|
properties->reloadPreferences(); |
|
|
|
#if defined(Q_OS_WIN) || defined(Q_OS_MAC) |
|
if (pref->isUpdateCheckEnabled()) |
|
checkProgramUpdate(); |
|
else |
|
programUpdateTimer.stop(); |
|
#endif |
|
|
|
qDebug("GUI settings loaded"); |
|
} |
|
|
|
void MainWindow::addUnauthenticatedTracker(const QPair<BitTorrent::TorrentHandle*, QString> &tracker) |
|
{ |
|
// Trackers whose authentication was cancelled |
|
if (unauthenticated_trackers.indexOf(tracker) < 0) |
|
unauthenticated_trackers << tracker; |
|
} |
|
|
|
// Called when a tracker requires authentication |
|
void MainWindow::trackerAuthenticationRequired(BitTorrent::TorrentHandle *const torrent) |
|
{ |
|
if (unauthenticated_trackers.indexOf(qMakePair(torrent, torrent->currentTracker())) < 0) |
|
// Tracker login |
|
new trackerLogin(this, torrent); |
|
} |
|
|
|
// Check connection status and display right icon |
|
void MainWindow::updateGUI() |
|
{ |
|
BitTorrent::SessionStatus status = BitTorrent::Session::instance()->status(); |
|
|
|
// update global informations |
|
if (systrayIcon) { |
|
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)) |
|
QString html = "<div style='background-color: #678db2; color: #fff;height: 18px; font-weight: bold; margin-bottom: 5px;'>"; |
|
html += "qBittorrent"; |
|
html += "</div>"; |
|
html += "<div style='vertical-align: baseline; height: 18px;'>"; |
|
html += "<img src=':/icons/skin/download.png'/> " + tr("DL speed: %1", "e.g: Download speed: 10 KiB/s").arg(Utils::Misc::friendlyUnit(status.payloadDownloadRate(), true)); |
|
html += "</div>"; |
|
html += "<div style='vertical-align: baseline; height: 18px;'>"; |
|
html += "<img src=':/icons/skin/seeding.png'/> " + tr("UP speed: %1", "e.g: Upload speed: 10 KiB/s").arg(Utils::Misc::friendlyUnit(status.payloadUploadRate(), true)); |
|
html += "</div>"; |
|
#else |
|
// OSes such as Windows do not support html here |
|
QString html = tr("DL speed: %1", "e.g: Download speed: 10 KiB/s").arg(Utils::Misc::friendlyUnit(status.payloadDownloadRate(), true)); |
|
html += "\n"; |
|
html += tr("UP speed: %1", "e.g: Upload speed: 10 KiB/s").arg(Utils::Misc::friendlyUnit(status.payloadUploadRate(), true)); |
|
#endif |
|
systrayIcon->setToolTip(html); // tray icon |
|
} |
|
if (displaySpeedInTitle) |
|
setWindowTitle(tr("[D: %1, U: %2] qBittorrent %3", "D = Download; U = Upload; %3 is qBittorrent version").arg(Utils::Misc::friendlyUnit(status.payloadDownloadRate(), true)).arg(Utils::Misc::friendlyUnit(status.payloadUploadRate(), true)).arg(QString::fromUtf8(VERSION))); |
|
} |
|
|
|
void MainWindow::showNotificationBaloon(QString title, QString msg) const |
|
{ |
|
if (!Preferences::instance()->useProgramNotification()) return; |
|
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)) && defined(QT_DBUS_LIB) |
|
org::freedesktop::Notifications notifications("org.freedesktop.Notifications", |
|
"/org/freedesktop/Notifications", |
|
QDBusConnection::sessionBus()); |
|
// Testing for 'notifications.isValid()' isn't helpful here. |
|
// If the notification daemon is configured to run 'as needed' |
|
// the above check can be false if the daemon wasn't started |
|
// by another application. In this case DBus will be able to |
|
// start the notification daemon and complete our request. Such |
|
// a daemon is xfce4-notifyd, DBus autostarts it and after |
|
// some inactivity shuts it down. Other DEs, like GNOME, choose |
|
// to start their daemons at the session startup and have it sit |
|
// idling for the whole session. |
|
QVariantMap hints; |
|
hints["desktop-entry"] = "qBittorrent"; |
|
QDBusPendingReply<uint> reply = notifications.Notify("qBittorrent", 0, "qbittorrent", title, |
|
msg, QStringList(), hints, -1); |
|
reply.waitForFinished(); |
|
if (!reply.isError()) |
|
return; |
|
#endif |
|
if (systrayIcon && QSystemTrayIcon::supportsMessages()) |
|
systrayIcon->showMessage(title, msg, QSystemTrayIcon::Information, TIME_TRAY_BALLOON); |
|
} |
|
|
|
/***************************************************** |
|
* * |
|
* Utils * |
|
* * |
|
*****************************************************/ |
|
|
|
void MainWindow::downloadFromURLList(const QStringList& url_list) |
|
{ |
|
const bool useTorrentAdditionDialog = Preferences::instance()->useAdditionDialog(); |
|
foreach (QString url, url_list) { |
|
if ((url.size() == 40 && !url.contains(QRegExp("[^0-9A-Fa-f]"))) |
|
|| (url.size() == 32 && !url.contains(QRegExp("[^2-7A-Za-z]")))) |
|
url = "magnet:?xt=urn:btih:" + url; |
|
|
|
if (useTorrentAdditionDialog) |
|
AddNewTorrentDialog::show(url, this); |
|
else |
|
BitTorrent::Session::instance()->addTorrent(url); |
|
} |
|
} |
|
|
|
/***************************************************** |
|
* * |
|
* Options * |
|
* * |
|
*****************************************************/ |
|
|
|
void MainWindow::createSystrayDelayed() |
|
{ |
|
static int timeout = 20; |
|
if (QSystemTrayIcon::isSystemTrayAvailable()) { |
|
// Ok, systray integration is now supported |
|
// Create systray icon |
|
createTrayIcon(); |
|
delete systrayCreator; |
|
} |
|
else { |
|
if (timeout) { |
|
// Retry a bit later |
|
systrayCreator->start(2000); |
|
--timeout; |
|
} |
|
else { |
|
// Timed out, apparently system really does not |
|
// support systray icon |
|
delete systrayCreator; |
|
// Disable it in program preferences to |
|
// avoid trying at each startup |
|
Preferences::instance()->setSystrayIntegration(false); |
|
} |
|
} |
|
} |
|
|
|
void MainWindow::updateAltSpeedsBtn(bool alternative) |
|
{ |
|
actionUse_alternative_speed_limits->setChecked(alternative); |
|
} |
|
|
|
void MainWindow::updateTrayIconMenu() |
|
{ |
|
actionToggleVisibility->setText(isVisible() ? tr("Hide") : tr("Show")); |
|
} |
|
|
|
QMenu* MainWindow::getTrayIconMenu() |
|
{ |
|
if (myTrayIconMenu) |
|
return myTrayIconMenu; |
|
// Tray icon Menu |
|
myTrayIconMenu = new QMenu(this); |
|
connect(myTrayIconMenu, SIGNAL(aboutToShow()), SLOT(updateTrayIconMenu())); |
|
myTrayIconMenu->addAction(actionToggleVisibility); |
|
myTrayIconMenu->addSeparator(); |
|
myTrayIconMenu->addAction(actionOpen); |
|
myTrayIconMenu->addAction(actionDownload_from_URL); |
|
myTrayIconMenu->addSeparator(); |
|
const bool isAltBWEnabled = Preferences::instance()->isAltBandwidthEnabled(); |
|
updateAltSpeedsBtn(isAltBWEnabled); |
|
actionUse_alternative_speed_limits->setChecked(isAltBWEnabled); |
|
myTrayIconMenu->addAction(actionUse_alternative_speed_limits); |
|
myTrayIconMenu->addAction(actionSet_global_download_limit); |
|
myTrayIconMenu->addAction(actionSet_global_upload_limit); |
|
myTrayIconMenu->addSeparator(); |
|
myTrayIconMenu->addAction(actionStart_All); |
|
myTrayIconMenu->addAction(actionPause_All); |
|
myTrayIconMenu->addSeparator(); |
|
myTrayIconMenu->addAction(actionExit); |
|
if (ui_locked) |
|
myTrayIconMenu->setEnabled(false); |
|
return myTrayIconMenu; |
|
} |
|
|
|
void MainWindow::createTrayIcon() |
|
{ |
|
// Tray icon |
|
systrayIcon = new QSystemTrayIcon(getSystrayIcon(), this); |
|
|
|
systrayIcon->setContextMenu(getTrayIconMenu()); |
|
connect(systrayIcon, SIGNAL(messageClicked()), this, SLOT(balloonClicked())); |
|
// End of Icon Menu |
|
connect(systrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(toggleVisibility(QSystemTrayIcon::ActivationReason))); |
|
systrayIcon->show(); |
|
} |
|
|
|
// Display Program Options |
|
void MainWindow::on_actionOptions_triggered() |
|
{ |
|
if (options) { |
|
// Get focus |
|
options->setFocus(); |
|
} |
|
else { |
|
options = new options_imp(this); |
|
connect(options, SIGNAL(status_changed()), this, SLOT(optionsSaved())); |
|
} |
|
} |
|
|
|
void MainWindow::on_actionTop_tool_bar_triggered() |
|
{ |
|
bool is_visible = static_cast<QAction*>(sender())->isChecked(); |
|
toolBar->setVisible(is_visible); |
|
Preferences::instance()->setToolbarDisplayed(is_visible); |
|
} |
|
|
|
void MainWindow::on_actionSpeed_in_title_bar_triggered() |
|
{ |
|
displaySpeedInTitle = static_cast<QAction*>(sender())->isChecked(); |
|
Preferences::instance()->showSpeedInTitleBar(displaySpeedInTitle); |
|
if (displaySpeedInTitle) |
|
updateGUI(); |
|
else |
|
setWindowTitle(QString("qBittorrent %1").arg(QString::fromUtf8(VERSION))); |
|
} |
|
|
|
void MainWindow::on_actionRSS_Reader_triggered() |
|
{ |
|
Preferences::instance()->setRSSEnabled(actionRSS_Reader->isChecked()); |
|
displayRSSTab(actionRSS_Reader->isChecked()); |
|
} |
|
|
|
void MainWindow::on_actionSearch_engine_triggered() |
|
{ |
|
if (!has_python && actionSearch_engine->isChecked()) { |
|
int pythonVersion = Utils::Misc::pythonVersion(); |
|
|
|
// Check if python is already in PATH |
|
if (pythonVersion > 0) |
|
Logger::instance()->addMessage(tr("Python found in %1").arg("PATH"), Log::INFO); // Prevent translators from messing with PATH |
|
#ifdef Q_OS_WIN |
|
else if (addPythonPathToEnv()) |
|
pythonVersion = Utils::Misc::pythonVersion(); |
|
#endif |
|
|
|
bool res = false; |
|
|
|
if ((pythonVersion == 2) || (pythonVersion == 3)) { |
|
// Check python minimum requirement: 2.7.0/3.3.0 |
|
QString version = Utils::Misc::pythonVersionComplete(); |
|
QStringList splitted = version.split('.'); |
|
if (splitted.size() > 1) { |
|
int middleVer = splitted.at(1).toInt(); |
|
if ((pythonVersion == 2 && middleVer < 7) || (pythonVersion == 3 && middleVer < 3)) { |
|
QMessageBox::information(this, tr("Old Python Interpreter"), tr("Your Python version %1 is outdated. Please upgrade to latest version for search engines to work. Minimum requirement: 2.7.0/3.3.0.").arg(version)); |
|
actionSearch_engine->setChecked(false); |
|
Preferences::instance()->setSearchEnabled(false); |
|
return; |
|
} |
|
else { |
|
res = true; |
|
} |
|
} |
|
else { |
|
QMessageBox::information(this, tr("Undetermined Python version"), tr("Couldn't determine your Python version (%1). Search engine disabled.").arg(version)); |
|
actionSearch_engine->setChecked(false); |
|
Preferences::instance()->setSearchEnabled(false); |
|
return; |
|
} |
|
} |
|
|
|
if (res) { |
|
has_python = true; |
|
} |
|
#ifdef Q_OS_WIN |
|
else if (QMessageBox::question(this, tr("Missing Python Interpreter"), |
|
tr("Python is required to use the search engine but it does not seem to be installed.\nDo you want to install it now?"), |
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes) { |
|
// Download and Install Python |
|
installPython(); |
|
actionSearch_engine->setChecked(false); |
|
Preferences::instance()->setSearchEnabled(false); |
|
return; |
|
} |
|
#endif |
|
else { |
|
#ifndef Q_OS_WIN |
|
QMessageBox::information(this, tr("Missing Python Interpreter"), tr("Python is required to use the search engine but it does not seem to be installed.")); |
|
#endif |
|
actionSearch_engine->setChecked(false); |
|
Preferences::instance()->setSearchEnabled(false); |
|
return; |
|
} |
|
} |
|
displaySearchTab(actionSearch_engine->isChecked()); |
|
} |
|
|
|
void MainWindow::on_action_Import_Torrent_triggered() |
|
{ |
|
TorrentImportDlg::importTorrent(); |
|
} |
|
|
|
/***************************************************** |
|
* * |
|
* HTTP Downloader * |
|
* * |
|
*****************************************************/ |
|
|
|
// Display an input dialog to prompt user for |
|
// an url |
|
void MainWindow::on_actionDownload_from_URL_triggered() |
|
{ |
|
if (!downloadFromURLDialog) { |
|
downloadFromURLDialog = new downloadFromURL(this); |
|
connect(downloadFromURLDialog, SIGNAL(urlsReadyToBeDownloaded(QStringList)), this, SLOT(downloadFromURLList(QStringList))); |
|
} |
|
} |
|
|
|
#if defined(Q_OS_WIN) || defined(Q_OS_MAC) |
|
|
|
void MainWindow::handleUpdateCheckFinished(bool update_available, QString new_version, bool invokedByUser) |
|
{ |
|
QMessageBox::StandardButton answer = QMessageBox::Yes; |
|
if (update_available) { |
|
answer = QMessageBox::question(this, tr("qBittorrent Update Available"), |
|
tr("A new version is available.\nUpdate to version %1?").arg(new_version), |
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); |
|
if (answer == QMessageBox::Yes) { |
|
// The user want to update, let's download the update |
|
ProgramUpdater* updater = dynamic_cast<ProgramUpdater*>(sender()); |
|
updater->updateProgram(); |
|
} |
|
} |
|
else if (invokedByUser) { |
|
QMessageBox::information(this, tr("Already Using the Latest qBittorrent Version"), |
|
tr("No updates available.\nYou are already using the latest version.")); |
|
} |
|
sender()->deleteLater(); |
|
actionCheck_for_updates->setEnabled(true); |
|
actionCheck_for_updates->setText(tr("&Check for Updates")); |
|
actionCheck_for_updates->setToolTip(tr("Check for program updates")); |
|
// Don't bother the user again in this session if he chose to ignore the update |
|
if (Preferences::instance()->isUpdateCheckEnabled() && answer == QMessageBox::Yes) |
|
programUpdateTimer.start(); |
|
} |
|
#endif |
|
|
|
void MainWindow::on_actionDonate_money_triggered() |
|
{ |
|
QDesktopServices::openUrl(QUrl("http://www.qbittorrent.org/donate")); |
|
} |
|
|
|
void MainWindow::showConnectionSettings() |
|
{ |
|
on_actionOptions_triggered(); |
|
options->showConnectionTab(); |
|
} |
|
|
|
void MainWindow::minimizeWindow() |
|
{ |
|
setWindowState(windowState() ^ Qt::WindowMinimized); |
|
} |
|
|
|
void MainWindow::on_actionExecution_Logs_triggered(bool checked) |
|
{ |
|
if (checked) { |
|
Q_ASSERT(!m_executionLog); |
|
m_executionLog = new ExecutionLog(tabs); |
|
int index_tab = tabs->addTab(m_executionLog, tr("Execution Log")); |
|
tabs->setTabIcon(index_tab, GuiIconProvider::instance()->getIcon("view-calendar-journal")); |
|
} |
|
else if (m_executionLog) { |
|
delete m_executionLog; |
|
} |
|
Preferences::instance()->setExecutionLogEnabled(checked); |
|
} |
|
|
|
void MainWindow::on_actionAutoExit_qBittorrent_toggled(bool enabled) |
|
{ |
|
qDebug() << Q_FUNC_INFO << enabled; |
|
Preferences::instance()->setShutdownqBTWhenDownloadsComplete(enabled); |
|
} |
|
|
|
void MainWindow::on_actionAutoSuspend_system_toggled(bool enabled) |
|
{ |
|
qDebug() << Q_FUNC_INFO << enabled; |
|
Preferences::instance()->setSuspendWhenDownloadsComplete(enabled); |
|
} |
|
|
|
void MainWindow::on_actionAutoHibernate_system_toggled(bool enabled) |
|
{ |
|
qDebug() << Q_FUNC_INFO << enabled; |
|
Preferences::instance()->setHibernateWhenDownloadsComplete(enabled); |
|
} |
|
|
|
void MainWindow::on_actionAutoShutdown_system_toggled(bool enabled) |
|
{ |
|
qDebug() << Q_FUNC_INFO << enabled; |
|
Preferences::instance()->setShutdownWhenDownloadsComplete(enabled); |
|
} |
|
|
|
void MainWindow::checkForActiveTorrents() |
|
{ |
|
m_pwr->setActivityState(BitTorrent::Session::instance()->hasActiveTorrents()); |
|
} |
|
|
|
QIcon MainWindow::getSystrayIcon() const |
|
{ |
|
TrayIcon::Style style = Preferences::instance()->trayIconStyle(); |
|
switch(style) { |
|
case TrayIcon::MONO_DARK: |
|
return QIcon(":/icons/skin/qbittorrent_mono_dark.png"); |
|
case TrayIcon::MONO_LIGHT: |
|
return QIcon(":/icons/skin/qbittorrent_mono_light.png"); |
|
default: |
|
break; |
|
} |
|
|
|
QIcon icon; |
|
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)) |
|
if (Preferences::instance()->useSystemIconTheme()) |
|
icon = QIcon::fromTheme("qbittorrent"); |
|
|
|
#endif |
|
if (icon.isNull()) { |
|
icon.addFile(":/icons/skin/qbittorrent22.png", QSize(22, 22)); |
|
icon.addFile(":/icons/skin/qbittorrent16.png", QSize(16, 16)); |
|
icon.addFile(":/icons/skin/qbittorrent32.png", QSize(32, 32)); |
|
} |
|
return icon; |
|
} |
|
|
|
#if defined(Q_OS_WIN) || defined(Q_OS_MAC) |
|
void MainWindow::checkProgramUpdate() |
|
{ |
|
programUpdateTimer.stop(); // If the user had clicked the menu item |
|
actionCheck_for_updates->setEnabled(false); |
|
actionCheck_for_updates->setText(tr("Checking for Updates...")); |
|
actionCheck_for_updates->setToolTip(tr("Already checking for program updates in the background")); |
|
bool invokedByUser = actionCheck_for_updates == qobject_cast<QAction*>(sender()); |
|
ProgramUpdater *updater = new ProgramUpdater(this, invokedByUser); |
|
connect(updater, SIGNAL(updateCheckFinished(bool, QString, bool)), SLOT(handleUpdateCheckFinished(bool, QString, bool))); |
|
updater->checkForUpdates(); |
|
} |
|
#endif |
|
|
|
#ifdef Q_OS_WIN |
|
bool MainWindow::addPythonPathToEnv() |
|
{ |
|
if (has_python) |
|
return true; |
|
QString python_path = Preferences::getPythonPath(); |
|
if (!python_path.isEmpty()) { |
|
Logger::instance()->addMessage(tr("Python found in '%1'").arg(Utils::Fs::toNativePath(python_path)), Log::INFO); |
|
// Add it to PATH envvar |
|
QString path_envar = QString::fromLocal8Bit(qgetenv("PATH").constData()); |
|
if (path_envar.isNull()) |
|
path_envar = ""; |
|
path_envar = python_path + ";" + path_envar; |
|
qDebug("New PATH envvar is: %s", qPrintable(path_envar)); |
|
qputenv("PATH", Utils::Fs::toNativePath(path_envar).toLocal8Bit()); |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
void MainWindow::installPython() |
|
{ |
|
setCursor(QCursor(Qt::WaitCursor)); |
|
// Download python |
|
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl("https://www.python.org/ftp/python/3.4.3/python-3.4.3.msi", true); |
|
connect(handler, SIGNAL(downloadFinished(QString, QString)), this, SLOT(pythonDownloadSuccess(QString, QString))); |
|
connect(handler, SIGNAL(downloadFailed(QString, QString)), this, SLOT(pythonDownloadFailure(QString, QString))); |
|
} |
|
|
|
void MainWindow::pythonDownloadSuccess(const QString &url, const QString &filePath) |
|
{ |
|
Q_UNUSED(url) |
|
setCursor(QCursor(Qt::ArrowCursor)); |
|
QFile::rename(filePath, filePath + ".msi"); |
|
QProcess installer; |
|
qDebug("Launching Python installer in passive mode..."); |
|
|
|
installer.start("msiexec.exe /passive /i " + Utils::Fs::toNativePath(filePath) + ".msi"); |
|
// Wait for setup to complete |
|
installer.waitForFinished(); |
|
|
|
qDebug("Installer stdout: %s", installer.readAllStandardOutput().data()); |
|
qDebug("Installer stderr: %s", installer.readAllStandardError().data()); |
|
qDebug("Setup should be complete!"); |
|
// Delete temp file |
|
Utils::Fs::forceRemove(filePath); |
|
// Reload search engine |
|
has_python = addPythonPathToEnv(); |
|
if (has_python) { |
|
// Make it print the version to Log |
|
Utils::Misc::pythonVersion(); |
|
actionSearch_engine->setChecked(true); |
|
displaySearchTab(true); |
|
} |
|
} |
|
|
|
void MainWindow::pythonDownloadFailure(const QString &url, const QString &error) |
|
{ |
|
Q_UNUSED(url) |
|
setCursor(QCursor(Qt::ArrowCursor)); |
|
QMessageBox::warning(this, tr("Download error"), tr("Python setup could not be downloaded, reason: %1.\nPlease install it manually.").arg(error)); |
|
} |
|
#endif
|
|
|