From 2742a54d6e82e5d1833e3bf3624f63cd936a4810 Mon Sep 17 00:00:00 2001 From: Christophe Dumez Date: Sun, 16 Aug 2009 03:09:20 +0000 Subject: [PATCH] - Rewrited torrent resume code to make it cleaner and more generic * magnet URI support should be easy to implement now Warning: Since a lot of code was rewrited, some bugs may have been introduced --- Changelog | 3 + src/GUI.cpp | 2233 ++++++++++++++++++----------------- src/arborescence.h | 6 +- src/bittorrent.cpp | 702 +++++------ src/bittorrent.h | 10 +- src/properties_imp.cpp | 118 +- src/properties_imp.h | 4 +- src/qtorrenthandle.cpp | 15 + src/qtorrenthandle.h | 3 + src/torrentAddition.h | 28 +- src/torrentPersistentData.h | 339 ++++++ 11 files changed, 1842 insertions(+), 1619 deletions(-) create mode 100644 src/torrentPersistentData.h diff --git a/Changelog b/Changelog index 23dbd5bb2..886042db9 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,6 @@ +* Unknown - Christophe Dumez - v1.5.0 + - BUGFIX: torrent resume code rewrited + * Thu Aug 13 2009 - Christophe Dumez - v1.4.0 - FEATURE: Display swarm information in lists - FEATURE: Allow to define temporary download folder diff --git a/src/GUI.cpp b/src/GUI.cpp index baee36988..7a9164d3e 100644 --- a/src/GUI.cpp +++ b/src/GUI.cpp @@ -35,13 +35,13 @@ #include #include #ifdef QT_4_4 - #include - #include - #include - #include +#include +#include +#include +#include #else - #include - #include +#include +#include #endif #include #include @@ -67,6 +67,7 @@ #include #include "console_imp.h" #include "httpserver.h" +#include "torrentPersistentData.h" using namespace libtorrent; @@ -171,7 +172,7 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), dis // Configure BT session according to options configureSession(true); // Resume unfinished torrents - BTSession->resumeUnfinishedTorrents(); + BTSession->startUpTorrents(); downloadingTorrentTab->loadLastSortedColumn(); finishedTorrentTab->loadLastSortedColumn(); // Add torrent given on command line @@ -198,362 +199,362 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), dis #endif if (!localServer->listen("qBittorrent-"+uid)) { #else - localServer = new QTcpServer(); - if (!localServer->listen(QHostAddress::LocalHost)) { + localServer = new QTcpServer(); + if (!localServer->listen(QHostAddress::LocalHost)) { #endif - std::cerr << "Couldn't create socket, single instance mode won't work...\n"; - } + std::cerr << "Couldn't create socket, single instance mode won't work...\n"; + } #ifndef QT_4_4 - else { - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - settings.setValue(QString::fromUtf8("uniqueInstancePort"), localServer->serverPort()); - } + else { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + settings.setValue(QString::fromUtf8("uniqueInstancePort"), localServer->serverPort()); + } #endif - connect(localServer, SIGNAL(newConnection()), this, SLOT(acceptConnection())); - // Start connection checking timer - checkConnect = new QTimer(this); - connect(checkConnect, SIGNAL(timeout()), this, SLOT(checkConnectionStatus())); - checkConnect->start(5000); - // Accept drag 'n drops - setAcceptDrops(true); - createKeyboardShortcuts(); - connecStatusLblIcon = new QLabel(); - connecStatusLblIcon->setFrameShape(QFrame::NoFrame); - connecStatusLblIcon->setPixmap(QPixmap(QString::fromUtf8(":/Icons/skin/firewalled.png"))); - connecStatusLblIcon->setToolTip(QString::fromUtf8("")+tr("Connection status:")+QString::fromUtf8("
")+QString::fromUtf8("")+tr("No direct connections. This may indicate network configuration problems.")+QString::fromUtf8("")); - dlSpeedLbl = new QLabel(tr("DL: %1 KiB/s").arg("0.0")); - upSpeedLbl = new QLabel(tr("UP: %1 KiB/s").arg("0.0")); - ratioLbl = new QLabel(tr("Ratio: %1").arg("1.0")); - DHTLbl = new QLabel(tr("DHT: %1 nodes").arg(0)); - statusSep1 = new QFrame(); - statusSep1->setFixedWidth(1); - statusSep1->setFrameStyle(QFrame::Box); - statusSep2 = new QFrame(); - statusSep2->setFixedWidth(1); - statusSep2->setFrameStyle(QFrame::Box); - statusSep3 = new QFrame(); - statusSep3->setFixedWidth(1); - statusSep3->setFrameStyle(QFrame::Box); - statusSep4 = new QFrame(); - statusSep4->setFixedWidth(1); - statusSep4->setFrameStyle(QFrame::Box); - QMainWindow::statusBar()->addPermanentWidget(DHTLbl); - QMainWindow::statusBar()->addPermanentWidget(statusSep1); - QMainWindow::statusBar()->addPermanentWidget(connecStatusLblIcon); - QMainWindow::statusBar()->addPermanentWidget(statusSep2); - QMainWindow::statusBar()->addPermanentWidget(dlSpeedLbl); - QMainWindow::statusBar()->addPermanentWidget(statusSep3); - QMainWindow::statusBar()->addPermanentWidget(upSpeedLbl); - QMainWindow::statusBar()->addPermanentWidget(statusSep4); - QMainWindow::statusBar()->addPermanentWidget(ratioLbl); - if(!settings.value(QString::fromUtf8("Preferences/General/StartMinimized"), false).toBool()) { - show(); - } - scrapeTimer = new QTimer(this); - connect(scrapeTimer, SIGNAL(timeout()), this, SLOT(scrapeTrackers())); - scrapeTimer->start(20000); - qDebug("GUI Built"); -} - -// Destructor -GUI::~GUI() { - qDebug("GUI destruction"); - hide(); - // Do this as soon as possible - BTSession->saveDHTEntry(); - BTSession->saveSessionState(); - BTSession->saveFastResumeData(); - scrapeTimer->stop(); - delete scrapeTimer; - delete dlSpeedLbl; - delete upSpeedLbl; - delete ratioLbl; - delete DHTLbl; - delete statusSep1; - delete statusSep2; - delete statusSep3; - delete statusSep4; - if(rssWidget != 0) - delete rssWidget; - delete searchEngine; - delete refresher; - delete downloadingTorrentTab; - delete finishedTorrentTab; - delete checkConnect; - qDebug("1"); - if(systrayCreator) { - delete systrayCreator; - } - if(systrayIntegration) { - delete myTrayIcon; - delete myTrayIconMenu; - } - qDebug("2"); - localServer->close(); - delete localServer; - delete connecStatusLblIcon; - delete tabs; - // HTTP Server - if(httpServer) - delete httpServer; - qDebug("3"); - // Keyboard shortcuts - delete switchSearchShortcut; - delete switchSearchShortcut2; - delete switchDownShortcut; - delete switchUpShortcut; - delete switchRSSShortcut; - qDebug("4"); - delete BTSession; - qDebug("5"); -} - -void GUI::displayRSSTab(bool enable) { - if(enable) { - // RSS tab - if(rssWidget == 0) { - rssWidget = new RSSImp(); - tabs->addTab(rssWidget, tr("RSS")); - tabs->setTabIcon(3, QIcon(QString::fromUtf8(":/Icons/rss32.png"))); - } - } else { - if(rssWidget != 0) { + connect(localServer, SIGNAL(newConnection()), this, SLOT(acceptConnection())); + // Start connection checking timer + checkConnect = new QTimer(this); + connect(checkConnect, SIGNAL(timeout()), this, SLOT(checkConnectionStatus())); + checkConnect->start(5000); + // Accept drag 'n drops + setAcceptDrops(true); + createKeyboardShortcuts(); + connecStatusLblIcon = new QLabel(); + connecStatusLblIcon->setFrameShape(QFrame::NoFrame); + connecStatusLblIcon->setPixmap(QPixmap(QString::fromUtf8(":/Icons/skin/firewalled.png"))); + connecStatusLblIcon->setToolTip(QString::fromUtf8("")+tr("Connection status:")+QString::fromUtf8("
")+QString::fromUtf8("")+tr("No direct connections. This may indicate network configuration problems.")+QString::fromUtf8("")); + dlSpeedLbl = new QLabel(tr("DL: %1 KiB/s").arg("0.0")); + upSpeedLbl = new QLabel(tr("UP: %1 KiB/s").arg("0.0")); + ratioLbl = new QLabel(tr("Ratio: %1").arg("1.0")); + DHTLbl = new QLabel(tr("DHT: %1 nodes").arg(0)); + statusSep1 = new QFrame(); + statusSep1->setFixedWidth(1); + statusSep1->setFrameStyle(QFrame::Box); + statusSep2 = new QFrame(); + statusSep2->setFixedWidth(1); + statusSep2->setFrameStyle(QFrame::Box); + statusSep3 = new QFrame(); + statusSep3->setFixedWidth(1); + statusSep3->setFrameStyle(QFrame::Box); + statusSep4 = new QFrame(); + statusSep4->setFixedWidth(1); + statusSep4->setFrameStyle(QFrame::Box); + QMainWindow::statusBar()->addPermanentWidget(DHTLbl); + QMainWindow::statusBar()->addPermanentWidget(statusSep1); + QMainWindow::statusBar()->addPermanentWidget(connecStatusLblIcon); + QMainWindow::statusBar()->addPermanentWidget(statusSep2); + QMainWindow::statusBar()->addPermanentWidget(dlSpeedLbl); + QMainWindow::statusBar()->addPermanentWidget(statusSep3); + QMainWindow::statusBar()->addPermanentWidget(upSpeedLbl); + QMainWindow::statusBar()->addPermanentWidget(statusSep4); + QMainWindow::statusBar()->addPermanentWidget(ratioLbl); + if(!settings.value(QString::fromUtf8("Preferences/General/StartMinimized"), false).toBool()) { + show(); + } + scrapeTimer = new QTimer(this); + connect(scrapeTimer, SIGNAL(timeout()), this, SLOT(scrapeTrackers())); + scrapeTimer->start(20000); + qDebug("GUI Built"); + } + + // Destructor + GUI::~GUI() { + qDebug("GUI destruction"); + hide(); + // Do this as soon as possible + BTSession->saveDHTEntry(); + BTSession->saveSessionState(); + BTSession->saveFastResumeData(); + scrapeTimer->stop(); + delete scrapeTimer; + delete dlSpeedLbl; + delete upSpeedLbl; + delete ratioLbl; + delete DHTLbl; + delete statusSep1; + delete statusSep2; + delete statusSep3; + delete statusSep4; + if(rssWidget != 0) delete rssWidget; - rssWidget = 0; + delete searchEngine; + delete refresher; + delete downloadingTorrentTab; + delete finishedTorrentTab; + delete checkConnect; + qDebug("1"); + if(systrayCreator) { + delete systrayCreator; + } + if(systrayIntegration) { + delete myTrayIcon; + delete myTrayIconMenu; + } + qDebug("2"); + localServer->close(); + delete localServer; + delete connecStatusLblIcon; + delete tabs; + // HTTP Server + if(httpServer) + delete httpServer; + qDebug("3"); + // Keyboard shortcuts + delete switchSearchShortcut; + delete switchSearchShortcut2; + delete switchDownShortcut; + delete switchUpShortcut; + delete switchRSSShortcut; + qDebug("4"); + delete BTSession; + qDebug("5"); + } + + void GUI::displayRSSTab(bool enable) { + if(enable) { + // RSS tab + if(rssWidget == 0) { + rssWidget = new RSSImp(); + tabs->addTab(rssWidget, tr("RSS")); + tabs->setTabIcon(3, QIcon(QString::fromUtf8(":/Icons/rss32.png"))); + } + } else { + if(rssWidget != 0) { + delete rssWidget; + rssWidget = 0; + } + } + } + + void GUI::scrapeTrackers() { + std::vector torrents = BTSession->getTorrents(); + std::vector::iterator torrentIT; + for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { + QTorrentHandle h = QTorrentHandle(*torrentIT); + if(!h.is_valid()) continue; + h.scrape_tracker(); } } -} -void GUI::scrapeTrackers() { - std::vector torrents = BTSession->getTorrents(); - std::vector::iterator torrentIT; - for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { - QTorrentHandle h = QTorrentHandle(*torrentIT); - if(!h.is_valid()) continue; - h.scrape_tracker(); + void GUI::updateRatio() { + // Update ratio info + float ratio = 1.; + session_status sessionStatus = BTSession->getSessionStatus(); + if(sessionStatus.total_payload_download == 0) { + if(sessionStatus.total_payload_upload == 0) + ratio = 1.; + else + ratio = 10.; + }else{ + ratio = (double)sessionStatus.total_payload_upload / (double)sessionStatus.total_payload_download; + if(ratio > 10.) + ratio = 10.; + } + ratioLbl->setText(tr("Ratio: %1").arg(QString(QByteArray::number(ratio, 'f', 1)))); + // Update DHT nodes + DHTLbl->setText(tr("DHT: %1 nodes").arg(QString::number(sessionStatus.dht_nodes))); } -} -void GUI::updateRatio() { - // Update ratio info - float ratio = 1.; - session_status sessionStatus = BTSession->getSessionStatus(); - if(sessionStatus.total_payload_download == 0) { - if(sessionStatus.total_payload_upload == 0) - ratio = 1.; - else - ratio = 10.; - }else{ - ratio = (double)sessionStatus.total_payload_upload / (double)sessionStatus.total_payload_download; - if(ratio > 10.) - ratio = 10.; + void GUI::on_actionWebsite_triggered() const { + QDesktopServices::openUrl(QUrl(QString::fromUtf8("http://www.qbittorrent.org"))); } - ratioLbl->setText(tr("Ratio: %1").arg(QString(QByteArray::number(ratio, 'f', 1)))); - // Update DHT nodes - DHTLbl->setText(tr("DHT: %1 nodes").arg(QString::number(sessionStatus.dht_nodes))); -} -void GUI::on_actionWebsite_triggered() const { - QDesktopServices::openUrl(QUrl(QString::fromUtf8("http://www.qbittorrent.org"))); -} + void GUI::on_actionDocumentation_triggered() const { + QDesktopServices::openUrl(QUrl(QString::fromUtf8("http://wiki.qbittorrent.org"))); + } -void GUI::on_actionDocumentation_triggered() const { - QDesktopServices::openUrl(QUrl(QString::fromUtf8("http://wiki.qbittorrent.org"))); -} + void GUI::on_actionBugReport_triggered() const { + QDesktopServices::openUrl(QUrl(QString::fromUtf8("http://bugs.qbittorrent.org"))); + } -void GUI::on_actionBugReport_triggered() const { - QDesktopServices::openUrl(QUrl(QString::fromUtf8("http://bugs.qbittorrent.org"))); -} + void GUI::writeSettings() { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + settings.beginGroup(QString::fromUtf8("MainWindow")); + settings.setValue(QString::fromUtf8("size"), size()); + settings.setValue(QString::fromUtf8("pos"), pos()); + settings.endGroup(); + } -void GUI::writeSettings() { - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - settings.beginGroup(QString::fromUtf8("MainWindow")); - settings.setValue(QString::fromUtf8("size"), size()); - settings.setValue(QString::fromUtf8("pos"), pos()); - settings.endGroup(); -} - -// called when a torrent has finished -void GUI::finishedTorrent(QTorrentHandle& h) const { - qDebug("In GUI, a torrent has finished"); - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - bool show_msg = true; - if(QFile::exists(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+h.hash()+".finished")) + // called when a torrent has finished + void GUI::finishedTorrent(QTorrentHandle& h) const { + qDebug("In GUI, a torrent has finished"); + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + bool show_msg = true; + if(TorrentPersistentData::isSeed(h.hash())) show_msg = false; - QString fileName = h.name(); - bool useNotificationBalloons = settings.value(QString::fromUtf8("Preferences/General/NotificationBaloons"), true).toBool(); - // Add it to finished tab - QString hash = h.hash(); - if(show_msg) - BTSession->addConsoleMessage(tr("%1 has finished downloading.", "e.g: xxx.avi has finished downloading.").arg(fileName)); - downloadingTorrentTab->deleteTorrent(hash); - finishedTorrentTab->addTorrent(hash); - if(show_msg && systrayIntegration && useNotificationBalloons) { - myTrayIcon->showMessage(tr("Download finished"), tr("%1 has finished downloading.", "e.g: xxx.avi has finished downloading.").arg(fileName), QSystemTrayIcon::Information, TIME_TRAY_BALLOON); - } -} - -void GUI::addedTorrent(QTorrentHandle& h) const { + QString fileName = h.name(); + bool useNotificationBalloons = settings.value(QString::fromUtf8("Preferences/General/NotificationBaloons"), true).toBool(); + // Add it to finished tab + QString hash = h.hash(); + if(show_msg) + BTSession->addConsoleMessage(tr("%1 has finished downloading.", "e.g: xxx.avi has finished downloading.").arg(fileName)); + downloadingTorrentTab->deleteTorrent(hash); + finishedTorrentTab->addTorrent(hash); + if(show_msg && systrayIntegration && useNotificationBalloons) { + myTrayIcon->showMessage(tr("Download finished"), tr("%1 has finished downloading.", "e.g: xxx.avi has finished downloading.").arg(fileName), QSystemTrayIcon::Information, TIME_TRAY_BALLOON); + } + } + + void GUI::addedTorrent(QTorrentHandle& h) const { if(h.is_seed()) { - finishedTorrentTab->addTorrent(h.hash()); + finishedTorrentTab->addTorrent(h.hash()); } else { - downloadingTorrentTab->addTorrent(h.hash()); + downloadingTorrentTab->addTorrent(h.hash()); } -} + } -void GUI::pausedTorrent(QTorrentHandle& h) const { + void GUI::pausedTorrent(QTorrentHandle& h) const { if(h.is_seed()) { - finishedTorrentTab->pauseTorrent(h.hash()); + finishedTorrentTab->pauseTorrent(h.hash()); } else { - downloadingTorrentTab->pauseTorrent(h.hash()); + downloadingTorrentTab->pauseTorrent(h.hash()); } -} + } -void GUI::resumedTorrent(QTorrentHandle& h) const { + void GUI::resumedTorrent(QTorrentHandle& h) const { if(h.is_seed()) { - finishedTorrentTab->updateTorrent(h); + finishedTorrentTab->updateTorrent(h); } else { - downloadingTorrentTab->updateTorrent(h); + downloadingTorrentTab->updateTorrent(h); } -} + } -void GUI::checkedTorrent(QTorrentHandle& h) const { + void GUI::checkedTorrent(QTorrentHandle& h) const { if(h.is_seed()) { - // Move torrent to finished tab - downloadingTorrentTab->deleteTorrent(h.hash()); - finishedTorrentTab->addTorrent(h.hash()); + // Move torrent to finished tab + downloadingTorrentTab->deleteTorrent(h.hash()); + finishedTorrentTab->addTorrent(h.hash()); } else { - // Move torrent back to download list (if necessary) - if(QFile::exists(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+h.hash()+".finished")) { - QFile::remove(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+h.hash()+".finished"); - finishedTorrentTab->deleteTorrent(h.hash()); - downloadingTorrentTab->addTorrent(h.hash()); - } + // Move torrent back to download list (if necessary) + if(TorrentPersistentData::isSeed(h.hash())) { + TorrentPersistentData::saveSeedStatus(h); + finishedTorrentTab->deleteTorrent(h.hash()); + downloadingTorrentTab->addTorrent(h.hash()); + } } -} + } -// Notification when disk is full -void GUI::fullDiskError(QTorrentHandle& h, QString msg) const { - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - bool useNotificationBalloons = settings.value(QString::fromUtf8("Preferences/General/NotificationBaloons"), true).toBool(); - if(systrayIntegration && useNotificationBalloons) { - myTrayIcon->showMessage(tr("I/O Error", "i.e: Input/Output Error"), tr("An I/O error occured for torrent %1.\n Reason: %2", "e.g: An error occured for torrent xxx.avi.\n Reason: disk is full.").arg(h.name()).arg(msg), QSystemTrayIcon::Critical, TIME_TRAY_BALLOON); - } - // Download will be paused by libtorrent. Updating GUI information accordingly - QString hash = h.hash(); - qDebug("Full disk error, pausing torrent %s", hash.toLocal8Bit().data()); - if(h.is_seed()) { - // In finished list - qDebug("Automatically paused torrent was in finished list"); - finishedTorrentTab->pauseTorrent(hash); - }else{ - downloadingTorrentTab->pauseTorrent(hash); - } - BTSession->addConsoleMessage(tr("An error occured (full disk?), '%1' paused.", "e.g: An error occured (full disk?), 'xxx.avi' paused.").arg(h.name())); -} - -void GUI::createKeyboardShortcuts() { - actionCreate_torrent->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+N"))); - actionOpen->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+O"))); - actionExit->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+Q"))); - switchDownShortcut = new QShortcut(QKeySequence(tr("Alt+1", "shortcut to switch to first tab")), this); - connect(switchDownShortcut, SIGNAL(activated()), this, SLOT(displayDownTab())); - switchUpShortcut = new QShortcut(QKeySequence(tr("Alt+2", "shortcut to switch to second tab")), this); - connect(switchUpShortcut, SIGNAL(activated()), this, SLOT(displayUpTab())); - switchSearchShortcut = new QShortcut(QKeySequence(tr("Alt+3", "shortcut to switch to third tab")), this); - connect(switchSearchShortcut, SIGNAL(activated()), this, SLOT(displaySearchTab())); - switchSearchShortcut2 = new QShortcut(QKeySequence(tr("Ctrl+F", "shortcut to switch to search tab")), this); - connect(switchSearchShortcut2, SIGNAL(activated()), this, SLOT(displaySearchTab())); - switchRSSShortcut = new QShortcut(QKeySequence(tr("Alt+4", "shortcut to switch to fourth tab")), this); - connect(switchRSSShortcut, SIGNAL(activated()), this, SLOT(displayRSSTab())); - actionTorrent_Properties->setShortcut(QKeySequence(QString::fromUtf8("Alt+P"))); - actionOptions->setShortcut(QKeySequence(QString::fromUtf8("Alt+O"))); - actionDelete->setShortcut(QKeySequence(QString::fromUtf8("Del"))); - actionDelete_Permanently->setShortcut(QKeySequence(QString::fromUtf8("Shift+Del"))); - 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"))); - actionDecreasePriority->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+-"))); - actionIncreasePriority->setShortcut(QKeySequence(QString::fromUtf8("Ctrl++"))); -} - -// Keyboard shortcuts slots -void GUI::displayDownTab() const { - tabs->setCurrentIndex(0); -} - -void GUI::displayUpTab() const { - tabs->setCurrentIndex(1); -} - -void GUI::displaySearchTab() const { - tabs->setCurrentIndex(2); -} - -void GUI::displayRSSTab() const { - tabs->setCurrentIndex(3); -} - -// End of keyboard shortcuts slots - -void GUI::readSettings() { - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - settings.beginGroup(QString::fromUtf8("MainWindow")); - resize(settings.value(QString::fromUtf8("size"), size()).toSize()); - move(settings.value(QString::fromUtf8("pos"), screenCenter()).toPoint()); - settings.endGroup(); -} - -void GUI::balloonClicked() { - if(isHidden()) { + // Notification when disk is full + void GUI::fullDiskError(QTorrentHandle& h, QString msg) const { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + bool useNotificationBalloons = settings.value(QString::fromUtf8("Preferences/General/NotificationBaloons"), true).toBool(); + if(systrayIntegration && useNotificationBalloons) { + myTrayIcon->showMessage(tr("I/O Error", "i.e: Input/Output Error"), tr("An I/O error occured for torrent %1.\n Reason: %2", "e.g: An error occured for torrent xxx.avi.\n Reason: disk is full.").arg(h.name()).arg(msg), QSystemTrayIcon::Critical, TIME_TRAY_BALLOON); + } + // Download will be paused by libtorrent. Updating GUI information accordingly + QString hash = h.hash(); + qDebug("Full disk error, pausing torrent %s", hash.toLocal8Bit().data()); + if(h.is_seed()) { + // In finished list + qDebug("Automatically paused torrent was in finished list"); + finishedTorrentTab->pauseTorrent(hash); + }else{ + downloadingTorrentTab->pauseTorrent(hash); + } + BTSession->addConsoleMessage(tr("An error occured (full disk?), '%1' paused.", "e.g: An error occured (full disk?), 'xxx.avi' paused.").arg(h.name())); + } + + void GUI::createKeyboardShortcuts() { + actionCreate_torrent->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+N"))); + actionOpen->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+O"))); + actionExit->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+Q"))); + switchDownShortcut = new QShortcut(QKeySequence(tr("Alt+1", "shortcut to switch to first tab")), this); + connect(switchDownShortcut, SIGNAL(activated()), this, SLOT(displayDownTab())); + switchUpShortcut = new QShortcut(QKeySequence(tr("Alt+2", "shortcut to switch to second tab")), this); + connect(switchUpShortcut, SIGNAL(activated()), this, SLOT(displayUpTab())); + switchSearchShortcut = new QShortcut(QKeySequence(tr("Alt+3", "shortcut to switch to third tab")), this); + connect(switchSearchShortcut, SIGNAL(activated()), this, SLOT(displaySearchTab())); + switchSearchShortcut2 = new QShortcut(QKeySequence(tr("Ctrl+F", "shortcut to switch to search tab")), this); + connect(switchSearchShortcut2, SIGNAL(activated()), this, SLOT(displaySearchTab())); + switchRSSShortcut = new QShortcut(QKeySequence(tr("Alt+4", "shortcut to switch to fourth tab")), this); + connect(switchRSSShortcut, SIGNAL(activated()), this, SLOT(displayRSSTab())); + actionTorrent_Properties->setShortcut(QKeySequence(QString::fromUtf8("Alt+P"))); + actionOptions->setShortcut(QKeySequence(QString::fromUtf8("Alt+O"))); + actionDelete->setShortcut(QKeySequence(QString::fromUtf8("Del"))); + actionDelete_Permanently->setShortcut(QKeySequence(QString::fromUtf8("Shift+Del"))); + 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"))); + actionDecreasePriority->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+-"))); + actionIncreasePriority->setShortcut(QKeySequence(QString::fromUtf8("Ctrl++"))); + } + + // Keyboard shortcuts slots + void GUI::displayDownTab() const { + tabs->setCurrentIndex(0); + } + + void GUI::displayUpTab() const { + tabs->setCurrentIndex(1); + } + + void GUI::displaySearchTab() const { + tabs->setCurrentIndex(2); + } + + void GUI::displayRSSTab() const { + tabs->setCurrentIndex(3); + } + + // End of keyboard shortcuts slots + + void GUI::readSettings() { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + settings.beginGroup(QString::fromUtf8("MainWindow")); + resize(settings.value(QString::fromUtf8("size"), size()).toSize()); + move(settings.value(QString::fromUtf8("pos"), screenCenter()).toPoint()); + settings.endGroup(); + } + + void GUI::balloonClicked() { + if(isHidden()) { show(); if(isMinimized()) { showNormal(); } raise(); activateWindow(); + } } -} -void GUI::acceptConnection() { - clientConnection = localServer->nextPendingConnection(); - connect(clientConnection, SIGNAL(disconnected()), this, SLOT(readParamsOnSocket())); - qDebug("accepted connection from another instance"); -} + void GUI::acceptConnection() { + clientConnection = localServer->nextPendingConnection(); + connect(clientConnection, SIGNAL(disconnected()), this, SLOT(readParamsOnSocket())); + qDebug("accepted connection from another instance"); + } -void GUI::readParamsOnSocket() { - if(clientConnection) { - QByteArray params = clientConnection->readAll(); - if(!params.isEmpty()) { - processParams(QString::fromUtf8(params.data()).split(QString::fromUtf8("\n"))); - qDebug("Received parameters from another instance"); + void GUI::readParamsOnSocket() { + if(clientConnection) { + QByteArray params = clientConnection->readAll(); + if(!params.isEmpty()) { + processParams(QString::fromUtf8(params.data()).split(QString::fromUtf8("\n"))); + qDebug("Received parameters from another instance"); + } } } -} -void GUI::handleDownloadFromUrlFailure(QString url, QString reason) const{ - // Display a message box - QMessageBox::critical(0, tr("Url download error"), tr("Couldn't download file at url: %1, reason: %2.").arg(url).arg(reason)); -} + void GUI::handleDownloadFromUrlFailure(QString url, QString reason) const{ + // Display a message box + QMessageBox::critical(0, tr("Url download error"), tr("Couldn't download file at url: %1, reason: %2.").arg(url).arg(reason)); + } -void GUI::on_actionSet_global_upload_limit_triggered() { - qDebug("actionSet_global_upload_limit_triggered"); - new BandwidthAllocationDialog(this, true, BTSession, QStringList()); -} + void GUI::on_actionSet_global_upload_limit_triggered() { + qDebug("actionSet_global_upload_limit_triggered"); + new BandwidthAllocationDialog(this, true, BTSession, QStringList()); + } -void GUI::on_actionShow_console_triggered() { - new consoleDlg(this, BTSession); -} + void GUI::on_actionShow_console_triggered() { + new consoleDlg(this, BTSession); + } -void GUI::on_actionSet_global_download_limit_triggered() { - qDebug("actionSet_global_download_limit_triggered"); - new BandwidthAllocationDialog(this, false, BTSession, QStringList()); -} + void GUI::on_actionSet_global_download_limit_triggered() { + qDebug("actionSet_global_download_limit_triggered"); + new BandwidthAllocationDialog(this, false, BTSession, QStringList()); + } -void GUI::on_actionPreview_file_triggered() { - QString hash; - switch(tabs->currentIndex()){ + void GUI::on_actionPreview_file_triggered() { + QString hash; + switch(tabs->currentIndex()){ case 0: hash = downloadingTorrentTab->getSelectedTorrents(true).first(); break; @@ -562,14 +563,14 @@ void GUI::on_actionPreview_file_triggered() { break; default: return; + } + QTorrentHandle h = BTSession->getTorrentHandle(hash); + new previewSelect(this, h); } - QTorrentHandle h = BTSession->getTorrentHandle(hash); - new previewSelect(this, h); -} -void GUI::openDestinationFolder() const { - QStringList hashes; - switch(tabs->currentIndex()){ + void GUI::openDestinationFolder() const { + QStringList hashes; + switch(tabs->currentIndex()){ case 0: hashes = downloadingTorrentTab->getSelectedTorrents(true); break; @@ -578,21 +579,21 @@ void GUI::openDestinationFolder() const { break; default: return; - } - QStringList pathsList; - foreach(const QString &hash, hashes) { - QTorrentHandle h = BTSession->getTorrentHandle(hash); - QString savePath = h.save_path(); - if(!pathsList.contains(savePath)) { - pathsList.append(savePath); - QDesktopServices::openUrl(QString("file://")+savePath); + } + QStringList pathsList; + foreach(const QString &hash, hashes) { + QTorrentHandle h = BTSession->getTorrentHandle(hash); + QString savePath = h.save_path(); + if(!pathsList.contains(savePath)) { + pathsList.append(savePath); + QDesktopServices::openUrl(QString("file://")+savePath); + } } } -} -void GUI::goBuyPage() const { - QStringList hashes; - switch(tabs->currentIndex()){ + void GUI::goBuyPage() const { + QStringList hashes; + switch(tabs->currentIndex()){ case 0: hashes = downloadingTorrentTab->getSelectedTorrents(true); break; @@ -601,224 +602,224 @@ void GUI::goBuyPage() const { break; default: return; + } + QStringList pathsList; + foreach(const QString &hash, hashes) { + QTorrentHandle h = BTSession->getTorrentHandle(hash); + QDesktopServices::openUrl("http://match.sharemonkey.com/?info_hash="+hash+"&n="+h.name()+"&cid=33"); + } } - QStringList pathsList; - foreach(const QString &hash, hashes) { - QTorrentHandle h = BTSession->getTorrentHandle(hash); - QDesktopServices::openUrl("http://match.sharemonkey.com/?info_hash="+hash+"&n="+h.name()+"&cid=33"); - } -} - -// Necessary if we want to close the window -// in one time if "close to systray" is enabled -void GUI::on_actionExit_triggered() { - force_exit = true; - close(); -} - -void GUI::previewFile(QString filePath) { - QDesktopServices::openUrl(QString("file://")+filePath); -} - -int GUI::getCurrentTabIndex() const{ - if(isMinimized() || isHidden()) - return -1; - return tabs->currentIndex(); -} - -void GUI::setTabText(int index, QString text) const { - tabs->setTabText(index, text); -} - -// Toggle Main window visibility -void GUI::toggleVisibility(QSystemTrayIcon::ActivationReason e) { - if(e == QSystemTrayIcon::Trigger || e == QSystemTrayIcon::DoubleClick) { - if(isHidden()) { - show(); - if(isMinimized()) { - if(isMaximized()) { - showMaximized(); - }else{ - showNormal(); + + // Necessary if we want to close the window + // in one time if "close to systray" is enabled + void GUI::on_actionExit_triggered() { + force_exit = true; + close(); + } + + void GUI::previewFile(QString filePath) { + QDesktopServices::openUrl(QString("file://")+filePath); + } + + int GUI::getCurrentTabIndex() const{ + if(isMinimized() || isHidden()) + return -1; + return tabs->currentIndex(); + } + + void GUI::setTabText(int index, QString text) const { + tabs->setTabText(index, text); + } + + // Toggle Main window visibility + void GUI::toggleVisibility(QSystemTrayIcon::ActivationReason e) { + if(e == QSystemTrayIcon::Trigger || e == QSystemTrayIcon::DoubleClick) { + if(isHidden()) { + show(); + if(isMinimized()) { + if(isMaximized()) { + showMaximized(); + }else{ + showNormal(); + } } + raise(); + activateWindow(); + }else{ + hide(); } - raise(); - activateWindow(); - }else{ - hide(); } } -} -// Center window -QPoint GUI::screenCenter() const{ - int scrn = 0; - QWidget *w = this->topLevelWidget(); + // Center window + QPoint GUI::screenCenter() const{ + int scrn = 0; + QWidget *w = this->topLevelWidget(); - if(w) - scrn = QApplication::desktop()->screenNumber(w); - else if(QApplication::desktop()->isVirtualDesktop()) - scrn = QApplication::desktop()->screenNumber(QCursor::pos()); - else - scrn = QApplication::desktop()->screenNumber(this); + if(w) + scrn = QApplication::desktop()->screenNumber(w); + else if(QApplication::desktop()->isVirtualDesktop()) + scrn = QApplication::desktop()->screenNumber(QCursor::pos()); + else + scrn = QApplication::desktop()->screenNumber(this); - QRect desk(QApplication::desktop()->availableGeometry(scrn)); - return QPoint((desk.width() - this->frameGeometry().width()) / 2, (desk.height() - this->frameGeometry().height()) / 2); -} + QRect desk(QApplication::desktop()->availableGeometry(scrn)); + return QPoint((desk.width() - this->frameGeometry().width()) / 2, (desk.height() - this->frameGeometry().height()) / 2); + } -// Display About Dialog -void GUI::on_actionAbout_triggered() { - //About dialog - new about(this); -} + // Display About Dialog + void GUI::on_actionAbout_triggered() { + //About dialog + new about(this); + } -void GUI::showEvent(QShowEvent *e) { + void GUI::showEvent(QShowEvent *e) { qDebug("** Show Event **"); updateLists(true); e->accept(); -} + } -// Called when we close the program -void GUI::closeEvent(QCloseEvent *e) { + // Called when we close the program + void GUI::closeEvent(QCloseEvent *e) { - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - bool goToSystrayOnExit = settings.value(QString::fromUtf8("Preferences/General/CloseToTray"), false).toBool(); - if(!force_exit && systrayIntegration && goToSystrayOnExit && !this->isHidden()) { - hide(); - //e->ignore(); - e->accept(); - return; - } - if(settings.value(QString::fromUtf8("Preferences/General/ExitConfirm"), true).toBool() && downloadingTorrentTab->getNbTorrentsInList()) { - show(); - if(!isMaximized()) - showNormal(); - if(e->spontaneous() == true || force_exit == true) { - if(QMessageBox::question(this, - tr("Are you sure you want to quit?")+QString::fromUtf8(" -- ")+tr("qBittorrent"), - tr("The download list is not empty.\nAre you sure you want to quit qBittorrent?"), - tr("&Yes"), tr("&No"), - QString(), 0, 1)) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + bool goToSystrayOnExit = settings.value(QString::fromUtf8("Preferences/General/CloseToTray"), false).toBool(); + if(!force_exit && systrayIntegration && goToSystrayOnExit && !this->isHidden()) { + hide(); + //e->ignore(); + e->accept(); + return; + } + if(settings.value(QString::fromUtf8("Preferences/General/ExitConfirm"), true).toBool() && downloadingTorrentTab->getNbTorrentsInList()) { + show(); + if(!isMaximized()) + showNormal(); + if(e->spontaneous() == true || force_exit == true) { + if(QMessageBox::question(this, + tr("Are you sure you want to quit?")+QString::fromUtf8(" -- ")+tr("qBittorrent"), + tr("The download list is not empty.\nAre you sure you want to quit qBittorrent?"), + tr("&Yes"), tr("&No"), + QString(), 0, 1)) { e->ignore(); force_exit = false; return; + } } } + hide(); + if(systrayIntegration) { + // Hide tray icon + myTrayIcon->hide(); + } + // Save window size, columns size + writeSettings(); + // Accept exit + e->accept(); + qApp->exit(); } - hide(); - if(systrayIntegration) { - // Hide tray icon - myTrayIcon->hide(); - } - // Save window size, columns size - writeSettings(); - // Accept exit - e->accept(); - qApp->exit(); -} -// Display window to create a torrent -void GUI::on_actionCreate_torrent_triggered() { - createtorrent *ct = new createtorrent(this); - connect(ct, SIGNAL(torrent_to_seed(QString)), this, SLOT(addTorrent(QString))); -} + // Display window to create a torrent + void GUI::on_actionCreate_torrent_triggered() { + createtorrent *ct = new createtorrent(this); + connect(ct, SIGNAL(torrent_to_seed(QString)), this, SLOT(addTorrent(QString))); + } -bool GUI::event(QEvent * e) { - if(e->type() == QEvent::WindowStateChange) { - //Now check to see if the window is minimised - if(isMinimized()) { - qDebug("minimisation"); - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - if(systrayIntegration && settings.value(QString::fromUtf8("Preferences/General/MinimizeToTray"), false).toBool()) { - hide(); + bool GUI::event(QEvent * e) { + if(e->type() == QEvent::WindowStateChange) { + //Now check to see if the window is minimised + if(isMinimized()) { + qDebug("minimisation"); + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + if(systrayIntegration && settings.value(QString::fromUtf8("Preferences/General/MinimizeToTray"), false).toBool()) { + hide(); + } } } + return QMainWindow::event(e); } - return QMainWindow::event(e); -} -// Action executed when a file is dropped -void GUI::dropEvent(QDropEvent *event) { - event->acceptProposedAction(); - QStringList files; - if(event->mimeData()->hasUrls()) { - QList urls = event->mimeData()->urls(); - foreach(const QUrl &url, urls) { - QString tmp = url.toString().trimmed(); - if(!tmp.isEmpty()) - files << url.toString(); - } - } else { - files = event->mimeData()->text().split(QString::fromUtf8("\n")); - } - // Add file to download list - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - bool useTorrentAdditionDialog = settings.value(QString::fromUtf8("Preferences/Downloads/AdditionDialog"), true).toBool(); - foreach(QString file, files) { - file = file.trimmed().replace(QString::fromUtf8("file://"), QString::fromUtf8(""), Qt::CaseInsensitive); - qDebug("Dropped file %s on download list", file.toLocal8Bit().data()); - if(file.startsWith(QString::fromUtf8("http://"), Qt::CaseInsensitive) || file.startsWith(QString::fromUtf8("ftp://"), Qt::CaseInsensitive) || file.startsWith(QString::fromUtf8("https://"), Qt::CaseInsensitive)) { - BTSession->downloadFromUrl(file); - continue; + // Action executed when a file is dropped + void GUI::dropEvent(QDropEvent *event) { + event->acceptProposedAction(); + QStringList files; + if(event->mimeData()->hasUrls()) { + QList urls = event->mimeData()->urls(); + foreach(const QUrl &url, urls) { + QString tmp = url.toString().trimmed(); + if(!tmp.isEmpty()) + files << url.toString(); + } + } else { + files = event->mimeData()->text().split(QString::fromUtf8("\n")); } - if(useTorrentAdditionDialog) { - torrentAdditionDialog *dialog = new torrentAdditionDialog(this, BTSession); - dialog->showLoad(file); - }else{ - BTSession->addTorrent(file); + // Add file to download list + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + bool useTorrentAdditionDialog = settings.value(QString::fromUtf8("Preferences/Downloads/AdditionDialog"), true).toBool(); + foreach(QString file, files) { + file = file.trimmed().replace(QString::fromUtf8("file://"), QString::fromUtf8(""), Qt::CaseInsensitive); + qDebug("Dropped file %s on download list", file.toLocal8Bit().data()); + if(file.startsWith(QString::fromUtf8("http://"), Qt::CaseInsensitive) || file.startsWith(QString::fromUtf8("ftp://"), Qt::CaseInsensitive) || file.startsWith(QString::fromUtf8("https://"), Qt::CaseInsensitive)) { + BTSession->downloadFromUrl(file); + continue; + } + if(useTorrentAdditionDialog) { + torrentAdditionDialog *dialog = new torrentAdditionDialog(this, BTSession); + dialog->showLoad(file); + }else{ + BTSession->addTorrent(file); + } } } -} -// Decode if we accept drag 'n drop or not -void GUI::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(); + // Decode if we accept drag 'n drop or not + void GUI::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 GUI::on_actionOpen_triggered() { - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - // Open File Open Dialog - // Note: it is possible to select more than one file - QStringList pathsList = QFileDialog::getOpenFileNames(0, - tr("Open Torrent Files"), settings.value(QString::fromUtf8("MainWindowLastDir"), QDir::homePath()).toString(), - tr("Torrent Files")+QString::fromUtf8(" (*.torrent)")); - if(!pathsList.empty()) { - bool useTorrentAdditionDialog = settings.value(QString::fromUtf8("Preferences/Downloads/AdditionDialog"), true).toBool(); - unsigned int listSize = pathsList.size(); - for(unsigned int i=0; ishowLoad(pathsList.at(i)); - }else{ - BTSession->addTorrent(pathsList.at(i)); + // Display a dialog to allow user to add + // torrents to download list + void GUI::on_actionOpen_triggered() { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + // Open File Open Dialog + // Note: it is possible to select more than one file + QStringList pathsList = QFileDialog::getOpenFileNames(0, + tr("Open Torrent Files"), settings.value(QString::fromUtf8("MainWindowLastDir"), QDir::homePath()).toString(), + tr("Torrent Files")+QString::fromUtf8(" (*.torrent)")); + if(!pathsList.empty()) { + bool useTorrentAdditionDialog = settings.value(QString::fromUtf8("Preferences/Downloads/AdditionDialog"), true).toBool(); + unsigned int listSize = pathsList.size(); + for(unsigned int i=0; ishowLoad(pathsList.at(i)); + }else{ + BTSession->addTorrent(pathsList.at(i)); + } } + // Save last dir to remember it + QStringList top_dir = pathsList.at(0).split(QDir::separator()); + top_dir.removeLast(); + settings.setValue(QString::fromUtf8("MainWindowLastDir"), top_dir.join(QDir::separator())); } - // Save last dir to remember it - QStringList top_dir = pathsList.at(0).split(QDir::separator()); - top_dir.removeLast(); - settings.setValue(QString::fromUtf8("MainWindowLastDir"), top_dir.join(QDir::separator())); } -} -// delete from download list AND from hard drive -void GUI::on_actionDelete_Permanently_triggered() { - QStringList hashes; - bool inDownloadList = true; - switch(tabs->currentIndex()){ + // delete from download list AND from hard drive + void GUI::on_actionDelete_Permanently_triggered() { + QStringList hashes; + bool inDownloadList = true; + switch(tabs->currentIndex()){ case 0: hashes = downloadingTorrentTab->getSelectedTorrents(); break; @@ -828,45 +829,45 @@ void GUI::on_actionDelete_Permanently_triggered() { break; default: return; + } + int ret; + if(inDownloadList) { + ret = QMessageBox::question( + this, + tr("Are you sure? -- qBittorrent"), + tr("Are you sure you want to delete the selected item(s) from download list and from hard drive?"), + tr("&Yes"), tr("&No"), + QString(), 0, 1); + }else{ + ret = QMessageBox::question( + this, + tr("Are you sure? -- qBittorrent"), + tr("Are you sure you want to delete the selected item(s) from finished list and from hard drive?"), + tr("&Yes"), tr("&No"), + QString(), 0, 1); + } + if(ret) return; + //User clicked YES + foreach(const QString &hash, hashes) { + // Get the file name + QTorrentHandle h = BTSession->getTorrentHandle(hash); + QString fileName = h.name(); + // Remove the torrent + BTSession->deleteTorrent(hash, true); + } } - int ret; - if(inDownloadList) { - ret = QMessageBox::question( - this, - tr("Are you sure? -- qBittorrent"), - tr("Are you sure you want to delete the selected item(s) from download list and from hard drive?"), - tr("&Yes"), tr("&No"), - QString(), 0, 1); - }else{ - ret = QMessageBox::question( - this, - tr("Are you sure? -- qBittorrent"), - tr("Are you sure you want to delete the selected item(s) from finished list and from hard drive?"), - tr("&Yes"), tr("&No"), - QString(), 0, 1); - } - if(ret) return; - //User clicked YES - foreach(const QString &hash, hashes) { - // Get the file name - QTorrentHandle h = BTSession->getTorrentHandle(hash); - QString fileName = h.name(); - // Remove the torrent - BTSession->deleteTorrent(hash, true); - } -} - -void GUI::deleteTorrent(QString hash) { - // Delete item from list - downloadingTorrentTab->deleteTorrent(hash); - finishedTorrentTab->deleteTorrent(hash); -} - -// delete selected items in the list -void GUI::on_actionDelete_triggered() { - QStringList hashes; - bool inDownloadList = true; - switch(tabs->currentIndex()){ + + void GUI::deleteTorrent(QString hash) { + // Delete item from list + downloadingTorrentTab->deleteTorrent(hash); + finishedTorrentTab->deleteTorrent(hash); + } + + // delete selected items in the list + void GUI::on_actionDelete_triggered() { + QStringList hashes; + bool inDownloadList = true; + switch(tabs->currentIndex()){ case 0: // DL hashes = downloadingTorrentTab->getSelectedTorrents(); break; @@ -879,171 +880,171 @@ void GUI::on_actionDelete_triggered() { return; default: return; + } + if(!hashes.size()) return; + int ret; + if(inDownloadList) { + ret = QMessageBox::question( + this, + tr("Are you sure? -- qBittorrent"), + tr("Are you sure you want to delete the selected item(s) in download list?"), + tr("&Yes"), tr("&No"), + QString(), 0, 1); + } else { + ret = QMessageBox::question( + this, + tr("Are you sure? -- qBittorrent"), + tr("Are you sure you want to delete the selected item(s) in finished list?"), + tr("&Yes"), tr("&No"), + QString(), 0, 1); + } + if(ret) return; + //User clicked YES + foreach(const QString &hash, hashes) { + // Get the file name + QTorrentHandle h = BTSession->getTorrentHandle(hash); + QString fileName = h.name(); + // Remove the torrent + BTSession->deleteTorrent(hash, false); + } } - if(!hashes.size()) return; - int ret; - if(inDownloadList) { - ret = QMessageBox::question( - this, - tr("Are you sure? -- qBittorrent"), - tr("Are you sure you want to delete the selected item(s) in download list?"), - tr("&Yes"), tr("&No"), - QString(), 0, 1); - } else { - ret = QMessageBox::question( - this, - tr("Are you sure? -- qBittorrent"), - tr("Are you sure you want to delete the selected item(s) in finished list?"), - tr("&Yes"), tr("&No"), - QString(), 0, 1); - } - if(ret) return; - //User clicked YES - foreach(const QString &hash, hashes) { - // Get the file name - QTorrentHandle h = BTSession->getTorrentHandle(hash); - QString fileName = h.name(); - // Remove the torrent - BTSession->deleteTorrent(hash, false); - } -} -// As program parameters, we can get paths or urls. -// This function parse the parameters and call -// the right addTorrent function, considering -// the parameter type. -void GUI::processParams(const QStringList& params) { - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - bool useTorrentAdditionDialog = settings.value(QString::fromUtf8("Preferences/Downloads/AdditionDialog"), true).toBool(); - foreach(QString param, params) { - param = param.trimmed(); - if(param.startsWith(QString::fromUtf8("http://"), Qt::CaseInsensitive) || param.startsWith(QString::fromUtf8("ftp://"), Qt::CaseInsensitive) || param.startsWith(QString::fromUtf8("https://"), Qt::CaseInsensitive)) { - BTSession->downloadFromUrl(param); - }else{ - if(useTorrentAdditionDialog) { - torrentAdditionDialog *dialog = new torrentAdditionDialog(this, BTSession); - dialog->showLoad(param); + // As program parameters, we can get paths or urls. + // This function parse the parameters and call + // the right addTorrent function, considering + // the parameter type. + void GUI::processParams(const QStringList& params) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + bool useTorrentAdditionDialog = settings.value(QString::fromUtf8("Preferences/Downloads/AdditionDialog"), true).toBool(); + foreach(QString param, params) { + param = param.trimmed(); + if(param.startsWith(QString::fromUtf8("http://"), Qt::CaseInsensitive) || param.startsWith(QString::fromUtf8("ftp://"), Qt::CaseInsensitive) || param.startsWith(QString::fromUtf8("https://"), Qt::CaseInsensitive)) { + BTSession->downloadFromUrl(param); }else{ - BTSession->addTorrent(param); + if(useTorrentAdditionDialog) { + torrentAdditionDialog *dialog = new torrentAdditionDialog(this, BTSession); + dialog->showLoad(param); + }else{ + BTSession->addTorrent(param); + } } } } -} -void GUI::addTorrent(QString path) { - BTSession->addTorrent(path); -} + void GUI::addTorrent(QString path) { + BTSession->addTorrent(path); + } -void GUI::processDownloadedFiles(QString path, QString url) { - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - bool useTorrentAdditionDialog = settings.value(QString::fromUtf8("Preferences/Downloads/AdditionDialog"), true).toBool(); - if(useTorrentAdditionDialog) { - torrentAdditionDialog *dialog = new torrentAdditionDialog(this, BTSession); - dialog->showLoad(path, url); - }else{ - BTSession->addTorrent(path, false, url); - } -} - -// Set BT session configuration -void GUI::configureSession(bool deleteOptions) { - qDebug("Configuring session"); - // General - bool new_displaySpeedInTitle = options->speedInTitleBar(); - if(!new_displaySpeedInTitle && new_displaySpeedInTitle != displaySpeedInTitle) { - // Reset title - setWindowTitle(tr("qBittorrent %1", "e.g: qBittorrent v0.x").arg(QString::fromUtf8(VERSION))); - } - displaySpeedInTitle = new_displaySpeedInTitle; - if(options->isToolbarDisplayed()) { - toolBar->setVisible(true); - toolBar->layout()->setSpacing(7); - } else { - toolBar->setVisible(false); - } - unsigned int new_refreshInterval = options->getRefreshInterval(); - if(refreshInterval != new_refreshInterval) { - refreshInterval = new_refreshInterval; - refresher->start(refreshInterval); - } - // Downloads - // * Save path - BTSession->setDefaultSavePath(options->getSavePath()); - if(options->isTempPathEnabled()) { - BTSession->setDefaultTempPath(options->getTempPath()); - } else { - BTSession->setDefaultTempPath(QString::null); - } - BTSession->preAllocateAllFiles(options->preAllocateAllFiles()); - BTSession->startTorrentsInPause(options->addTorrentsInPause()); - // * Scan dir - if(options->getScanDir().isNull()) { - BTSession->disableDirectoryScanning(); - }else{ - //Interval first - BTSession->enableDirectoryScanning(options->getScanDir()); - } - // Connection - // * Ports binding - unsigned short old_listenPort = BTSession->getListenPort(); - BTSession->setListeningPortsRange(options->getPorts()); - unsigned short new_listenPort = BTSession->getListenPort(); - if(new_listenPort != old_listenPort) { - BTSession->addConsoleMessage(tr("qBittorrent is bound to port: TCP/%1", "e.g: qBittorrent is bound to port: 6881").arg( misc::toQString(new_listenPort))); - } - // * Global download limit - QPair limits = options->getGlobalBandwidthLimits(); - if(limits.first <= 0) { - // Download limit disabled - BTSession->setDownloadRateLimit(-1); - } else { - // Enabled - BTSession->setDownloadRateLimit(limits.first*1024); - } - // * Global Upload limit - if(limits.second <= 0) { - // Upload limit disabled - BTSession->setUploadRateLimit(-1); - } else { - // Enabled - BTSession->setUploadRateLimit(limits.second*1024); - } - // * UPnP - if(options->isUPnPEnabled()) { - BTSession->enableUPnP(true); - BTSession->addConsoleMessage(tr("UPnP support [ON]"), QString::fromUtf8("blue")); - } else { - BTSession->enableUPnP(false); - BTSession->addConsoleMessage(tr("UPnP support [OFF]"), QString::fromUtf8("blue")); - } - // * NAT-PMP - if(options->isNATPMPEnabled()) { - BTSession->enableNATPMP(true); - BTSession->addConsoleMessage(tr("NAT-PMP support [ON]"), QString::fromUtf8("blue")); - } else { - BTSession->enableNATPMP(false); - BTSession->addConsoleMessage(tr("NAT-PMP support [OFF]"), QString::fromUtf8("blue")); - } - // * Session settings - session_settings sessionSettings; - if(options->shouldSpoofAzureus()) { - sessionSettings.user_agent = "Azureus 3.0.5.2"; - } else { - sessionSettings.user_agent = "qBittorrent "VERSION; - } - sessionSettings.upnp_ignore_nonrouters = true; - sessionSettings.use_dht_as_fallback = false; - // To keep same behavior as in qbittorrent v1.2.0 - sessionSettings.rate_limit_ip_overhead = false; - // Queueing System - if(options->isQueueingSystemEnabled()) { + void GUI::processDownloadedFiles(QString path, QString url) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + bool useTorrentAdditionDialog = settings.value(QString::fromUtf8("Preferences/Downloads/AdditionDialog"), true).toBool(); + if(useTorrentAdditionDialog) { + torrentAdditionDialog *dialog = new torrentAdditionDialog(this, BTSession); + dialog->showLoad(path, url); + }else{ + BTSession->addTorrent(path, false, url); + } + } + + // Set BT session configuration + void GUI::configureSession(bool deleteOptions) { + qDebug("Configuring session"); + // General + bool new_displaySpeedInTitle = options->speedInTitleBar(); + if(!new_displaySpeedInTitle && new_displaySpeedInTitle != displaySpeedInTitle) { + // Reset title + setWindowTitle(tr("qBittorrent %1", "e.g: qBittorrent v0.x").arg(QString::fromUtf8(VERSION))); + } + displaySpeedInTitle = new_displaySpeedInTitle; + if(options->isToolbarDisplayed()) { + toolBar->setVisible(true); + toolBar->layout()->setSpacing(7); + } else { + toolBar->setVisible(false); + } + unsigned int new_refreshInterval = options->getRefreshInterval(); + if(refreshInterval != new_refreshInterval) { + refreshInterval = new_refreshInterval; + refresher->start(refreshInterval); + } + // Downloads + // * Save path + BTSession->setDefaultSavePath(options->getSavePath()); + if(options->isTempPathEnabled()) { + BTSession->setDefaultTempPath(options->getTempPath()); + } else { + BTSession->setDefaultTempPath(QString::null); + } + BTSession->preAllocateAllFiles(options->preAllocateAllFiles()); + BTSession->startTorrentsInPause(options->addTorrentsInPause()); + // * Scan dir + if(options->getScanDir().isNull()) { + BTSession->disableDirectoryScanning(); + }else{ + //Interval first + BTSession->enableDirectoryScanning(options->getScanDir()); + } + // Connection + // * Ports binding + unsigned short old_listenPort = BTSession->getListenPort(); + BTSession->setListeningPortsRange(options->getPorts()); + unsigned short new_listenPort = BTSession->getListenPort(); + if(new_listenPort != old_listenPort) { + BTSession->addConsoleMessage(tr("qBittorrent is bound to port: TCP/%1", "e.g: qBittorrent is bound to port: 6881").arg( misc::toQString(new_listenPort))); + } + // * Global download limit + QPair limits = options->getGlobalBandwidthLimits(); + if(limits.first <= 0) { + // Download limit disabled + BTSession->setDownloadRateLimit(-1); + } else { + // Enabled + BTSession->setDownloadRateLimit(limits.first*1024); + } + // * Global Upload limit + if(limits.second <= 0) { + // Upload limit disabled + BTSession->setUploadRateLimit(-1); + } else { + // Enabled + BTSession->setUploadRateLimit(limits.second*1024); + } + // * UPnP + if(options->isUPnPEnabled()) { + BTSession->enableUPnP(true); + BTSession->addConsoleMessage(tr("UPnP support [ON]"), QString::fromUtf8("blue")); + } else { + BTSession->enableUPnP(false); + BTSession->addConsoleMessage(tr("UPnP support [OFF]"), QString::fromUtf8("blue")); + } + // * NAT-PMP + if(options->isNATPMPEnabled()) { + BTSession->enableNATPMP(true); + BTSession->addConsoleMessage(tr("NAT-PMP support [ON]"), QString::fromUtf8("blue")); + } else { + BTSession->enableNATPMP(false); + BTSession->addConsoleMessage(tr("NAT-PMP support [OFF]"), QString::fromUtf8("blue")); + } + // * Session settings + session_settings sessionSettings; + if(options->shouldSpoofAzureus()) { + sessionSettings.user_agent = "Azureus 3.0.5.2"; + } else { + sessionSettings.user_agent = "qBittorrent "VERSION; + } + sessionSettings.upnp_ignore_nonrouters = true; + sessionSettings.use_dht_as_fallback = false; + // To keep same behavior as in qbittorrent v1.2.0 + sessionSettings.rate_limit_ip_overhead = false; + // Queueing System + if(options->isQueueingSystemEnabled()) { if(!BTSession->isQueueingEnabled()) { - downloadingTorrentTab->hidePriorityColumn(false); - actionDecreasePriority->setVisible(true); - actionIncreasePriority->setVisible(true); - prioSeparator->setVisible(true); - prioSeparator2->setVisible(true); - toolBar->layout()->setSpacing(7); + downloadingTorrentTab->hidePriorityColumn(false); + actionDecreasePriority->setVisible(true); + actionIncreasePriority->setVisible(true); + prioSeparator->setVisible(true); + prioSeparator2->setVisible(true); + toolBar->layout()->setSpacing(7); } int max_torrents = options->getMaxActiveTorrents(); int max_uploads = options->getMaxActiveUploads(); @@ -1053,61 +1054,61 @@ void GUI::configureSession(bool deleteOptions) { sessionSettings.active_limit = max_torrents; sessionSettings.dont_count_slow_torrents = false; BTSession->setQueueingEnabled(true); - } else { + } else { if(BTSession->isQueueingEnabled()) { - sessionSettings.active_downloads = -1; - sessionSettings.active_seeds = -1; - sessionSettings.active_limit = -1; - BTSession->setQueueingEnabled(false); - downloadingTorrentTab->hidePriorityColumn(true); - actionDecreasePriority->setVisible(false); - actionIncreasePriority->setVisible(false); - prioSeparator->setVisible(false); - prioSeparator2->setVisible(false); - toolBar->layout()->setSpacing(7); + sessionSettings.active_downloads = -1; + sessionSettings.active_seeds = -1; + sessionSettings.active_limit = -1; + BTSession->setQueueingEnabled(false); + downloadingTorrentTab->hidePriorityColumn(true); + actionDecreasePriority->setVisible(false); + actionIncreasePriority->setVisible(false); + prioSeparator->setVisible(false); + prioSeparator2->setVisible(false); + toolBar->layout()->setSpacing(7); + } + } + BTSession->setSessionSettings(sessionSettings); + // Bittorrent + // * Max connections limit + BTSession->setMaxConnections(options->getMaxConnecs()); + // * Max connections per torrent limit + BTSession->setMaxConnectionsPerTorrent(options->getMaxConnecsPerTorrent()); + // * Max uploads per torrent limit + BTSession->setMaxUploadsPerTorrent(options->getMaxUploadsPerTorrent()); + // * DHT + if(options->isDHTEnabled()) { + // Set DHT Port + BTSession->setDHTPort(options->getDHTPort()); + if(BTSession->enableDHT(true)) { + int dht_port = new_listenPort; + if(options->getDHTPort()) + dht_port = options->getDHTPort(); + BTSession->addConsoleMessage(tr("DHT support [ON], port: UDP/%1").arg(dht_port), QString::fromUtf8("blue")); + } else { + BTSession->addConsoleMessage(tr("DHT support [OFF]"), QString::fromUtf8("red")); } - } - BTSession->setSessionSettings(sessionSettings); - // Bittorrent - // * Max connections limit - BTSession->setMaxConnections(options->getMaxConnecs()); - // * Max connections per torrent limit - BTSession->setMaxConnectionsPerTorrent(options->getMaxConnecsPerTorrent()); - // * Max uploads per torrent limit - BTSession->setMaxUploadsPerTorrent(options->getMaxUploadsPerTorrent()); - // * DHT - if(options->isDHTEnabled()) { - // Set DHT Port - BTSession->setDHTPort(options->getDHTPort()); - if(BTSession->enableDHT(true)) { - int dht_port = new_listenPort; - if(options->getDHTPort()) - dht_port = options->getDHTPort(); - BTSession->addConsoleMessage(tr("DHT support [ON], port: UDP/%1").arg(dht_port), QString::fromUtf8("blue")); } else { - BTSession->addConsoleMessage(tr("DHT support [OFF]"), QString::fromUtf8("red")); - } - } else { - BTSession->enableDHT(false); - BTSession->addConsoleMessage(tr("DHT support [OFF]"), QString::fromUtf8("blue")); - } - // * PeX - BTSession->addConsoleMessage(tr("PeX support [ON]"), QString::fromUtf8("blue")); - // * LSD - if(options->isLSDEnabled()) { - BTSession->enableLSD(true); - BTSession->addConsoleMessage(tr("Local Peer Discovery [ON]"), QString::fromUtf8("blue")); - } else { - BTSession->enableLSD(false); - BTSession->addConsoleMessage(tr("Local Peer Discovery support [OFF]"), QString::fromUtf8("blue")); - } - // * Encryption - int encryptionState = options->getEncryptionSetting(); - // The most secure, rc4 only so that all streams and encrypted - pe_settings encryptionSettings; - encryptionSettings.allowed_enc_level = pe_settings::rc4; - encryptionSettings.prefer_rc4 = true; - switch(encryptionState) { + BTSession->enableDHT(false); + BTSession->addConsoleMessage(tr("DHT support [OFF]"), QString::fromUtf8("blue")); + } + // * PeX + BTSession->addConsoleMessage(tr("PeX support [ON]"), QString::fromUtf8("blue")); + // * LSD + if(options->isLSDEnabled()) { + BTSession->enableLSD(true); + BTSession->addConsoleMessage(tr("Local Peer Discovery [ON]"), QString::fromUtf8("blue")); + } else { + BTSession->enableLSD(false); + BTSession->addConsoleMessage(tr("Local Peer Discovery support [OFF]"), QString::fromUtf8("blue")); + } + // * Encryption + int encryptionState = options->getEncryptionSetting(); + // The most secure, rc4 only so that all streams and encrypted + pe_settings encryptionSettings; + encryptionSettings.allowed_enc_level = pe_settings::rc4; + encryptionSettings.prefer_rc4 = true; + switch(encryptionState) { case 0: //Enabled encryptionSettings.out_enc_policy = pe_settings::enabled; encryptionSettings.in_enc_policy = pe_settings::enabled; @@ -1122,40 +1123,40 @@ void GUI::configureSession(bool deleteOptions) { encryptionSettings.out_enc_policy = pe_settings::disabled; encryptionSettings.in_enc_policy = pe_settings::disabled; BTSession->addConsoleMessage(tr("Encryption support [OFF]"), QString::fromUtf8("blue")); - } - BTSession->applyEncryptionSettings(encryptionSettings); - // * Desired ratio - BTSession->setGlobalRatio(options->getDesiredRatio()); - // * Maximum ratio - BTSession->setDeleteRatio(options->getDeleteRatio()); - // Ip Filter - if(options->isFilteringEnabled()) { - BTSession->enableIPFilter(options->getFilter()); - }else{ - BTSession->disableIPFilter(); - } - // RSS - if(options->isRSSEnabled()) { - displayRSSTab(true); - } else { - displayRSSTab(false); - } - // * Proxy settings - proxy_settings proxySettings; - if(options->isProxyEnabled()) { - qDebug("Enabling P2P proxy"); - proxySettings.hostname = options->getProxyIp().toStdString(); - qDebug("hostname is %s", proxySettings.hostname.c_str()); - proxySettings.port = options->getProxyPort(); - qDebug("port is %d", proxySettings.port); - if(options->isProxyAuthEnabled()) { - - proxySettings.username = options->getProxyUsername().toStdString(); - proxySettings.password = options->getProxyPassword().toStdString(); - qDebug("username is %s", proxySettings.username.c_str()); - qDebug("password is %s", proxySettings.password.c_str()); - } - switch(options->getProxyType()) { + } + BTSession->applyEncryptionSettings(encryptionSettings); + // * Desired ratio + BTSession->setGlobalRatio(options->getDesiredRatio()); + // * Maximum ratio + BTSession->setDeleteRatio(options->getDeleteRatio()); + // Ip Filter + if(options->isFilteringEnabled()) { + BTSession->enableIPFilter(options->getFilter()); + }else{ + BTSession->disableIPFilter(); + } + // RSS + if(options->isRSSEnabled()) { + displayRSSTab(true); + } else { + displayRSSTab(false); + } + // * Proxy settings + proxy_settings proxySettings; + if(options->isProxyEnabled()) { + qDebug("Enabling P2P proxy"); + proxySettings.hostname = options->getProxyIp().toStdString(); + qDebug("hostname is %s", proxySettings.hostname.c_str()); + proxySettings.port = options->getProxyPort(); + qDebug("port is %d", proxySettings.port); + if(options->isProxyAuthEnabled()) { + + proxySettings.username = options->getProxyUsername().toStdString(); + proxySettings.password = options->getProxyPassword().toStdString(); + qDebug("username is %s", proxySettings.username.c_str()); + qDebug("password is %s", proxySettings.password.c_str()); + } + switch(options->getProxyType()) { case HTTP: qDebug("type: http"); proxySettings.type = proxy_settings::http; @@ -1172,440 +1173,440 @@ void GUI::configureSession(bool deleteOptions) { qDebug("type: socks5_pw"); proxySettings.type = proxy_settings::socks5_pw; break; + } + qDebug("booleans: %d %d %d %d", options->useProxyForTrackers(), options->useProxyForPeers(), options->useProxyForWebseeds(), options->useProxyForDHT()); + BTSession->setProxySettings(proxySettings, options->useProxyForTrackers(), options->useProxyForPeers(), options->useProxyForWebseeds(), options->useProxyForDHT()); + } else { + qDebug("Disabling P2P proxy"); + BTSession->setProxySettings(proxySettings, false, false, false, false); } - qDebug("booleans: %d %d %d %d", options->useProxyForTrackers(), options->useProxyForPeers(), options->useProxyForWebseeds(), options->useProxyForDHT()); - BTSession->setProxySettings(proxySettings, options->useProxyForTrackers(), options->useProxyForPeers(), options->useProxyForWebseeds(), options->useProxyForDHT()); - } else { - qDebug("Disabling P2P proxy"); - BTSession->setProxySettings(proxySettings, false, false, false, false); - } - if(options->isHTTPProxyEnabled()) { - qDebug("Enabling Search HTTP proxy"); - // HTTP Proxy - QString proxy_str; - switch(options->getHTTPProxyType()) { + if(options->isHTTPProxyEnabled()) { + qDebug("Enabling Search HTTP proxy"); + // HTTP Proxy + QString proxy_str; + switch(options->getHTTPProxyType()) { case HTTP_PW: proxy_str = misc::toQString("http://")+options->getHTTPProxyUsername()+":"+options->getHTTPProxyPassword()+"@"+options->getHTTPProxyIp()+":"+misc::toQString(options->getHTTPProxyPort()); break; default: proxy_str = misc::toQString("http://")+options->getHTTPProxyIp()+":"+misc::toQString(options->getHTTPProxyPort()); - } - // We need this for urllib in search engine plugins + } + // We need this for urllib in search engine plugins #ifdef Q_WS_WIN - char proxystr[512]; - snprintf(proxystr, 512, "http_proxy=%s", proxy_str.toLocal8Bit().data()); - putenv(proxystr); + char proxystr[512]; + snprintf(proxystr, 512, "http_proxy=%s", proxy_str.toLocal8Bit().data()); + putenv(proxystr); #else - qDebug("HTTP: proxy string: %s", proxy_str.toLocal8Bit().data()); - setenv("http_proxy", proxy_str.toLocal8Bit().data(), 1); + qDebug("HTTP: proxy string: %s", proxy_str.toLocal8Bit().data()); + setenv("http_proxy", proxy_str.toLocal8Bit().data(), 1); #endif - } else { - qDebug("Disabling search proxy"); + } else { + qDebug("Disabling search proxy"); #ifdef Q_WS_WIN - putenv("http_proxy="); + putenv("http_proxy="); #else - unsetenv("http_proxy"); + unsetenv("http_proxy"); #endif + } + // Clean up + if(deleteOptions && options) { + qDebug("Deleting options"); + //delete options; + options->deleteLater(); + } + qDebug("Session configured"); } - // Clean up - if(deleteOptions && options) { - qDebug("Deleting options"); - //delete options; - options->deleteLater(); - } - qDebug("Session configured"); -} -void GUI::updateUnfinishedTorrentNumber(unsigned int nb) { - unsigned int paused = BTSession->getUnfinishedPausedTorrentsNb(); - tabs->setTabText(0, tr("Downloads") +QString::fromUtf8(" (")+misc::toQString(nb-paused)+"/"+misc::toQString(nb)+QString::fromUtf8(")")); -} + void GUI::updateUnfinishedTorrentNumber(unsigned int nb) { + unsigned int paused = BTSession->getUnfinishedPausedTorrentsNb(); + tabs->setTabText(0, tr("Downloads") +QString::fromUtf8(" (")+misc::toQString(nb-paused)+"/"+misc::toQString(nb)+QString::fromUtf8(")")); + } -void GUI::updateFinishedTorrentNumber(unsigned int nb) { - unsigned int paused = BTSession->getFinishedPausedTorrentsNb(); - tabs->setTabText(1, tr("Finished") +QString::fromUtf8(" (")+misc::toQString(nb-paused)+"/"+misc::toQString(nb)+QString::fromUtf8(")")); -} + void GUI::updateFinishedTorrentNumber(unsigned int nb) { + unsigned int paused = BTSession->getFinishedPausedTorrentsNb(); + tabs->setTabText(1, tr("Finished") +QString::fromUtf8(" (")+misc::toQString(nb-paused)+"/"+misc::toQString(nb)+QString::fromUtf8(")")); + } -// Allow to change action on double-click -void GUI::torrentDoubleClicked(QString hash, bool finished) { - int action; - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - QTorrentHandle h = BTSession->getTorrentHandle(hash); + // Allow to change action on double-click + void GUI::torrentDoubleClicked(QString hash, bool finished) { + int action; + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + QTorrentHandle h = BTSession->getTorrentHandle(hash); - if(finished) { - action = settings.value(QString::fromUtf8("Preferences/Downloads/DblClOnTorFN"), 0).toInt(); - } else { - action = settings.value(QString::fromUtf8("Preferences/Downloads/DblClOnTorDl"), 0).toInt(); - } + if(finished) { + action = settings.value(QString::fromUtf8("Preferences/Downloads/DblClOnTorFN"), 0).toInt(); + } else { + action = settings.value(QString::fromUtf8("Preferences/Downloads/DblClOnTorDl"), 0).toInt(); + } - switch(action) { + switch(action) { case TOGGLE_PAUSE: this->togglePausedState(hash); - break; - case OPEN_DEST: { - QTorrentHandle h = BTSession->getTorrentHandle(hash); - QString savePath = h.save_path(); - QDesktopServices::openUrl(QUrl(savePath)); break; - } + case OPEN_DEST: { + QTorrentHandle h = BTSession->getTorrentHandle(hash); + QString savePath = h.save_path(); + QDesktopServices::openUrl(QUrl(savePath)); + break; + } case SHOW_PROPERTIES : if(finished) { finishedTorrentTab->showPropertiesFromHash(hash); } else { downloadingTorrentTab->showPropertiesFromHash(hash); } - break; - } -} - -// Toggle paused state of selected torrent -void GUI::togglePausedState(QString hash) { - if(tabs->currentIndex() > 1) return; - bool inDownloadList = true; - if(tabs->currentIndex() == 1) - inDownloadList = false; - QTorrentHandle h = BTSession->getTorrentHandle(hash); - if(h.is_paused()) { - h.resume(); - resumedTorrent(h); - if(inDownloadList) { - updateUnfinishedTorrentNumber(downloadingTorrentTab->getNbTorrentsInList()); - }else{ - updateFinishedTorrentNumber(finishedTorrentTab->getNbTorrentsInList()); + break; } - }else{ - h.pause(); - pausedTorrent(h); - if(inDownloadList) { - updateUnfinishedTorrentNumber(downloadingTorrentTab->getNbTorrentsInList()); + } + + // Toggle paused state of selected torrent + void GUI::togglePausedState(QString hash) { + if(tabs->currentIndex() > 1) return; + bool inDownloadList = true; + if(tabs->currentIndex() == 1) + inDownloadList = false; + QTorrentHandle h = BTSession->getTorrentHandle(hash); + if(h.is_paused()) { + h.resume(); + resumedTorrent(h); + if(inDownloadList) { + updateUnfinishedTorrentNumber(downloadingTorrentTab->getNbTorrentsInList()); + }else{ + updateFinishedTorrentNumber(finishedTorrentTab->getNbTorrentsInList()); + } }else{ - updateFinishedTorrentNumber(finishedTorrentTab->getNbTorrentsInList()); + h.pause(); + pausedTorrent(h); + if(inDownloadList) { + updateUnfinishedTorrentNumber(downloadingTorrentTab->getNbTorrentsInList()); + }else{ + updateFinishedTorrentNumber(finishedTorrentTab->getNbTorrentsInList()); + } } } -} -// Pause All Downloads in DL list -void GUI::on_actionPause_All_triggered() { + // Pause All Downloads in DL list + void GUI::on_actionPause_All_triggered() { bool change = false; std::vector torrents = BTSession->getTorrents(); std::vector::iterator torrentIT; for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { - QTorrentHandle h = QTorrentHandle(*torrentIT); - if(!h.is_valid() || h.is_paused()) continue; - change = true; - h.pause(); - pausedTorrent(h); + QTorrentHandle h = QTorrentHandle(*torrentIT); + if(!h.is_valid() || h.is_paused()) continue; + change = true; + h.pause(); + pausedTorrent(h); } if(change) { - updateUnfinishedTorrentNumber(downloadingTorrentTab->getNbTorrentsInList()); - updateFinishedTorrentNumber(finishedTorrentTab->getNbTorrentsInList()); + updateUnfinishedTorrentNumber(downloadingTorrentTab->getNbTorrentsInList()); + updateFinishedTorrentNumber(finishedTorrentTab->getNbTorrentsInList()); } -} + } -void GUI::on_actionIncreasePriority_triggered() { - if(tabs->currentIndex() != 0) + void GUI::on_actionIncreasePriority_triggered() { + if(tabs->currentIndex() != 0) return; - QStringList hashes = downloadingTorrentTab->getSelectedTorrents(); - foreach(const QString &hash, hashes) { + QStringList hashes = downloadingTorrentTab->getSelectedTorrents(); + foreach(const QString &hash, hashes) { BTSession->increaseDlTorrentPriority(hash); + } + updateLists(); } - updateLists(); -} -void GUI::on_actionDecreasePriority_triggered() { - Q_ASSERT(tabs->currentIndex() == 0); - QStringList hashes = downloadingTorrentTab->getSelectedTorrents(); - foreach(const QString &hash, hashes) { + void GUI::on_actionDecreasePriority_triggered() { + Q_ASSERT(tabs->currentIndex() == 0); + QStringList hashes = downloadingTorrentTab->getSelectedTorrents(); + foreach(const QString &hash, hashes) { BTSession->decreaseDlTorrentPriority(hash); + } + updateLists(); } - updateLists(); -} - -// pause selected items in the list -void GUI::on_actionPause_triggered() { - bool inDownloadList = true; - if(tabs->currentIndex() > 1) return; - if(tabs->currentIndex() == 1) - inDownloadList = false; - QStringList hashes; - if(inDownloadList) { - hashes = downloadingTorrentTab->getSelectedTorrents(); - } else { - hashes = finishedTorrentTab->getSelectedTorrents(); - } - foreach(const QString &hash, hashes) { - QTorrentHandle h = BTSession->getTorrentHandle(hash); - if(!h.is_paused()){ - h.pause(); - pausedTorrent(h); - if(inDownloadList) { - updateUnfinishedTorrentNumber(downloadingTorrentTab->getNbTorrentsInList()); - } else { - updateFinishedTorrentNumber(finishedTorrentTab->getNbTorrentsInList()); + + // pause selected items in the list + void GUI::on_actionPause_triggered() { + bool inDownloadList = true; + if(tabs->currentIndex() > 1) return; + if(tabs->currentIndex() == 1) + inDownloadList = false; + QStringList hashes; + if(inDownloadList) { + hashes = downloadingTorrentTab->getSelectedTorrents(); + } else { + hashes = finishedTorrentTab->getSelectedTorrents(); + } + foreach(const QString &hash, hashes) { + QTorrentHandle h = BTSession->getTorrentHandle(hash); + if(!h.is_paused()){ + h.pause(); + pausedTorrent(h); + if(inDownloadList) { + updateUnfinishedTorrentNumber(downloadingTorrentTab->getNbTorrentsInList()); + } else { + updateFinishedTorrentNumber(finishedTorrentTab->getNbTorrentsInList()); + } } } } -} -// Resume All Downloads in DL list -void GUI::on_actionStart_All_triggered() { - bool change = false; + // Resume All Downloads in DL list + void GUI::on_actionStart_All_triggered() { + bool change = false; std::vector torrents = BTSession->getTorrents(); std::vector::iterator torrentIT; for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { - QTorrentHandle h = QTorrentHandle(*torrentIT); - if(!h.is_valid() || !h.is_paused()) continue; - change = true; - h.resume(); - resumedTorrent(h); - } - if(change) { - updateUnfinishedTorrentNumber(downloadingTorrentTab->getNbTorrentsInList()); - updateFinishedTorrentNumber(finishedTorrentTab->getNbTorrentsInList()); - } -} - -// start selected items in the list -void GUI::on_actionStart_triggered() { - bool inDownloadList = true; - if(tabs->currentIndex() > 1) return; - if(tabs->currentIndex() == 1) - inDownloadList = false; - QStringList hashes; - if(inDownloadList) { - hashes = downloadingTorrentTab->getSelectedTorrents(); - } else { - hashes = finishedTorrentTab->getSelectedTorrents(); - } - foreach(const QString &hash, hashes) { - QTorrentHandle h = BTSession->getTorrentHandle(hash); - if(h.is_paused()){ + QTorrentHandle h = QTorrentHandle(*torrentIT); + if(!h.is_valid() || !h.is_paused()) continue; + change = true; h.resume(); resumedTorrent(h); - if(inDownloadList) { - updateUnfinishedTorrentNumber(downloadingTorrentTab->getNbTorrentsInList()); - } else { - updateFinishedTorrentNumber(finishedTorrentTab->getNbTorrentsInList()); + } + if(change) { + updateUnfinishedTorrentNumber(downloadingTorrentTab->getNbTorrentsInList()); + updateFinishedTorrentNumber(finishedTorrentTab->getNbTorrentsInList()); + } + } + + // start selected items in the list + void GUI::on_actionStart_triggered() { + bool inDownloadList = true; + if(tabs->currentIndex() > 1) return; + if(tabs->currentIndex() == 1) + inDownloadList = false; + QStringList hashes; + if(inDownloadList) { + hashes = downloadingTorrentTab->getSelectedTorrents(); + } else { + hashes = finishedTorrentTab->getSelectedTorrents(); + } + foreach(const QString &hash, hashes) { + QTorrentHandle h = BTSession->getTorrentHandle(hash); + if(h.is_paused()){ + h.resume(); + resumedTorrent(h); + if(inDownloadList) { + updateUnfinishedTorrentNumber(downloadingTorrentTab->getNbTorrentsInList()); + } else { + updateFinishedTorrentNumber(finishedTorrentTab->getNbTorrentsInList()); + } } } } -} -void GUI::addUnauthenticatedTracker(QPair tracker) { - // Trackers whose authentication was cancelled - if(unauthenticated_trackers.indexOf(tracker) < 0) { - unauthenticated_trackers << tracker; + void GUI::addUnauthenticatedTracker(QPair tracker) { + // Trackers whose authentication was cancelled + if(unauthenticated_trackers.indexOf(tracker) < 0) { + unauthenticated_trackers << tracker; + } } -} -// display properties of selected items -void GUI::on_actionTorrent_Properties_triggered() { - if(tabs->currentIndex() > 1) return; - switch(tabs->currentIndex()){ + // display properties of selected items + void GUI::on_actionTorrent_Properties_triggered() { + if(tabs->currentIndex() > 1) return; + switch(tabs->currentIndex()){ case 1: // DL List finishedTorrentTab->propertiesSelection(); break; default: downloadingTorrentTab->propertiesSelection(); + } } -} -void GUI::updateLists(bool force) { + void GUI::updateLists(bool force) { if(isVisible() || force) { - // update global informations - dlSpeedLbl->setText(tr("DL: %1 KiB/s").arg(QString(QByteArray::number(BTSession->getPayloadDownloadRate()/1024., 'f', 1)))); - upSpeedLbl->setText(tr("UP: %1 KiB/s").arg(QString(QByteArray::number(BTSession->getPayloadUploadRate()/1024., 'f', 1)))); - std::vector torrents = BTSession->getTorrents(); - std::vector::iterator torrentIT; - for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { - QTorrentHandle h = QTorrentHandle(*torrentIT); - if(!h.is_valid()) continue; - if(h.is_seed()) { - // Update in finished list - finishedTorrentTab->updateTorrent(h); - } else { - // Update in download list - if(downloadingTorrentTab->updateTorrent(h)) { - // Torrent was added, we may need to remove it from finished tab - finishedTorrentTab->deleteTorrent(h.hash()); - QFile::remove(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+h.hash()+".finished"); - } - } + // update global informations + dlSpeedLbl->setText(tr("DL: %1 KiB/s").arg(QString(QByteArray::number(BTSession->getPayloadDownloadRate()/1024., 'f', 1)))); + upSpeedLbl->setText(tr("UP: %1 KiB/s").arg(QString(QByteArray::number(BTSession->getPayloadUploadRate()/1024., 'f', 1)))); + std::vector torrents = BTSession->getTorrents(); + std::vector::iterator torrentIT; + for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { + QTorrentHandle h = QTorrentHandle(*torrentIT); + if(!h.is_valid()) continue; + if(h.is_seed()) { + // Update in finished list + finishedTorrentTab->updateTorrent(h); + } else { + // Update in download list + if(downloadingTorrentTab->updateTorrent(h)) { + // Torrent was added, we may need to remove it from finished tab + finishedTorrentTab->deleteTorrent(h.hash()); + TorrentPersistentData::saveSeedStatus(h); + } } + } } if(displaySpeedInTitle) { - QString dl_rate = QByteArray::number(BTSession->getSessionStatus().payload_download_rate/1024, 'f', 1); - QString up_rate = QByteArray::number(BTSession->getSessionStatus().payload_upload_rate/1024, 'f', 1); - setWindowTitle(tr("qBittorrent %1 (DL: %2KiB/s, UP: %3KiB/s)", "%1 is qBittorrent version").arg(QString::fromUtf8(VERSION)).arg(dl_rate).arg(up_rate)); - } -} - -// Called when a tracker requires authentication -void GUI::trackerAuthenticationRequired(QTorrentHandle& h) { - if(unauthenticated_trackers.indexOf(QPair(h, h.current_tracker())) < 0) { - // Tracker login - new trackerLogin(this, h); - } -} - -// Check connection status and display right icon -void GUI::checkConnectionStatus() { -// qDebug("Checking connection status"); - // Update Ratio - updateRatio(); - // update global informations - if(systrayIntegration) { + QString dl_rate = QByteArray::number(BTSession->getSessionStatus().payload_download_rate/1024, 'f', 1); + QString up_rate = QByteArray::number(BTSession->getSessionStatus().payload_upload_rate/1024, 'f', 1); + setWindowTitle(tr("qBittorrent %1 (DL: %2KiB/s, UP: %3KiB/s)", "%1 is qBittorrent version").arg(QString::fromUtf8(VERSION)).arg(dl_rate).arg(up_rate)); + } + } + + // Called when a tracker requires authentication + void GUI::trackerAuthenticationRequired(QTorrentHandle& h) { + if(unauthenticated_trackers.indexOf(QPair(h, h.current_tracker())) < 0) { + // Tracker login + new trackerLogin(this, h); + } + } + + // Check connection status and display right icon + void GUI::checkConnectionStatus() { + // qDebug("Checking connection status"); + // Update Ratio + updateRatio(); + // update global informations + if(systrayIntegration) { #ifdef Q_WS_WIN // Windows does not support html here QString html =tr("DL speed: %1 KiB/s", "e.g: Download speed: 10 KiB/s").arg(QString(QByteArray::number(BTSession->getPayloadDownloadRate()/1024., 'f', 1))); html += "\n"; html += tr("UP speed: %1 KiB/s", "e.g: Upload speed: 10 KiB/s").arg(QString(QByteArray::number(BTSession->getPayloadUploadRate()/1024., 'f', 1))); #else - QString html = "
"; - html += tr("qBittorrent"); - html += "
"; - html += "
"; - html += " "+tr("DL speed: %1 KiB/s", "e.g: Download speed: 10 KiB/s").arg(QString(QByteArray::number(BTSession->getPayloadDownloadRate()/1024., 'f', 1))); - html += "
"; - html += "
"; - html += " "+tr("UP speed: %1 KiB/s", "e.g: Upload speed: 10 KiB/s").arg(QString(QByteArray::number(BTSession->getPayloadUploadRate()/1024., 'f', 1))); - html += "
"; + QString html = "
"; + html += tr("qBittorrent"); + html += "
"; + html += "
"; + html += " "+tr("DL speed: %1 KiB/s", "e.g: Download speed: 10 KiB/s").arg(QString(QByteArray::number(BTSession->getPayloadDownloadRate()/1024., 'f', 1))); + html += "
"; + html += "
"; + html += " "+tr("UP speed: %1 KiB/s", "e.g: Upload speed: 10 KiB/s").arg(QString(QByteArray::number(BTSession->getPayloadUploadRate()/1024., 'f', 1))); + html += "
"; #endif - myTrayIcon->setToolTip(html); // tray icon - } - session_status sessionStatus = BTSession->getSessionStatus(); - if(sessionStatus.has_incoming_connections) { - // Connection OK - connecStatusLblIcon->setPixmap(QPixmap(QString::fromUtf8(":/Icons/skin/connected.png"))); - connecStatusLblIcon->setToolTip(QString::fromUtf8("")+tr("Connection Status:")+QString::fromUtf8("
")+tr("Online")); - }else{ - connecStatusLblIcon->setPixmap(QPixmap(QString::fromUtf8(":/Icons/skin/firewalled.png"))); - connecStatusLblIcon->setToolTip(QString::fromUtf8("")+tr("Connection status:")+QString::fromUtf8("
")+QString::fromUtf8("")+tr("No direct connections. This may indicate network configuration problems.")+QString::fromUtf8("")); + myTrayIcon->setToolTip(html); // tray icon + } + session_status sessionStatus = BTSession->getSessionStatus(); + if(sessionStatus.has_incoming_connections) { + // Connection OK + connecStatusLblIcon->setPixmap(QPixmap(QString::fromUtf8(":/Icons/skin/connected.png"))); + connecStatusLblIcon->setToolTip(QString::fromUtf8("")+tr("Connection Status:")+QString::fromUtf8("
")+tr("Online")); + }else{ + connecStatusLblIcon->setPixmap(QPixmap(QString::fromUtf8(":/Icons/skin/firewalled.png"))); + connecStatusLblIcon->setToolTip(QString::fromUtf8("")+tr("Connection status:")+QString::fromUtf8("
")+QString::fromUtf8("")+tr("No direct connections. This may indicate network configuration problems.")+QString::fromUtf8("")); + } } -} -/***************************************************** + /***************************************************** * * * Utils * * * *****************************************************/ -void GUI::downloadFromURLList(const QStringList& urls) { - BTSession->downloadFromURLList(urls); -} + void GUI::downloadFromURLList(const QStringList& urls) { + BTSession->downloadFromURLList(urls); + } -/***************************************************** + /***************************************************** * * * Options * * * *****************************************************/ -void GUI::createSystrayDelayed() { - static int timeout = 10; - if(QSystemTrayIcon::isSystemTrayAvailable()) { + void GUI::createSystrayDelayed() { + static int timeout = 10; + if(QSystemTrayIcon::isSystemTrayAvailable()) { // Ok, systray integration is now supported // Create systray icon createTrayIcon(); systrayIntegration = true; delete systrayCreator; - } else { - if(timeout) { - // Retry a bit later - systrayCreator->start(1000); - --timeout; } else { - // Timed out, apparently system really does not - // support systray icon - delete systrayCreator; + if(timeout) { + // Retry a bit later + systrayCreator->start(1000); + --timeout; + } else { + // Timed out, apparently system really does not + // support systray icon + delete systrayCreator; + } } } -} -void GUI::createTrayIcon() { - // Tray icon - #ifdef Q_WS_WIN - myTrayIcon = new QSystemTrayIcon(QIcon(QString::fromUtf8(":/Icons/skin/qbittorrent16.png")), this); - #endif - #ifndef Q_WS_WIN - myTrayIcon = new QSystemTrayIcon(QIcon(QString::fromUtf8(":/Icons/skin/qbittorrent22.png")), this); + void GUI::createTrayIcon() { + // Tray icon +#ifdef Q_WS_WIN + myTrayIcon = new QSystemTrayIcon(QIcon(QString::fromUtf8(":/Icons/skin/qbittorrent16.png")), this); #endif - // Tray icon Menu - myTrayIconMenu = new QMenu(this); - myTrayIconMenu->addAction(actionOpen); - myTrayIconMenu->addAction(actionDownload_from_URL); - myTrayIconMenu->addSeparator(); - 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); - myTrayIcon->setContextMenu(myTrayIconMenu); - connect(myTrayIcon, SIGNAL(messageClicked()), this, SLOT(balloonClicked())); - // End of Icon Menu - connect(myTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(toggleVisibility(QSystemTrayIcon::ActivationReason))); - myTrayIcon->show(); -} - -// Display Program Options -void GUI::on_actionOptions_triggered() { - options = new options_imp(this); - connect(options, SIGNAL(status_changed(bool)), this, SLOT(OptionsSaved(bool))); - options->show(); -} - -// Is executed each time options are saved -void GUI::OptionsSaved(bool deleteOptions) { - BTSession->addConsoleMessage(tr("Options were saved successfully.")); - bool newSystrayIntegration = options->systrayIntegration(); - if(newSystrayIntegration != systrayIntegration) { - if(newSystrayIntegration) { - // create the trayicon - createTrayIcon(); - } else { - // Destroy trayicon - delete myTrayIcon; - delete myTrayIconMenu; +#ifndef Q_WS_WIN + myTrayIcon = new QSystemTrayIcon(QIcon(QString::fromUtf8(":/Icons/skin/qbittorrent22.png")), this); +#endif + // Tray icon Menu + myTrayIconMenu = new QMenu(this); + myTrayIconMenu->addAction(actionOpen); + myTrayIconMenu->addAction(actionDownload_from_URL); + myTrayIconMenu->addSeparator(); + 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); + myTrayIcon->setContextMenu(myTrayIconMenu); + connect(myTrayIcon, SIGNAL(messageClicked()), this, SLOT(balloonClicked())); + // End of Icon Menu + connect(myTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(toggleVisibility(QSystemTrayIcon::ActivationReason))); + myTrayIcon->show(); + } + + // Display Program Options + void GUI::on_actionOptions_triggered() { + options = new options_imp(this); + connect(options, SIGNAL(status_changed(bool)), this, SLOT(OptionsSaved(bool))); + options->show(); + } + + // Is executed each time options are saved + void GUI::OptionsSaved(bool deleteOptions) { + BTSession->addConsoleMessage(tr("Options were saved successfully.")); + bool newSystrayIntegration = options->systrayIntegration(); + if(newSystrayIntegration != systrayIntegration) { + if(newSystrayIntegration) { + // create the trayicon + createTrayIcon(); + } else { + // Destroy trayicon + delete myTrayIcon; + delete myTrayIconMenu; + } + systrayIntegration = newSystrayIntegration; + } + // Update Web UI + if (options->isWebUiEnabled()) { + quint16 port = options->webUiPort(); + QString username = options->webUiUsername(); + QString password = options->webUiPassword(); + initWebUi(username, password, port); + } else if(httpServer) { + delete httpServer; } - systrayIntegration = newSystrayIntegration; + // Update session + configureSession(deleteOptions); } - // Update Web UI - if (options->isWebUiEnabled()) { - quint16 port = options->webUiPort(); - QString username = options->webUiUsername(); - QString password = options->webUiPassword(); - initWebUi(username, password, port); - } else if(httpServer) { - delete httpServer; - } - // Update session - configureSession(deleteOptions); -} - -bool GUI::initWebUi(QString username, QString password, int port) { - if(httpServer) - httpServer->close(); - else - httpServer = new HttpServer(BTSession, 3000, this); - httpServer->setAuthorization(username, password); - bool success = httpServer->listen(QHostAddress::Any, port); - if (success) - qDebug("Web UI listening on port %d", port); - else - QMessageBox::critical(this, "Web User Interface Error", "Unable to initialize HTTP Server on port " + misc::toQString(port)); - return success; -} -/***************************************************** + bool GUI::initWebUi(QString username, QString password, int port) { + if(httpServer) + httpServer->close(); + else + httpServer = new HttpServer(BTSession, 3000, this); + httpServer->setAuthorization(username, password); + bool success = httpServer->listen(QHostAddress::Any, port); + if (success) + qDebug("Web UI listening on port %d", port); + else + QMessageBox::critical(this, "Web User Interface Error", "Unable to initialize HTTP Server on port " + misc::toQString(port)); + return success; + } + + /***************************************************** * * * HTTP Downloader * * * *****************************************************/ -// Display an input dialog to prompt user for -// an url -void GUI::on_actionDownload_from_URL_triggered() { - downloadFromURL *downloadFromURLDialog = new downloadFromURL(this); - connect(downloadFromURLDialog, SIGNAL(urlsReadyToBeDownloaded(const QStringList&)), BTSession, SLOT(downloadFromURLList(const QStringList&))); -} + // Display an input dialog to prompt user for + // an url + void GUI::on_actionDownload_from_URL_triggered() { + downloadFromURL *downloadFromURLDialog = new downloadFromURL(this); + connect(downloadFromURLDialog, SIGNAL(urlsReadyToBeDownloaded(const QStringList&)), BTSession, SLOT(downloadFromURLList(const QStringList&))); + } diff --git a/src/arborescence.h b/src/arborescence.h index 0ebd23765..6bcbdfabb 100644 --- a/src/arborescence.h +++ b/src/arborescence.h @@ -199,7 +199,7 @@ class arborescence { Q_ASSERT(root->getSize() == t->total_size()); } - arborescence(torrent_info const& t, std::vector fp, int *prioritiesTab) { + arborescence(torrent_info const& t, std::vector fp, std::vector files_priority) { torrent_info::file_iterator fi = t.begin_files(); if(t.num_files() > 1) { qDebug("More than one file in the torrent, setting a folder as root"); @@ -207,13 +207,13 @@ class arborescence { } else { // XXX: Will crash if there is no file in torrent qDebug("one file in the torrent, setting it as root with index 0"); - root = new torrent_file(0, misc::toQString(t.name()), false, fi->size, 0, ((double)fp[0])/t.file_at(0).size, prioritiesTab[0]); + root = new torrent_file(0, misc::toQString(t.name()), false, fi->size, 0, ((double)fp[0])/t.file_at(0).size, files_priority.at(0)); return; } int i = 0; while(fi != t.end_files()) { QString path = QDir::cleanPath(misc::toQString(fi->path.string())); - addFile(path, fi->size, i, ((double)fp[i])/t.file_at(i).size, prioritiesTab[i]); + addFile(path, fi->size, i, ((double)fp[i])/t.file_at(i).size, files_priority.at(i)); fi++; ++i; } diff --git a/src/bittorrent.cpp b/src/bittorrent.cpp index fed917041..cc8fb0ca2 100644 --- a/src/bittorrent.cpp +++ b/src/bittorrent.cpp @@ -40,6 +40,7 @@ #include "misc.h" #include "downloadThread.h" #include "filterParserThread.h" +#include "torrentPersistentData.h" #include #include #include @@ -107,8 +108,8 @@ bittorrent::~bittorrent() { delete filterParser; delete downloader; if(FSWatcher) { - delete FSWatcher; - delete FSMutex; + delete FSWatcher; + delete FSMutex; } // Delete BT session qDebug("Deleting session"); @@ -126,22 +127,22 @@ void bittorrent::preAllocateAllFiles(bool b) { void bittorrent::deleteBigRatios() { if(ratio_limit == -1) return; - std::vector torrents = getTorrents(); - std::vector::iterator torrentIT; - for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { - QTorrentHandle h = QTorrentHandle(*torrentIT); - if(!h.is_valid()) continue; - if(h.is_seed()) { - QString hash = h.hash(); - float ratio = getRealRatio(hash); - if(ratio <= MAX_RATIO && ratio > ratio_limit) { - QString fileName = h.name(); - addConsoleMessage(tr("%1 reached the maximum ratio you set.").arg(fileName)); - deleteTorrent(hash); - //emit torrent_ratio_deleted(fileName); - } - } + std::vector torrents = getTorrents(); + std::vector::iterator torrentIT; + for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { + QTorrentHandle h = QTorrentHandle(*torrentIT); + if(!h.is_valid()) continue; + if(h.is_seed()) { + QString hash = h.hash(); + float ratio = getRealRatio(hash); + if(ratio <= MAX_RATIO && ratio > ratio_limit) { + QString fileName = h.name(); + addConsoleMessage(tr("%1 reached the maximum ratio you set.").arg(fileName)); + deleteTorrent(hash); + //emit torrent_ratio_deleted(fileName); + } } + } } void bittorrent::setDownloadLimit(QString hash, long val) { @@ -206,22 +207,22 @@ int bittorrent::getUpTorrentPriority(QString hash) const { // Calculate the ETA using GASA // GASA: global Average Speed Algorithm qlonglong bittorrent::getETA(QString hash) const { - QTorrentHandle h = getTorrentHandle(hash); - if(!h.is_valid()) return -1; - switch(h.state()) { - case torrent_status::downloading: { - if(h.active_time() == 0) - return -1; - double avg_speed = (double)h.all_time_download() / h.active_time(); - return (qlonglong) floor((double) (h.actual_size() - h.total_wanted_done()) / avg_speed); - } - default: + QTorrentHandle h = getTorrentHandle(hash); + if(!h.is_valid()) return -1; + switch(h.state()) { + case torrent_status::downloading: { + if(h.active_time() == 0) return -1; + double avg_speed = (double)h.all_time_download() / h.active_time(); + return (qlonglong) floor((double) (h.actual_size() - h.total_wanted_done()) / avg_speed); } + default: + return -1; + } } std::vector bittorrent::getTorrents() const { - return s->get_torrents(); + return s->get_torrents(); } // Return the torrent handle, given its hash @@ -232,28 +233,28 @@ QTorrentHandle bittorrent::getTorrentHandle(QString hash) const{ unsigned int bittorrent::getFinishedPausedTorrentsNb() const { unsigned int nbPaused = 0; std::vector torrents = getTorrents(); - std::vector::iterator torrentIT; - for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { - QTorrentHandle h = QTorrentHandle(*torrentIT); - if(!h.is_valid()) continue; - if(h.is_seed() && h.is_paused()) { - ++nbPaused; - } + std::vector::iterator torrentIT; + for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { + QTorrentHandle h = QTorrentHandle(*torrentIT); + if(!h.is_valid()) continue; + if(h.is_seed() && h.is_paused()) { + ++nbPaused; } + } return nbPaused; } unsigned int bittorrent::getUnfinishedPausedTorrentsNb() const { unsigned int nbPaused = 0; std::vector torrents = getTorrents(); - std::vector::iterator torrentIT; - for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { - QTorrentHandle h = QTorrentHandle(*torrentIT); - if(!h.is_valid()) continue; - if(!h.is_seed() && h.is_paused()) { - ++nbPaused; - } + std::vector::iterator torrentIT; + for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { + QTorrentHandle h = QTorrentHandle(*torrentIT); + if(!h.is_valid()) continue; + if(!h.is_seed() && h.is_paused()) { + ++nbPaused; } + } return nbPaused; } @@ -270,7 +271,7 @@ void bittorrent::deleteTorrent(QString hash, bool permanent) { QString fileName = h.name(); // Remove it from session if(permanent) - s->remove_torrent(h.get_torrent_handle(), session::delete_files); + s->remove_torrent(h.get_torrent_handle(), session::delete_files); else s->remove_torrent(h.get_torrent_handle()); // Remove it from torrent backup directory @@ -281,6 +282,7 @@ void bittorrent::deleteTorrent(QString hash, bool permanent) { foreach(const QString &file, files) { torrentBackup.remove(file); } + TorrentPersistentData::deletePersistentData(hash); // Remove tracker errors trackersErrors.remove(hash); if(permanent) @@ -291,53 +293,49 @@ void bittorrent::deleteTorrent(QString hash, bool permanent) { } void bittorrent::pauseAllTorrents() { - std::vector torrents = getTorrents(); - std::vector::iterator torrentIT; - for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { - QTorrentHandle h = QTorrentHandle(*torrentIT); - if(!h.is_valid()) continue; - if(!h.is_paused()) { - h.pause(); - emit pausedTorrent(h); - } + std::vector torrents = getTorrents(); + std::vector::iterator torrentIT; + for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { + QTorrentHandle h = QTorrentHandle(*torrentIT); + if(!h.is_valid()) continue; + if(!h.is_paused()) { + h.pause(); + emit pausedTorrent(h); } + } } void bittorrent::resumeAllTorrents() { - std::vector torrents = getTorrents(); - std::vector::iterator torrentIT; - for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { - QTorrentHandle h = QTorrentHandle(*torrentIT); - if(!h.is_valid()) continue; - if(h.is_paused()) { - h.resume(); - emit resumedTorrent(h); - } + std::vector torrents = getTorrents(); + std::vector::iterator torrentIT; + for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { + QTorrentHandle h = QTorrentHandle(*torrentIT); + if(!h.is_valid()) continue; + if(h.is_paused()) { + h.resume(); + emit resumedTorrent(h); } + } } void bittorrent::pauseTorrent(QString hash) { - QTorrentHandle h = getTorrentHandle(hash); - if(!h.is_paused()) { - h.pause(); - emit pausedTorrent(h); - } + QTorrentHandle h = getTorrentHandle(hash); + if(!h.is_paused()) { + h.pause(); + emit pausedTorrent(h); + } } void bittorrent::resumeTorrent(QString hash) { - QTorrentHandle h = getTorrentHandle(hash); - if(h.is_paused()) { - h.resume(); - emit resumedTorrent(h); - } + QTorrentHandle h = getTorrentHandle(hash); + if(h.is_paused()) { + h.resume(); + emit resumedTorrent(h); + } } void bittorrent::loadWebSeeds(QString hash) { - QFile urlseeds_file(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".urlseeds"); - if(!urlseeds_file.open(QIODevice::ReadOnly | QIODevice::Text)) return; - QByteArray urlseeds_lines = urlseeds_file.readAll(); - urlseeds_file.close(); - QList url_seeds = urlseeds_lines.split('\n'); + QVariantList url_seeds = TorrentPersistentData::getUrlSeeds(hash); QTorrentHandle h = getTorrentHandle(hash); // First remove from the torrent the url seeds that were deleted // in a previous session @@ -352,7 +350,8 @@ void bittorrent::loadWebSeeds(QString hash) { h.remove_url_seed(existing_seed); } // Add the ones that were added in a previous session - foreach(const QByteArray &url_seed, url_seeds) { + foreach(const QVariant &var_url_seed, url_seeds) { + QString url_seed = var_url_seed.toString(); if(!url_seed.isEmpty()) { // XXX: Should we check if it is already in the list before adding it // or is libtorrent clever enough to know @@ -362,11 +361,12 @@ void bittorrent::loadWebSeeds(QString hash) { } // Add a torrent to the bittorrent session -QTorrentHandle bittorrent::addTorrent(QString path, bool fromScanDir, QString from_url, bool) { +QTorrentHandle bittorrent::addTorrent(QString path, bool fromScanDir, QString from_url, bool resumed) { QTorrentHandle h; bool fastResume=false; QDir torrentBackup(misc::qBittorrentPath() + "BT_backup"); - QString file, dest_file; + QString file, dest_file, hash; + boost::intrusive_ptr t; // Checking if BT_backup Dir exists // create it if it is not @@ -382,75 +382,71 @@ QTorrentHandle bittorrent::addTorrent(QString path, bool fromScanDir, QString fr return h; } Q_ASSERT(!file.startsWith("http://", Qt::CaseInsensitive) && !file.startsWith("https://", Qt::CaseInsensitive) && !file.startsWith("ftp://", Qt::CaseInsensitive)); + qDebug("Adding %s to download list", file.toLocal8Bit().data()); - boost::intrusive_ptr t; try { - // Getting torrent file informations - t = new torrent_info(file.toLocal8Bit().data()); + // Getting torrent file informations + t = new torrent_info(file.toLocal8Bit().data()); } catch(std::exception&) { - if(!from_url.isNull()) { - addConsoleMessage(tr("Unable to decode torrent file: '%1'", "e.g: Unable to decode torrent file: '/home/y/xxx.torrent'").arg(from_url), QString::fromUtf8("red")); - //emit invalidTorrent(from_url); - QFile::remove(file); - }else{ - addConsoleMessage(tr("Unable to decode torrent file: '%1'", "e.g: Unable to decode torrent file: '/home/y/xxx.torrent'").arg(file), QString::fromUtf8("red")); - //emit invalidTorrent(file); - } - addConsoleMessage(tr("This file is either corrupted or this isn't a torrent."),QString::fromUtf8("red")); - if(fromScanDir) { - // Remove file - QFile::remove(file); - } - return h; + if(!from_url.isNull()) { + addConsoleMessage(tr("Unable to decode torrent file: '%1'", "e.g: Unable to decode torrent file: '/home/y/xxx.torrent'").arg(from_url), QString::fromUtf8("red")); + //emit invalidTorrent(from_url); + QFile::remove(file); + }else{ + addConsoleMessage(tr("Unable to decode torrent file: '%1'", "e.g: Unable to decode torrent file: '/home/y/xxx.torrent'").arg(file), QString::fromUtf8("red")); + //emit invalidTorrent(file); + } + addConsoleMessage(tr("This file is either corrupted or this isn't a torrent."),QString::fromUtf8("red")); + if(fromScanDir) { + // Remove file + QFile::remove(file); + } + return h; } qDebug(" -> Hash: %s", misc::toString(t->info_hash()).c_str()); qDebug(" -> Name: %s", t->name().c_str()); - QString hash = misc::toQString(t->info_hash()); + hash = misc::toQString(t->info_hash()); if(file.startsWith(torrentBackup.path())) { - QFileInfo fi(file); - QString old_hash = fi.baseName(); - if(old_hash != hash){ - qDebug("* ERROR: Strange, hash changed from %s to %s", old_hash.toLocal8Bit().data(), hash.toLocal8Bit().data()); - } + QFileInfo fi(file); + QString old_hash = fi.baseName(); + if(old_hash != hash){ + qDebug("* ERROR: Strange, hash changed from %s to %s", old_hash.toLocal8Bit().data(), hash.toLocal8Bit().data()); + } } // Check if torrent is already in download list if(s->find_torrent(t->info_hash()).is_valid()) { - qDebug("/!\\ Torrent is already in download list"); - // Update info Bar - if(!fromScanDir) { - if(!from_url.isNull()) { - // If download from url, remove temp file - QFile::remove(file); - addConsoleMessage(tr("'%1' is already in download list.", "e.g: 'xxx.avi' is already in download list.").arg(from_url)); - //emit duplicateTorrent(from_url); - }else{ - addConsoleMessage(tr("'%1' is already in download list.", "e.g: 'xxx.avi' is already in download list.").arg(file)); - //emit duplicateTorrent(file); - } + qDebug("/!\\ Torrent is already in download list"); + // Update info Bar + if(!fromScanDir) { + if(!from_url.isNull()) { + // If download from url, remove temp file + QFile::remove(file); + addConsoleMessage(tr("'%1' is already in download list.", "e.g: 'xxx.avi' is already in download list.").arg(from_url)); + //emit duplicateTorrent(from_url); }else{ - // Delete torrent from scan dir - QFile::remove(file); + addConsoleMessage(tr("'%1' is already in download list.", "e.g: 'xxx.avi' is already in download list.").arg(file)); + //emit duplicateTorrent(file); } - return h; + }else{ + // Delete torrent from scan dir + QFile::remove(file); + } + return h; } add_torrent_params p; //Getting fast resume data if existing std::vector buf; - qDebug("Trying to load fastresume data: %s", (torrentBackup.path()+QDir::separator()+hash+QString(".fastresume")).toLocal8Bit().data()); - if (load_file((torrentBackup.path()+QDir::separator()+hash+QString(".fastresume")).toLocal8Bit().data(), buf) == 0) { + if(resumed) { + qDebug("Trying to load fastresume data: %s", (torrentBackup.path()+QDir::separator()+hash+QString(".fastresume")).toLocal8Bit().data()); + if (load_file((torrentBackup.path()+QDir::separator()+hash+QString(".fastresume")).toLocal8Bit().data(), buf) == 0) { fastResume = true; p.resume_data = &buf; qDebug("Successfuly loaded"); + } } QString savePath = getSavePath(hash); - // Save save_path to hard drive - QFile savepath_file(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".savepath")); - if(!savepath_file.exists()) { - savepath_file.open(QIODevice::WriteOnly | QIODevice::Text); - savepath_file.write(savePath.toLocal8Bit()); - savepath_file.close(); - } - if(defaultTempPath.isEmpty() || QFile::exists(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".finished"))) { + qDebug("addTorrent: using save_path: %s", savePath.toUtf8().data()); + if(defaultTempPath.isEmpty() || (resumed && TorrentPersistentData::isSeed(hash))) { p.save_path = savePath.toLocal8Bit().data(); } else { p.save_path = defaultTempPath.toLocal8Bit().data(); @@ -467,17 +463,17 @@ QTorrentHandle bittorrent::addTorrent(QString path, bool fromScanDir, QString fr p.auto_managed = false; // Because it is added in paused state // Adding torrent to bittorrent session try { - h = QTorrentHandle(s->add_torrent(p)); + h = QTorrentHandle(s->add_torrent(p)); }catch(std::exception e){ qDebug("Error: %s", e.what()); } // Check if it worked if(!h.is_valid()) { - // No need to keep on, it failed. - qDebug("/!\\ Error: Invalid handle"); - // If download from url, remove temp file - if(!from_url.isNull()) QFile::remove(file); - return h; + // No need to keep on, it failed. + qDebug("/!\\ Error: Invalid handle"); + // If download from url, remove temp file + if(!from_url.isNull()) QFile::remove(file); + return h; } // Connections limit per torrent h.set_max_connections(maxConnecsPerTorrent); @@ -485,76 +481,71 @@ QTorrentHandle bittorrent::addTorrent(QString path, bool fromScanDir, QString fr h.set_max_uploads(maxUploadsPerTorrent); // Load filtered files loadFilesPriorities(h); - // Load custom url seeds - loadWebSeeds(hash); - // Load speed limit from hard drive - loadTorrentSpeedLimits(hash); - // Load trackers - bool loaded_trackers = loadTrackerFile(hash); - // Doing this to order trackers well - if(!loaded_trackers) { - saveTrackerFile(hash); - loadTrackerFile(hash); + if(resumed) { + // Load custom url seeds + loadWebSeeds(hash); + // Load speed limit from hard drive + loadTorrentSpeedLimits(hash); + // Load trackers + loadTrackerFile(hash); + } else { + // Sequential download + if(TorrentTempData::hasTempData(hash)) { + qDebug("addTorrent: Setting download as sequential (from tmp data)"); + h.set_sequential_download(TorrentTempData::isSequential(hash)); + } + // Save persistent data for new torrent + TorrentPersistentData::saveTorrentPersistentData(h); + // Save save_path + if(!defaultTempPath.isEmpty()) { + qDebug("addTorrent: Saving save_path in persistent data: %s", savePath.toUtf8().data()); + TorrentPersistentData::saveSavePath(hash, savePath); + } } QString newFile = torrentBackup.path() + QDir::separator() + hash + ".torrent"; if(file != newFile) { - // Delete file from torrentBackup directory in case it exists because - // QFile::copy() do not overwrite - QFile::remove(newFile); - // Copy it to torrentBackup directory - QFile::copy(file, newFile); - } - // Incremental download - if(QFile::exists(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".incremental")) { - qDebug("Incremental download enabled for %s", t->name().c_str()); - h.set_sequential_download(true); + // Delete file from torrentBackup directory in case it exists because + // QFile::copy() do not overwrite + QFile::remove(newFile); + // Copy it to torrentBackup directory + QFile::copy(file, newFile); } if(!addInPause && !fastResume) { - // Start torrent because it was added in paused state - h.resume(); + // Start torrent because it was added in paused state + h.resume(); } // If download from url, remove temp file if(!from_url.isNull()) QFile::remove(file); // Delete from scan dir to avoid trying to download it again if(fromScanDir) { - QFile::remove(file); + QFile::remove(file); } // Send torrent addition signal if(!from_url.isNull()) { - if(fastResume) - addConsoleMessage(tr("'%1' resumed. (fast resume)", "'/home/y/xxx.torrent' was resumed. (fast resume)").arg(from_url)); - else - addConsoleMessage(tr("'%1' added to download list.", "'/home/y/xxx.torrent' was added to download list.").arg(from_url)); + if(fastResume) + addConsoleMessage(tr("'%1' resumed. (fast resume)", "'/home/y/xxx.torrent' was resumed. (fast resume)").arg(from_url)); + else + addConsoleMessage(tr("'%1' added to download list.", "'/home/y/xxx.torrent' was added to download list.").arg(from_url)); }else{ - if(fastResume) - addConsoleMessage(tr("'%1' resumed. (fast resume)", "'/home/y/xxx.torrent' was resumed. (fast resume)").arg(file)); - else - addConsoleMessage(tr("'%1' added to download list.", "'/home/y/xxx.torrent' was added to download list.").arg(file)); + if(fastResume) + addConsoleMessage(tr("'%1' resumed. (fast resume)", "'/home/y/xxx.torrent' was resumed. (fast resume)").arg(file)); + else + addConsoleMessage(tr("'%1' added to download list.", "'/home/y/xxx.torrent' was added to download list.").arg(file)); } emit addedTorrent(h); return h; } -// Check in .priorities file if the user filtered files -// in this torrent. +// Check if the user filtered files in this torrent. bool bittorrent::has_filtered_files(QString hash) const{ - QFile pieces_file(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".priorities"); - // Read saved file - if(!pieces_file.open(QIODevice::ReadOnly | QIODevice::Text)) { - return false; - } - QByteArray pieces_text = pieces_file.readAll(); - pieces_file.close(); - QList pieces_priorities_list = pieces_text.split('\n'); - unsigned int listSize = pieces_priorities_list.size(); - for(unsigned int i=0; i 7) { priority = 1; } - if(!priority) { + if(!priority) return true; - } } return false; } @@ -648,21 +639,21 @@ void bittorrent::enableLSD(bool b) { } void bittorrent::loadSessionState() { - boost::filesystem::ifstream ses_state_file((misc::qBittorrentPath()+QString::fromUtf8("ses_state")).toLocal8Bit().data() - , std::ios_base::binary); - ses_state_file.unsetf(std::ios_base::skipws); - s->load_state(bdecode( - std::istream_iterator(ses_state_file) - , std::istream_iterator())); + boost::filesystem::ifstream ses_state_file((misc::qBittorrentPath()+QString::fromUtf8("ses_state")).toLocal8Bit().data() + , std::ios_base::binary); + ses_state_file.unsetf(std::ios_base::skipws); + s->load_state(bdecode( + std::istream_iterator(ses_state_file) + , std::istream_iterator())); } void bittorrent::saveSessionState() { - qDebug("Saving session state to disk..."); - entry session_state = s->state(); - boost::filesystem::ofstream out((misc::qBittorrentPath()+QString::fromUtf8("ses_state")).toLocal8Bit().data() - , std::ios_base::binary); - out.unsetf(std::ios_base::skipws); - bencode(std::ostream_iterator(out), session_state); + qDebug("Saving session state to disk..."); + entry session_state = s->state(); + boost::filesystem::ofstream out((misc::qBittorrentPath()+QString::fromUtf8("ses_state")).toLocal8Bit().data() + , std::ios_base::binary); + out.unsetf(std::ios_base::skipws); + bencode(std::ostream_iterator(out), session_state); } // Enable DHT @@ -677,18 +668,18 @@ bool bittorrent::enableDHT(bool b) { try{ dht_state = bdecode(std::istream_iterator(dht_state_file), std::istream_iterator()); }catch (std::exception&) {} - } + } try { - s->start_dht(dht_state); - s->add_dht_router(std::make_pair(std::string("router.bittorrent.com"), 6881)); - s->add_dht_router(std::make_pair(std::string("router.utorrent.com"), 6881)); - s->add_dht_router(std::make_pair(std::string("router.bitcomet.com"), 6881)); - DHTEnabled = true; - qDebug("DHT enabled"); - }catch(std::exception e) { - qDebug("Could not enable DHT, reason: %s", e.what()); - return false; - } + s->start_dht(dht_state); + s->add_dht_router(std::make_pair(std::string("router.bittorrent.com"), 6881)); + s->add_dht_router(std::make_pair(std::string("router.utorrent.com"), 6881)); + s->add_dht_router(std::make_pair(std::string("router.bitcomet.com"), 6881)); + DHTEnabled = true; + qDebug("DHT enabled"); + }catch(std::exception e) { + qDebug("Could not enable DHT, reason: %s", e.what()); + return false; + } } } else { if(DHTEnabled) { @@ -715,7 +706,7 @@ void bittorrent::saveTorrentSpeedLimits(QString hash) { } void bittorrent::loadTorrentSpeedLimits(QString hash) { -// qDebug("Loading speedLimits file for %s", hash.toLocal8Bit().data()); + // qDebug("Loading speedLimits file for %s", hash.toLocal8Bit().data()); QTorrentHandle h = getTorrentHandle(hash); QFile speeds_file(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".speedLimits"); if(!speeds_file.open(QIODevice::ReadOnly | QIODevice::Text)) { @@ -732,7 +723,7 @@ void bittorrent::loadTorrentSpeedLimits(QString hash) { h.set_upload_limit(speeds.at(1).toInt()); } -// Read pieces priorities from .priorities file +// Read pieces priorities from hard disk // and ask QTorrentHandle to consider them void bittorrent::loadFilesPriorities(QTorrentHandle &h) { qDebug("Applying pieces priorities"); @@ -740,31 +731,19 @@ void bittorrent::loadFilesPriorities(QTorrentHandle &h) { qDebug("/!\\ Error: Invalid handle"); return; } - unsigned int nbFiles = h.num_files(); - QString hash = h.hash(); - QFile pieces_file(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".priorities"); - if(!pieces_file.exists()){ - return; - } - // Read saved file - if(!pieces_file.open(QIODevice::ReadOnly | QIODevice::Text)) { - qDebug("* Error: Couldn't open priorities file: %s", hash.toLocal8Bit().data()); - return; - } - QByteArray pieces_priorities = pieces_file.readAll(); - pieces_file.close(); - QList pieces_priorities_list = pieces_priorities.split('\n'); - if((unsigned int)pieces_priorities_list.size() != nbFiles+1) { - std::cerr << "* Error: Corrupted priorities file\n"; - return; - } std::vector v; - for(unsigned int i=0; i 7) { priority = 1; } - qDebug("Setting piece piority to %d", priority); + qDebug("Setting file piority to %d", priority); v.push_back(priority); } h.prioritize_files(v); @@ -800,47 +779,47 @@ void bittorrent::saveFastResumeData() { QTorrentHandle h = QTorrentHandle(*torrentIT); if(!h.is_valid() || !h.has_metadata()) continue; if(isQueueingEnabled()) - saveTorrentPriority(h.hash(), h.queue_position()); + TorrentPersistentData::savePriority(h); if(h.is_paused()) continue; if(h.state() == torrent_status::checking_files || h.state() == torrent_status::queued_for_checking) continue; h.save_resume_data(); ++num_resume_data; } while (num_resume_data > 0) { - alert const* a = s->wait_for_alert(seconds(30)); - if (a == 0) { - std::cerr << " aborting with " << num_resume_data << " outstanding " - "torrents to save resume data for" << std::endl; - break; - } - // Saving fastresume data can fail - save_resume_data_failed_alert const* rda = dynamic_cast(a); - if (rda) { - --num_resume_data; - s->pop_alert(); - // Remove torrent from session - s->remove_torrent(rda->handle); - continue; - } - save_resume_data_alert const* rd = dynamic_cast(a); - if (!rd) { - s->pop_alert(); - continue; - } - // Saving fast resume data was successful + alert const* a = s->wait_for_alert(seconds(30)); + if (a == 0) { + std::cerr << " aborting with " << num_resume_data << " outstanding " + "torrents to save resume data for" << std::endl; + break; + } + // Saving fastresume data can fail + save_resume_data_failed_alert const* rda = dynamic_cast(a); + if (rda) { --num_resume_data; - if (!rd->resume_data) continue; - QDir torrentBackup(misc::qBittorrentPath() + "BT_backup"); - QTorrentHandle h(rd->handle); - // Remove old fastresume file if it exists - QFile::remove(torrentBackup.path()+QDir::separator()+ h.hash() + ".fastresume"); - QString file = h.hash()+".fastresume"; - boost::filesystem::ofstream out(fs::path(torrentBackup.path().toLocal8Bit().data()) / file.toLocal8Bit().data(), std::ios_base::binary); - out.unsetf(std::ios_base::skipws); - bencode(std::ostream_iterator(out), *rd->resume_data); + s->pop_alert(); // Remove torrent from session - s->remove_torrent(rd->handle); + s->remove_torrent(rda->handle); + continue; + } + save_resume_data_alert const* rd = dynamic_cast(a); + if (!rd) { s->pop_alert(); + continue; + } + // Saving fast resume data was successful + --num_resume_data; + if (!rd->resume_data) continue; + QDir torrentBackup(misc::qBittorrentPath() + "BT_backup"); + QTorrentHandle h(rd->handle); + // Remove old fastresume file if it exists + QFile::remove(torrentBackup.path()+QDir::separator()+ h.hash() + ".fastresume"); + QString file = h.hash()+".fastresume"; + boost::filesystem::ofstream out(fs::path(torrentBackup.path().toLocal8Bit().data()) / file.toLocal8Bit().data(), std::ios_base::binary); + out.unsetf(std::ios_base::skipws); + bencode(std::ostream_iterator(out), *rd->resume_data); + // Remove torrent from session + s->remove_torrent(rd->handle); + s->pop_alert(); } } @@ -896,14 +875,14 @@ void bittorrent::scanDirectory(QString scan_dir) { filters << "*.torrent"; QStringList files = dir.entryList(filters, QDir::Files, QDir::Unsorted); foreach(const QString &file, files) { - QString fullPath = dir.path()+QDir::separator()+file; - QFile torrent(fullPath); - if(torrent.size() != 0) { - qDebug("Adding for scan_dir: %s", fullPath.toLocal8Bit().data()); - addTorrent(fullPath, true); - } else { - qDebug("Ignoring empty file: %s", fullPath.toLocal8Bit().data()); - } + QString fullPath = dir.path()+QDir::separator()+file; + QFile torrent(fullPath); + if(torrent.size() != 0) { + qDebug("Adding for scan_dir: %s", fullPath.toLocal8Bit().data()); + addTorrent(fullPath, true); + } else { + qDebug("Ignoring empty file: %s", fullPath.toLocal8Bit().data()); + } } FSMutex->unlock(); } @@ -912,6 +891,10 @@ void bittorrent::setDefaultSavePath(QString savepath) { defaultSavePath = savepath; } +bool bittorrent::useTemporaryFolder() const { + return !defaultTempPath.isEmpty(); +} + void bittorrent::setDefaultTempPath(QString temppath) { if(defaultTempPath == temppath) return; @@ -938,23 +921,28 @@ void bittorrent::setDefaultTempPath(QString temppath) { defaultTempPath = temppath; } +void bittorrent::saveTrackerFile(QString hash) { + QTorrentHandle h = getTorrentHandle(hash); + TorrentPersistentData::saveTrackers(h); +} + // Enable directory scanning void bittorrent::enableDirectoryScanning(QString scan_dir) { if(!scan_dir.isEmpty()) { if(FSWatcher == 0) { - FSMutex = new QMutex(); - FSWatcher = new QFileSystemWatcher(QStringList(scan_dir), this); - connect(FSWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(scanDirectory(QString))); + FSMutex = new QMutex(); + FSWatcher = new QFileSystemWatcher(QStringList(scan_dir), this); + connect(FSWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(scanDirectory(QString))); + // Initial scan + scanDirectory(scan_dir); + } else { + QString old_scan_dir = FSWatcher->directories().first(); + if(old_scan_dir != scan_dir) { + FSWatcher->removePath(old_scan_dir); + FSWatcher->addPath(scan_dir); // Initial scan scanDirectory(scan_dir); - } else { - QString old_scan_dir = FSWatcher->directories().first(); - if(old_scan_dir != scan_dir) { - FSWatcher->removePath(old_scan_dir); - FSWatcher->addPath(scan_dir); - // Initial scan - scanDirectory(scan_dir); - } + } } } } @@ -962,8 +950,8 @@ void bittorrent::enableDirectoryScanning(QString scan_dir) { // Disable directory scanning void bittorrent::disableDirectoryScanning() { if(FSWatcher) { - delete FSWatcher; - delete FSMutex; + delete FSWatcher; + delete FSMutex; } } @@ -1032,46 +1020,21 @@ void bittorrent::setDeleteRatio(float ratio) { } } -bool bittorrent::loadTrackerFile(QString hash) { - QDir torrentBackup(misc::qBittorrentPath() + "BT_backup"); - QFile tracker_file(torrentBackup.path()+QDir::separator()+ hash + ".trackers"); - if(!tracker_file.exists()) return false; - tracker_file.open(QIODevice::ReadOnly | QIODevice::Text); - QStringList lines = QString::fromUtf8(tracker_file.readAll().data()).split("\n"); +void bittorrent::loadTrackerFile(QString hash) { + QHash tiers = TorrentPersistentData::getTrackers(hash); std::vector trackers; - foreach(const QString &line, lines) { - QStringList parts = line.split("|"); - if(parts.size() != 2) continue; - announce_entry t(parts[0].toStdString()); - t.tier = parts[1].toInt(); + foreach(const QString tracker_url, tiers.keys()) { + announce_entry t(tracker_url.toStdString()); + t.tier = tiers[tracker_url].toInt(); trackers.push_back(t); } if(!trackers.empty()) { QTorrentHandle h = getTorrentHandle(hash); h.replace_trackers(trackers); h.force_reannounce(); - return true; - }else{ - return false; } } -void bittorrent::saveTrackerFile(QString hash) { - qDebug("Saving tracker file for %s", hash.toLocal8Bit().data()); - QDir torrentBackup(misc::qBittorrentPath() + "BT_backup"); - QFile tracker_file(torrentBackup.path()+QDir::separator()+ hash + ".trackers"); - if(tracker_file.exists()) { - tracker_file.remove(); - } - tracker_file.open(QIODevice::WriteOnly | QIODevice::Text); - QTorrentHandle h = getTorrentHandle(hash); - std::vector trackers = h.trackers(); - for(unsigned int i=0; i= 1000 or 0 if same as BT) void bittorrent::setDHTPort(int dht_port) { if(dht_port == 0 or dht_port >= 1000) { @@ -1149,10 +1112,8 @@ void bittorrent::readAlerts() { if(h.is_valid()){ emit finishedTorrent(h); QString hash = h.hash(); - // Create .finished file if necessary - QFile finished_file(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".finished"); - finished_file.open(QIODevice::WriteOnly | QIODevice::Text); - finished_file.close(); + // Remember finished state + TorrentPersistentData::saveSeedStatus(h); // Move to download directory if necessary if(!defaultTempPath.isEmpty()) { // Check if directory is different @@ -1167,19 +1128,19 @@ void bittorrent::readAlerts() { } } else if (save_resume_data_alert* p = dynamic_cast(a.get())) { - QDir torrentBackup(misc::qBittorrentPath() + "BT_backup"); - QTorrentHandle h(p->handle); - QString file = h.hash()+".fastresume"; - // Delete old fastresume file if necessary - if(QFile::exists(file)) - QFile::remove(file); - qDebug("Saving fastresume data in %s", file.toLocal8Bit().data()); - if (p->resume_data) - { - boost::filesystem::ofstream out(fs::path(torrentBackup.path().toLocal8Bit().data()) / file.toLocal8Bit().data(), std::ios_base::binary); - out.unsetf(std::ios_base::skipws); - bencode(std::ostream_iterator(out), *p->resume_data); - } + QDir torrentBackup(misc::qBittorrentPath() + "BT_backup"); + QTorrentHandle h(p->handle); + QString file = h.hash()+".fastresume"; + // Delete old fastresume file if necessary + if(QFile::exists(file)) + QFile::remove(file); + qDebug("Saving fastresume data in %s", file.toLocal8Bit().data()); + if (p->resume_data) + { + boost::filesystem::ofstream out(fs::path(torrentBackup.path().toLocal8Bit().data()) / file.toLocal8Bit().data(), std::ios_base::binary); + out.unsetf(std::ios_base::skipws); + bencode(std::ostream_iterator(out), *p->resume_data); + } } else if (file_error_alert* p = dynamic_cast(a.get())) { QTorrentHandle h(p->handle); @@ -1284,17 +1245,17 @@ session_status bittorrent::getSessionStatus() const{ } QString bittorrent::getSavePath(QString hash) { - QFile savepath_file(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".savepath"); - QByteArray line; QString savePath; - if(savepath_file.open(QIODevice::ReadOnly | QIODevice::Text)) { - line = savepath_file.readAll(); - savepath_file.close(); - qDebug(" -> Save path: %s", line.data()); - savePath = QString::fromUtf8(line.data()); - }else{ - // use default save path - qDebug("Using default save path because none was set"); + if(TorrentTempData::hasTempData(hash)) { + savePath = TorrentTempData::getSavePath(hash); + qDebug("getSavePath, got save_path from temp data: %s", savePath.toUtf8().data()); + } else { + savePath = TorrentPersistentData::getSavePath(hash); + qDebug("getSavePath, got save_path from persistent data: %s", savePath.toUtf8().data()); + } + if(savePath.isEmpty()) { + // use default save path if no other can be found + qDebug("Using default save path because none was set: %s", defaultSavePath.toUtf8().data()); savePath = defaultSavePath; } // Checking if savePath Dir exists @@ -1383,58 +1344,39 @@ void bittorrent::applyEncryptionSettings(pe_settings se) { s->set_pe_settings(se); } -void bittorrent::saveTorrentPriority(QString hash, int prio) { - // Write .queued file - QFile prio_file(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".prio"); - prio_file.open(QIODevice::WriteOnly | QIODevice::Text); - prio_file.write(QByteArray::number(prio)); - prio_file.close(); -} - // Will fast resume torrents in // backup directory -void bittorrent::resumeUnfinishedTorrents() { +void bittorrent::startUpTorrents() { qDebug("Resuming unfinished torrents"); QDir torrentBackup(misc::qBittorrentPath() + "BT_backup"); QStringList fileNames; - // Scan torrentBackup directory - QStringList filters; - filters << "*.torrent"; - fileNames = torrentBackup.entryList(filters, QDir::Files, QDir::Unsorted); + QStringList known_torrents = TorrentPersistentData::knownTorrents(); if(isQueueingEnabled()) { - QList > filePaths; - foreach(const QString &fileName, fileNames) { - QString filePath = torrentBackup.path()+QDir::separator()+fileName; - int prio = 99999; - // Get priority - QString prioPath = filePath; - prioPath.replace(".torrent", ".prio"); - if(QFile::exists(prioPath)) { - QFile prio_file(prioPath); - if(prio_file.open(QIODevice::ReadOnly | QIODevice::Text)) { - bool ok = false; - prio = prio_file.readAll().toInt(&ok); - if(!ok) - prio = 99999; - prio_file.close(); - } - } - misc::insertSort2(filePaths, qMakePair(prio, filePath)); - } - // Resume downloads - QPair fileName; - foreach(fileName, filePaths) { - addTorrent(fileName.second, false, QString(), true); + QList > filePaths; + foreach(const QString &hash, known_torrents) { + QString filePath; + if(TorrentPersistentData::isMagnet(hash)) { + filePath = TorrentPersistentData::getMagnetUri(hash); + } else { + filePath = torrentBackup.path()+QDir::separator()+hash+".torrent"; } - } else { - QStringList filePaths; - foreach(const QString &fileName, fileNames) { - filePaths.append(torrentBackup.path()+QDir::separator()+fileName); - } - // Resume downloads - foreach(const QString &fileName, filePaths) { - addTorrent(fileName, false, QString(), true); - } + int prio = TorrentPersistentData::getPriority(hash); + misc::insertSort2(filePaths, qMakePair(prio, filePath)); } + // Resume downloads + QPair fileName; + foreach(fileName, filePaths) { + addTorrent(fileName.second, false, QString(), true); + } + } else { + QStringList filePaths; + foreach(const QString &fileName, fileNames) { + filePaths.append(torrentBackup.path()+QDir::separator()+fileName); + } + // Resume downloads + foreach(const QString &fileName, filePaths) { + addTorrent(fileName, false, QString(), true); + } + } qDebug("Unfinished torrents resumed"); } diff --git a/src/bittorrent.h b/src/bittorrent.h index 2755affbe..e864ebab6 100644 --- a/src/bittorrent.h +++ b/src/bittorrent.h @@ -107,6 +107,7 @@ class bittorrent : public QObject { QStringList getConsoleMessages() const; QStringList getPeerBanMessages() const; qlonglong getETA(QString hash) const; + bool useTemporaryFolder() const; public slots: QTorrentHandle addTorrent(QString path, bool fromScanDir = false, QString from_url = QString(), bool resumed = false); @@ -115,11 +116,12 @@ class bittorrent : public QObject { void downloadFromUrl(QString url); void downloadFromURLList(const QStringList& url_list); void deleteTorrent(QString hash, bool permanent = false); + void startUpTorrents(); /* Needed by Web UI */ void pauseAllTorrents(); - void resumeAllTorrents(); void pauseTorrent(QString hash); void resumeTorrent(QString hash); + void resumeAllTorrents(); /* End Web UI */ void saveDHTEntry(); void preAllocateAllFiles(bool b); @@ -129,8 +131,6 @@ class bittorrent : public QObject { void enableIPFilter(QString filter); void disableIPFilter(); void setQueueingEnabled(bool enable); - void resumeUnfinishedTorrents(); - void saveTorrentPriority(QString hash, int prio); void saveTorrentSpeedLimits(QString hash); void loadTorrentSpeedLimits(QString hash); void handleDownloadFailure(QString url, QString reason); @@ -164,12 +164,12 @@ class bittorrent : public QObject { void addConsoleMessage(QString msg, QColor color=QApplication::palette().color(QPalette::WindowText)); void addPeerBanMessage(QString msg, bool from_ipfilter); void processDownloadedFile(QString, QString); + void saveTrackerFile(QString hash); protected slots: void scanDirectory(QString); void readAlerts(); - bool loadTrackerFile(QString hash); - void saveTrackerFile(QString hash); + void loadTrackerFile(QString hash); void deleteBigRatios(); signals: diff --git a/src/properties_imp.cpp b/src/properties_imp.cpp index 2d3355c6d..fb6e0ea6d 100644 --- a/src/properties_imp.cpp +++ b/src/properties_imp.cpp @@ -36,6 +36,7 @@ #include "realprogressbar.h" #include "realprogressbarthread.h" #include "TrackersAdditionDlg.h" +#include "torrentPersistentData.h" #include #include @@ -86,7 +87,7 @@ properties::properties(QWidget *parent, bittorrent *BTSession, QTorrentHandle &h // get Infos from torrent handle fileName->setText(h.name()); // Torrent Infos - save_path->setText(h.save_path()); + save_path->setText(TorrentPersistentData::getSavePath(hash)); QString author = h.creator().trimmed(); if(author.isEmpty()) author = tr("Unknown"); @@ -115,23 +116,18 @@ properties::properties(QWidget *parent, bittorrent *BTSession, QTorrentHandle &h shareRatio->setText(QString(QByteArray::number(ratio, 'f', 1))); std::vector fp; h.file_progress(fp); - int *prioritiesTab = loadPiecesPriorities(); + std::vector files_priority = loadFilesPriorities(); // List files in torrent - arborescence *arb = new arborescence(h.get_torrent_info(), fp, prioritiesTab); + arborescence *arb = new arborescence(h.get_torrent_info(), fp, files_priority); addFilesToTree(arb->getRoot(), PropListModel->invisibleRootItem()); delete arb; - delete prioritiesTab; connect(PropListModel, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(updatePriorities(QStandardItem*))); filesList->expandAll(); // List web seeds loadWebSeedsFromFile(); loadWebSeeds(); // Incremental download - if(QFile::exists(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".incremental")){ - incrementalDownload->setChecked(true); - }else{ - incrementalDownload->setChecked(false); - } + incrementalDownload->setChecked(TorrentPersistentData::isSequentialDownload(hash)); updateInfosTimer = new QTimer(this); connect(updateInfosTimer, SIGNAL(timeout()), this, SLOT(updateInfos())); updateInfosTimer->start(3000); @@ -314,41 +310,19 @@ void properties::loadWebSeeds(){ } } -int* properties::loadPiecesPriorities(){ - unsigned int nbFiles = h.num_files(); - int *prioritiesTab = new int[nbFiles]; - QString fileName = h.name(); - QFile pieces_file(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".priorities"); - has_filtered_files = false; - qDebug("Loading pieces priorities"); - // Read saved file - if(!pieces_file.open(QIODevice::ReadOnly | QIODevice::Text)){ - qDebug("Could not find pieces file"); - for(unsigned int i=0; i pieces_priority_list = pieces_text.split('\n'); - if((unsigned int)pieces_priority_list.size() != nbFiles+1){ - std::cerr << "Error: Corrupted pieces file\n"; - for(unsigned int i=0; i properties::loadFilesPriorities(){ + std::vector fp; + QVariantList files_priority = TorrentPersistentData::getFilesPriority(hash); + foreach(const QVariant &var_prio, files_priority) { + int priority = var_prio.toInt(); if( priority < 0 || priority > 7){ // Normal priority as default priority = 1; } - if(!priority){ - has_filtered_files = true; - } - prioritiesTab[i] = priority; + fp.push_back(priority); } - return prioritiesTab; + + return fp; } bool properties::allFiltered() const { @@ -494,7 +468,7 @@ void properties::askWebSeed(){ } urlSeeds << url_seed; h.add_url_seed(url_seed); - saveWebSeeds(); + TorrentPersistentData::saveUrlSeeds(h); // Refresh the seeds list loadWebSeeds(); } @@ -536,7 +510,7 @@ void properties::deleteSelectedUrlSeeds(){ } if(change){ // Save them to disk - saveWebSeeds(); + TorrentPersistentData::saveUrlSeeds(h); // Refresh list loadWebSeeds(); } @@ -672,19 +646,16 @@ void properties::setAllPiecesState(unsigned short priority){ } } -void properties::on_incrementalDownload_stateChanged(int){ +void properties::on_incrementalDownload_stateChanged(int state){ qDebug("Incremental download toggled"); - if(incrementalDownload->isChecked()){ - if(!QFile::exists(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".incremental"))) { - // Create .incremental file - QFile incremental_file(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".incremental")); - incremental_file.open(QIODevice::WriteOnly | QIODevice::Text); - incremental_file.close(); + if(state == Qt::Checked){ + if(!TorrentPersistentData::isSequentialDownload(hash)) { h.set_sequential_download(true); + TorrentPersistentData::saveSequentialStatus(h); } }else{ - QFile::remove(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".incremental"); h.set_sequential_download(false); + TorrentPersistentData::saveSequentialStatus(h); } } @@ -706,12 +677,10 @@ void properties::on_changeSavePathButton_clicked() { } } // Save savepath - QFile savepath_file(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".savepath")); - savepath_file.open(QIODevice::WriteOnly | QIODevice::Text); - savepath_file.write(savePath.path().toLocal8Bit()); - savepath_file.close(); + TorrentPersistentData::saveSavePath(hash, savePath.path()); // Actually move storage - h.move_storage(savePath.path()); + if(!BTSession->useTemporaryFolder() || h.is_seed()) + h.move_storage(savePath.path()); // Update save_path in dialog save_path->setText(savePath.path()); } @@ -723,13 +692,10 @@ void properties::on_okButton_clicked(){ } void properties::loadWebSeedsFromFile(){ - QFile urlseeds_file(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".urlseeds"); - if(!urlseeds_file.open(QIODevice::ReadOnly | QIODevice::Text)) return; - QByteArray urlseeds_lines = urlseeds_file.readAll(); - urlseeds_file.close(); - QList url_seeds = urlseeds_lines.split('\n'); urlSeeds.clear(); - foreach(const QByteArray &url_seed, url_seeds){ + QVariantList url_seeds = TorrentPersistentData::getUrlSeeds(hash); + foreach(const QVariant &var_url_seed, url_seeds){ + QString url_seed = var_url_seed.toString(); if(!url_seed.isEmpty()) urlSeeds << url_seed; } @@ -743,19 +709,6 @@ void properties::loadWebSeedsFromFile(){ } } -void properties::saveWebSeeds(){ - QFile urlseeds_file(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".urlseeds")); - if(!urlseeds_file.open(QIODevice::WriteOnly | QIODevice::Text)){ - std::cerr << "Error: Could not save url seeds\n"; - return; - } - foreach(const QString &url_seed, urlSeeds){ - urlseeds_file.write((url_seed+"\n").toLocal8Bit()); - } - urlseeds_file.close(); - qDebug("url seeds were saved"); -} - bool properties::savePiecesPriorities() { if(!changedFilteredfiles) return true; if(allFiltered()) { @@ -763,30 +716,15 @@ bool properties::savePiecesPriorities() { return false; } qDebug("Saving pieces priorities"); - bool hasFilteredFiles = false; - QString fileName = h.name(); - QFile pieces_file(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".priorities")); - // First, remove old file - pieces_file.remove(); int *priorities = new int[h.get_torrent_info().num_files()]; getPriorities(PropListModel->invisibleRootItem(), priorities); - // Ok, we have priorities, save them - if(!pieces_file.open(QIODevice::WriteOnly | QIODevice::Text)){ - std::cerr << "Error: Could not save pieces priorities\n"; - return true; - } unsigned int nbFiles = h.get_torrent_info().num_files(); for(unsigned int i=0; iloadFilesPriorities(h); + TorrentPersistentData::saveFilesPriority(h); // Emit a signal so that the GUI updates the size emit filteredFilesChanged(hash); - has_filtered_files = hasFilteredFiles; return true; } diff --git a/src/properties_imp.h b/src/properties_imp.h index 4f1af055e..0fec185f3 100644 --- a/src/properties_imp.h +++ b/src/properties_imp.h @@ -55,7 +55,6 @@ class properties : public QDialog, private Ui::properties{ PropListDelegate *PropDelegate; QStandardItemModel *PropListModel; QTimer *updateInfosTimer; - bool has_filtered_files; QStringList urlSeeds; RealProgressBar *progressBar; RealProgressBarThread *progressBarUpdater; @@ -79,7 +78,6 @@ class properties : public QDialog, private Ui::properties{ void maximumSelection(); void loadWebSeeds(); void askWebSeed(); - void saveWebSeeds(); void loadWebSeedsFromFile(); void deleteSelectedUrlSeeds(); void addFilesToTree(const torrent_file *root, QStandardItem *parent); @@ -103,7 +101,7 @@ class properties : public QDialog, private Ui::properties{ ~properties(); bool allFiltered() const; bool savePiecesPriorities(); - int* loadPiecesPriorities(); + std::vector loadFilesPriorities(); protected: QPoint screenCenter() const; diff --git a/src/qtorrenthandle.cpp b/src/qtorrenthandle.cpp index 4c234b3e4..f69c5610b 100644 --- a/src/qtorrenthandle.cpp +++ b/src/qtorrenthandle.cpp @@ -241,6 +241,11 @@ torrent_status::state_t QTorrentHandle::state() const { return h.status().state; } +std::vector QTorrentHandle::file_priorities() const { + Q_ASSERT(h.is_valid()); + return h.file_priorities(); +} + QString QTorrentHandle::creator() const { Q_ASSERT(h.is_valid()); return misc::toQString(h.get_torrent_info().creator()); @@ -325,6 +330,11 @@ int QTorrentHandle::active_time() const { return h.status().active_time; } +bool QTorrentHandle::is_sequential_download() const { + Q_ASSERT(h.is_valid()); + return h.is_sequential_download(); +} + // // Setters // @@ -428,6 +438,11 @@ void QTorrentHandle::move_storage(QString new_path) const { h.move_storage(new_path.toLocal8Bit().data()); } +void QTorrentHandle::file_priority(int index, int priority) const { + Q_ASSERT(h.is_valid()); + h.file_priority(index, priority); +} + // // Operators // diff --git a/src/qtorrenthandle.h b/src/qtorrenthandle.h index c73ca75eb..4e2928ab0 100644 --- a/src/qtorrenthandle.h +++ b/src/qtorrenthandle.h @@ -108,6 +108,8 @@ class QTorrentHandle { bool is_seed() const; bool is_auto_managed() const; int active_time() const; + std::vector file_priorities() const; + bool is_sequential_download() const; // // Setters @@ -122,6 +124,7 @@ class QTorrentHandle { void set_max_uploads(int val); void set_max_connections(int val); void prioritize_files(std::vector v); + void file_priority(int index, int priority) const; void set_ratio(float ratio) const; void replace_trackers(std::vector const&) const; void force_reannounce(); diff --git a/src/torrentAddition.h b/src/torrentAddition.h index 707c8acfa..d98fbaad2 100644 --- a/src/torrentAddition.h +++ b/src/torrentAddition.h @@ -48,6 +48,7 @@ #include "PropListDelegate.h" #include "ui_addTorrentDialog.h" #include "arborescence.h" +#include "torrentPersistentData.h" using namespace libtorrent; @@ -371,22 +372,14 @@ class torrentAdditionDialog : public QDialog, private Ui_addTorrentDialog{ void savePiecesPriorities(){ qDebug("Saving pieces priorities"); - QFile pieces_file(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".priorities")); - // First, remove old file - pieces_file.remove(); int *priorities = new int[nbFiles]; getPriorities(PropListModel->invisibleRootItem(), priorities); - // Ok, we have priorities, save them - if(!pieces_file.open(QIODevice::WriteOnly | QIODevice::Text)){ - std::cerr << "Error: Could not save pieces priorities\n"; - return; - } + std::vector vect_prio; for(unsigned int i=0; itext()); // Create .incremental file if necessary - if(checkIncrementalDL->isChecked()){ - QFile incremental_file(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".incremental")); - incremental_file.open(QIODevice::WriteOnly | QIODevice::Text); - incremental_file.close(); - }else{ - QFile::remove(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".incremental")); - } + TorrentTempData::setSequential(hash, checkIncrementalDL->isChecked()); // Check if there is at least one selected file if(allFiltered()){ QMessageBox::warning(0, tr("Invalid file selection"), tr("You must select at least one file in the torrent")); diff --git a/src/torrentPersistentData.h b/src/torrentPersistentData.h new file mode 100644 index 000000000..b00540bf1 --- /dev/null +++ b/src/torrentPersistentData.h @@ -0,0 +1,339 @@ +/* + * 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 + */ + +#ifndef TORRENTPERSISTENTDATA_H +#define TORRENTPERSISTENTDATA_H + +#include +#include +#include +#include + +#include "qtorrenthandle.h" +#include "misc.h" + +class TorrentTempData { +public: + static bool hasTempData(QString hash) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents-tmp", QHash()).toHash(); + return all_data.contains(hash); + } + + static void deleteTempData(QString hash) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents-tmp", QHash()).toHash(); + if(all_data.contains(hash)) { + all_data.remove(hash); + settings.setValue("torrents-tmp", all_data); + } + } + + static void setFilesPriority(QString hash, std::vector pp) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents-tmp", QHash()).toHash(); + QHash data = all_data[hash].toHash(); + std::vector::iterator pp_it = pp.begin(); + QVariantList pieces_priority; + while(pp_it != pp.end()) { + pieces_priority << *pp_it; + pp_it++; + } + data["files_priority"] = pieces_priority; + all_data[hash] = data; + settings.setValue("torrents-tmp", all_data); + } + + static void setSavePath(QString hash, QString save_path) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents-tmp", QHash()).toHash(); + QHash data = all_data[hash].toHash(); + data["save_path"] = save_path; + all_data[hash] = data; + settings.setValue("torrents-tmp", all_data); + } + + static void setSequential(QString hash, bool sequential) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents-tmp", QHash()).toHash(); + QHash data = all_data[hash].toHash(); + data["sequential"] = sequential; + all_data[hash] = data; + settings.setValue("torrents-tmp", all_data); + } + + static bool isSequential(QString hash) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents-tmp", QHash()).toHash(); + QHash data = all_data[hash].toHash(); + if(data.contains("sequential")) + return data["sequential"].toBool(); + return false; + + } + + static QString getSavePath(QString hash) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents-tmp", QHash()).toHash(); + QHash data = all_data[hash].toHash(); + if(data.contains("save_path")) + return data["save_path"].toString(); + qDebug("Warning Temp::getSavePath returns null string!"); + return QString::null; + } + + static QVariantList getFilesPriority(QString hash) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents-tmp", QHash()).toHash(); + QHash data = all_data[hash].toHash(); + if(data.contains("files_priority")) + return data["files_priority"].toList(); + return QVariantList(); + } +}; + +class TorrentPersistentData { +public: + + static bool isKnownTorrent(QString hash) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents", QHash()).toHash(); + return all_data.contains(hash); + } + + static QStringList knownTorrents() { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents", QHash()).toHash(); + return all_data.keys(); + } + + static void deletePersistentData(QString hash) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents", QHash()).toHash(); + if(all_data.contains(hash)) { + all_data.remove(hash); + settings.setValue("torrents", all_data); + } + } + + static void saveTorrentPersistentData(QTorrentHandle h, bool is_magnet = false) { + // First, remove temp data + TorrentTempData::deleteTempData(h.hash()); + Q_ASSERT(!TorrentTempData::hasTempData(h.hash())); + // Save persistent data + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents", QHash()).toHash(); + QHash data; + data["hash"] = h.hash(); + data["is_magnet"] = is_magnet; + if(is_magnet) { + data["magnet_uri"] = misc::toQString(make_magnet_uri(h.get_torrent_handle())); + } + data["seed"] = h.is_seed(); + data["priority"] = h.queue_position(); + QVariantList files_priority; + std::vector fp = h.file_priorities(); + std::vector::iterator fp_it = fp.begin(); + while(fp_it != fp.end()) { + files_priority << *fp_it; + fp_it++; + } + data["files_priority"] = files_priority; + data["save_path"] = h.save_path(); + QHash trackers; + std::vector tr = h.trackers(); + std::vector::iterator tr_it = tr.begin(); + while(tr_it != tr.end()) { + trackers[misc::toQString((*tr_it).url)] = (*tr_it).tier; + tr_it++; + } + data["trackers"] = trackers; + QVariantList url_seeds; + foreach(QString url_seed, h.url_seeds()) { + url_seeds << url_seed; + } + data["url_seeds"] = url_seeds; + data["sequential"] = h.is_sequential_download(); + // Save data + all_data[h.hash()] = data; + settings.setValue("torrents", all_data); + } + + static void saveTrackers(QTorrentHandle h) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents", QHash()).toHash(); + QHash data = all_data[h.hash()].toHash(); + QVariantList trackers; + std::vector tr = h.trackers(); + std::vector::iterator tr_it = tr.begin(); + while(tr_it != tr.end()) { + trackers << misc::toQString((*tr_it).url); + tr_it++; + } + data["trackers"] = trackers; + // Save data + all_data[h.hash()] = data; + settings.setValue("torrents", all_data); + } + + // Setters + + static void saveFilesPriority(QTorrentHandle h) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents", QHash()).toHash(); + QHash data = all_data[h.hash()].toHash(); + std::vector fp = h.file_priorities(); + std::vector::iterator fp_it = fp.begin(); + QVariantList files_priority; + while(fp_it != fp.end()) { + files_priority << *fp_it; + fp_it++; + } + data["files_priority"] = files_priority; + all_data[h.hash()] = data; + settings.setValue("torrents", all_data); + } + + static void saveSavePath(QString hash, QString save_path) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents", QHash()).toHash(); + QHash data = all_data[hash].toHash(); + data["save_path"] = save_path; + all_data[hash] = data; + settings.setValue("torrents", all_data); + } + + static void saveUrlSeeds(QTorrentHandle h) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents", QHash()).toHash(); + QHash data = all_data[h.hash()].toHash(); + QVariantList url_seeds; + foreach(QString url_seed, h.url_seeds()) { + url_seeds << url_seed; + } + data["url_seeds"] = url_seeds; + all_data[h.hash()] = data; + settings.setValue("torrents", all_data); + } + + static void savePriority(QTorrentHandle h) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents", QHash()).toHash(); + QHash data = all_data[h.hash()].toHash(); + data["priority"] = h.queue_position(); + all_data[h.hash()] = data; + settings.setValue("torrents", all_data); + } + + static void saveSeedStatus(QTorrentHandle h) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents", QHash()).toHash(); + QHash data = all_data[h.hash()].toHash(); + data["seed"] = h.is_seed(); + all_data[h.hash()] = data; + settings.setValue("torrents", all_data); + } + + static void saveSequentialStatus(QTorrentHandle h) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents", QHash()).toHash(); + QHash data = all_data[h.hash()].toHash(); + data["sequential"] = h.is_sequential_download(); + all_data[h.hash()] = data; + settings.setValue("torrents", all_data); + } + + // Getters + static QHash getTrackers(QString hash) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents", QHash()).toHash(); + QHash data = all_data[hash].toHash(); + return data["trackers"].toHash(); + } + + static QVariantList getFilesPriority(QString hash) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents", QHash()).toHash(); + QHash data = all_data[hash].toHash(); + return data["files_priority"].toList(); + } + + static QString getSavePath(QString hash) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents", QHash()).toHash(); + QHash data = all_data[hash].toHash(); + return data["save_path"].toString(); + } + + static int getPriority(QString hash) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents", QHash()).toHash(); + QHash data = all_data[hash].toHash(); + return data["priority"].toInt(); + } + + static QVariantList getUrlSeeds(QString hash) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents", QHash()).toHash(); + QHash data = all_data[hash].toHash(); + return data["url_seeds"].toList(); + } + + static bool isSeed(QString hash) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents", QHash()).toHash(); + QHash data = all_data[hash].toHash(); + return data["seed"].toBool(); + } + + static bool isMagnet(QString hash) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents", QHash()).toHash(); + QHash data = all_data[hash].toHash(); + return data["is_magnet"].toBool(); + } + + static QString getMagnetUri(QString hash) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents", QHash()).toHash(); + QHash data = all_data[hash].toHash(); + Q_ASSERT(data["is_magnet"].toBool()); + return data["magnet_uri"].toString(); + } + + static bool isSequentialDownload(QString hash) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents", QHash()).toHash(); + QHash data = all_data[hash].toHash(); + return data["sequential"].toBool(); + } + +}; +#endif // TORRENTPERSISTENTDATA_H