From d6e90883cb1cd51d6bd796c51da34db2ac12d3bb Mon Sep 17 00:00:00 2001 From: Christophe Dumez Date: Sat, 7 Nov 2009 19:55:33 +0000 Subject: [PATCH] - Initial commit (both lists are merged but not all the features are there and it is probably buggy) --- src/GUI.cpp | 535 ++++------------------------------- src/GUI.h | 37 +-- src/TransferListDelegate.h | 121 ++++++++ src/TransferListWidget.cpp | 537 ++++++++++++++++++++++++++++++++++++ src/TransferListWidget.h | 95 +++++++ src/bittorrent.cpp | 25 +- src/bittorrent.h | 3 +- src/downloadingTorrents.cpp | 10 +- src/downloadingTorrents.h | 1 - src/src.pro | 7 +- 10 files changed, 821 insertions(+), 550 deletions(-) create mode 100644 src/TransferListDelegate.h create mode 100644 src/TransferListWidget.cpp create mode 100644 src/TransferListWidget.h diff --git a/src/GUI.cpp b/src/GUI.cpp index 62f98af5c..c23a89462 100644 --- a/src/GUI.cpp +++ b/src/GUI.cpp @@ -46,19 +46,17 @@ #include #include "GUI.h" -#include "downloadingTorrents.h" +#include "TransferListWidget.h" #include "misc.h" #include "createtorrent_imp.h" #include "downloadFromURLImp.h" #include "torrentAddition.h" #include "searchEngine.h" #include "rss_imp.h" -#include "FinishedTorrents.h" #include "bittorrent.h" #include "about_imp.h" #include "trackerLogin.h" #include "options_imp.h" -#include "previewSelect.h" #include "allocationDlg.h" #include #include "console_imp.h" @@ -74,7 +72,7 @@ using namespace libtorrent; *****************************************************/ // Constructor -GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), displaySpeedInTitle(false), force_exit(false), refreshInterval(1500) { +GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), displaySpeedInTitle(false), force_exit(false) { setupUi(this); setWindowTitle(tr("qBittorrent %1", "e.g: qBittorrent v0.x").arg(QString::fromUtf8(VERSION))); QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); @@ -131,47 +129,45 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), dis BTSession = new bittorrent(); connect(BTSession, SIGNAL(fullDiskError(QTorrentHandle&, QString)), this, SLOT(fullDiskError(QTorrentHandle&, QString))); connect(BTSession, SIGNAL(finishedTorrent(QTorrentHandle&)), this, SLOT(finishedTorrent(QTorrentHandle&))); - connect(BTSession, SIGNAL(addedTorrent(QTorrentHandle&)), this, SLOT(addedTorrent(QTorrentHandle&))); - connect(BTSession, SIGNAL(pausedTorrent(QTorrentHandle&)), this, SLOT(pausedTorrent(QTorrentHandle&))); - connect(BTSession, SIGNAL(resumedTorrent(QTorrentHandle&)), this, SLOT(resumedTorrent(QTorrentHandle&))); - connect(BTSession, SIGNAL(torrentFinishedChecking(QTorrentHandle&)), this, SLOT(checkedTorrent(QTorrentHandle&))); connect(BTSession, SIGNAL(trackerAuthenticationRequired(QTorrentHandle&)), this, SLOT(trackerAuthenticationRequired(QTorrentHandle&))); connect(BTSession, SIGNAL(newDownloadedTorrent(QString, QString)), this, SLOT(processDownloadedFiles(QString, QString))); connect(BTSession, SIGNAL(downloadFromUrlFailure(QString, QString)), this, SLOT(handleDownloadFromUrlFailure(QString, QString))); - connect(BTSession, SIGNAL(deletedTorrent(QString)), this, SLOT(deleteTorrent(QString))); - connect(BTSession, SIGNAL(torrentPaused(QTorrentHandle&)), this, SLOT(setPaused(QTorrentHandle&))); + qDebug("create tabWidget"); tabs = new QTabWidget(); - // Download torrents tab - downloadingTorrentTab = new DownloadingTorrents(this, BTSession); - tabs->addTab(downloadingTorrentTab, tr("Downloads") + QString::fromUtf8(" (0/0)")); - tabs->setTabIcon(0, QIcon(QString::fromUtf8(":/Icons/skin/downloading.png"))); + // Transfer List tab + transferList = new TransferListWidget(tabs, BTSession); + int index_tab = tabs->addTab(transferList, tr("Transfers")); + tabs->setTabIcon(index_tab, QIcon(QString::fromUtf8(":/Icons/skin/downloading.png"))); vboxLayout->addWidget(tabs); - connect(downloadingTorrentTab, SIGNAL(unfinishedTorrentsNumberChanged(unsigned int)), this, SLOT(updateUnfinishedTorrentNumber(unsigned int))); - connect(downloadingTorrentTab, SIGNAL(torrentDoubleClicked(QString, bool)), this, SLOT(torrentDoubleClicked(QString, bool))); - // Finished torrents tab - finishedTorrentTab = new FinishedTorrents(this, BTSession); - tabs->addTab(finishedTorrentTab, tr("Uploads") + QString::fromUtf8(" (0/0)")); - tabs->setTabIcon(1, QIcon(QString::fromUtf8(":/Icons/skin/seeding.png"))); - connect(finishedTorrentTab, SIGNAL(torrentDoubleClicked(QString, bool)), this, SLOT(torrentDoubleClicked(QString, bool))); - connect(finishedTorrentTab, SIGNAL(finishedTorrentsNumberChanged(unsigned int)), this, SLOT(updateFinishedTorrentNumber(unsigned int))); + + // Transfer list slots + connect(actionStart, SIGNAL(triggered()), transferList, SLOT(startSelectedTorrents())); + connect(actionStart_All, SIGNAL(triggered()), transferList, SLOT(startAllTorrents())); + connect(actionPause, SIGNAL(triggered()), transferList, SLOT(pauseSelectedTorrents())); + connect(actionPause_All, SIGNAL(triggered()), transferList, SLOT(pauseAllTorrents())); + connect(actionDelete, SIGNAL(triggered()), transferList, SLOT(deleteSelectedTorrents())); + connect(actionDelete_Permanently, SIGNAL(triggered()), transferList, SLOT(deletePermSelectedTorrents())); + connect(actionIncreasePriority, SIGNAL(triggered()), transferList, SLOT(increasePrioSelectedTorrents())); + connect(actionDecreasePriority, SIGNAL(triggered()), transferList, SLOT(decreasePrioSelectedTorrents())); + + //connect(downloadingTorrentTab, SIGNAL(unfinishedTorrentsNumberChanged(unsigned int)), this, SLOT(updateUnfinishedTorrentNumber(unsigned int))); + //connect(downloadingTorrentTab, SIGNAL(torrentDoubleClicked(QString, bool)), this, SLOT(torrentDoubleClicked(QString, bool))); // Search engine tab searchEngine = new SearchEngine(BTSession, myTrayIcon, systrayIntegration); - tabs->addTab(searchEngine, tr("Search")); - tabs->setTabIcon(2, QIcon(QString::fromUtf8(":/Icons/oxygen/edit-find.png"))); + index_tab = tabs->addTab(searchEngine, tr("Search")); + tabs->setTabIcon(index_tab, QIcon(QString::fromUtf8(":/Icons/oxygen/edit-find.png"))); readSettings(); // RSS Tab rssWidget = 0; - // Start download list refresher - refresher = new QTimer(this); - connect(refresher, SIGNAL(timeout()), this, SLOT(updateLists())); - refresher->start(1500); + // Configure BT session according to options configureSession(true); // Resume unfinished torrents BTSession->startUpTorrents(); - downloadingTorrentTab->loadLastSortedColumn(); - finishedTorrentTab->loadLastSortedColumn(); + // FIXME: Sorting + //downloadingTorrentTab->loadLastSortedColumn(); + //finishedTorrentTab->loadLastSortedColumn(); // Add torrent given on command line processParams(torrentCmdLine); // Initialize Web UI @@ -264,9 +260,7 @@ GUI::~GUI() { if(rssWidget != 0) delete rssWidget; delete searchEngine; - delete refresher; - delete downloadingTorrentTab; - delete finishedTorrentTab; + delete transferList; delete checkConnect; qDebug("1"); if(systrayCreator) { @@ -301,8 +295,8 @@ void GUI::displayRSSTab(bool enable) { // RSS tab if(rssWidget == 0) { rssWidget = new RSSImp(BTSession); - tabs->addTab(rssWidget, tr("RSS")); - tabs->setTabIcon(3, QIcon(QString::fromUtf8(":/Icons/rss32.png"))); + int index_tab = tabs->addTab(rssWidget, tr("RSS")); + tabs->setTabIcon(index_tab, QIcon(QString::fromUtf8(":/Icons/rss32.png"))); } } else { if(rssWidget != 0) { @@ -363,92 +357,22 @@ void GUI::writeSettings() { // 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 { - if(h.is_seed()) { - finishedTorrentTab->addTorrent(h.hash()); - } else { - downloadingTorrentTab->addTorrent(h.hash()); - } -} - -void GUI::pausedTorrent(QTorrentHandle& h) const { - if(h.is_seed()) { - finishedTorrentTab->pauseTorrent(h.hash()); - } else { - downloadingTorrentTab->pauseTorrent(h.hash()); - } -} - -void GUI::resumedTorrent(QTorrentHandle& h) const { - if(h.is_seed()) { - finishedTorrentTab->updateTorrent(h); - } else { - downloadingTorrentTab->updateTorrent(h); - } -} - -void GUI::checkedTorrent(QTorrentHandle& h) const { - if(h.is_seed()) { - // Move torrent to finished tab - downloadingTorrentTab->deleteTorrent(h.hash()); - finishedTorrentTab->addTorrent(h.hash()); - } else { - // Move torrent back to download list (if necessary) - if(TorrentPersistentData::isSeed(h.hash())) { - TorrentPersistentData::saveSeedStatus(h); - finishedTorrentTab->deleteTorrent(h.hash()); - downloadingTorrentTab->addTorrent(h.hash()); - } - } + if(!TorrentPersistentData::isSeed(h.hash())) + showNotificationBaloon(tr("Download completion"), tr("%1 has finished downloading.", "e.g: xxx.avi has finished downloading.").arg(h.name())); } // 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); - } + if(!h.is_valid()) return; + showNotificationBaloon(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)); // Download will be paused by libtorrent. Updating GUI information accordingly QString hash = h.hash(); qDebug("Full disk error, pausing torrent %s", hash.toLocal8Bit().data()); - setPaused(h); + h.pause(); + transferList->pauseTorrent(h.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::setPaused(QTorrentHandle &h) const { - if(!h.is_paused()) { - // FIXME in v1.6.0: Add Error state and stop using pause for this - h.pause(); - } - qDebug("Marking torrent %s as paused", h.hash().toLocal8Bit().data()); - if(h.is_seed()) { - // In finished list - qDebug("Automatically paused torrent was in finished list"); - finishedTorrentTab->pauseTorrent(h.hash()); - }else{ - downloadingTorrentTab->pauseTorrent(h.hash()); - } -} - void GUI::createKeyboardShortcuts() { actionCreate_torrent->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+N"))); actionOpen->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+O"))); @@ -548,86 +472,6 @@ void GUI::on_actionSet_global_download_limit_triggered() { new BandwidthAllocationDialog(this, false, BTSession, QStringList()); } -void GUI::on_actionPreview_file_triggered() { - QString hash; - switch(tabs->currentIndex()){ - case 0: - hash = downloadingTorrentTab->getSelectedTorrents(true).first(); - break; - case 1: - hash = finishedTorrentTab->getSelectedTorrents(true).first(); - break; - default: - return; - } - QTorrentHandle h = BTSession->getTorrentHandle(hash); - new previewSelect(this, h); -} - -void GUI::openDestinationFolder() const { - QStringList hashes; - switch(tabs->currentIndex()){ - case 0: - hashes = downloadingTorrentTab->getSelectedTorrents(true); - break; - case 1: - hashes = finishedTorrentTab->getSelectedTorrents(true); - 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); - } - } -} - -void GUI::copyMagnetURI() const { - QStringList hashes; - switch(tabs->currentIndex()){ - case 0: - hashes = downloadingTorrentTab->getSelectedTorrents(); - break; - case 1: - hashes = finishedTorrentTab->getSelectedTorrents(); - break; - default: - return; - } - QStringList magnet_uris; - foreach(QString hash, hashes) { - QTorrentHandle h = BTSession->getTorrentHandle(hash); - if(h.is_valid()) { - magnet_uris << misc::toQString(make_magnet_uri(h.get_torrent_info())); - } - } - qApp->clipboard()->setText(magnet_uris.join("\n")); -} - -void GUI::goBuyPage() const { - QStringList hashes; - switch(tabs->currentIndex()){ - case 0: - hashes = downloadingTorrentTab->getSelectedTorrents(true); - break; - case 1: - hashes = finishedTorrentTab->getSelectedTorrents(true); - 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"); - } -} - // Necessary if we want to close the window // in one time if "close to systray" is enabled void GUI::on_actionExit_triggered() { @@ -693,7 +537,7 @@ void GUI::on_actionAbout_triggered() { void GUI::showEvent(QShowEvent *e) { qDebug("** Show Event **"); - updateLists(true); + //updateLists(true); e->accept(); } @@ -708,14 +552,14 @@ void GUI::closeEvent(QCloseEvent *e) { e->accept(); return; } - if(settings.value(QString::fromUtf8("Preferences/General/ExitConfirm"), true).toBool() && downloadingTorrentTab->getNbTorrentsInList()) { + if(settings.value(QString::fromUtf8("Preferences/General/ExitConfirm"), true).toBool() && BTSession->hasActiveTorrents()) { 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("Some files are currently transferring.\nAre you sure you want to quit qBittorrent?"), tr("&Yes"), tr("&No"), QString(), 0, 1)) { e->ignore(); @@ -838,101 +682,6 @@ void GUI::on_actionOpen_triggered() { } } -// 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; - case 1: - hashes = finishedTorrentTab->getSelectedTorrents(); - inDownloadList = false; - break; - default: - return; - } - if(hashes.empty()) 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); - } -} - -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; - case 1: // SEED - hashes = finishedTorrentTab->getSelectedTorrents(); - inDownloadList = false; - break; - case 3: //RSSImp - rssWidget->deleteSelectedItems(); - return; - default: - return; - } - if(hashes.empty()) 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 @@ -993,10 +742,7 @@ void GUI::configureSession(bool deleteOptions) { toolBar->setVisible(false); } unsigned int new_refreshInterval = options->getRefreshInterval(); - if(refreshInterval != new_refreshInterval) { - refreshInterval = new_refreshInterval; - refresher->start(refreshInterval); - } + transferList->setRefreshInterval(new_refreshInterval); // Downloads // * Save path BTSession->setDefaultSavePath(options->getSavePath()); @@ -1069,7 +815,7 @@ void GUI::configureSession(bool deleteOptions) { // Queueing System if(options->isQueueingSystemEnabled()) { if(!BTSession->isQueueingEnabled()) { - downloadingTorrentTab->hidePriorityColumn(false); + transferList->hidePriorityColumn(false); actionDecreasePriority->setVisible(true); actionIncreasePriority->setVisible(true); prioSeparator->setVisible(true); @@ -1090,7 +836,7 @@ void GUI::configureSession(bool deleteOptions) { sessionSettings.active_seeds = -1; sessionSettings.active_limit = -1; BTSession->setQueueingEnabled(false); - downloadingTorrentTab->hidePriorityColumn(true); + transferList->hidePriorityColumn(true); actionDecreasePriority->setVisible(false); actionIncreasePriority->setVisible(false); prioSeparator->setVisible(false); @@ -1247,182 +993,6 @@ void GUI::configureSession(bool deleteOptions) { 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::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); - - 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) { - 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 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()); - } - }else{ - 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() { - 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); - } - if(change) { - updateUnfinishedTorrentNumber(downloadingTorrentTab->getNbTorrentsInList()); - updateFinishedTorrentNumber(finishedTorrentTab->getNbTorrentsInList()); - } -} - -void GUI::on_actionIncreasePriority_triggered() { - if(tabs->currentIndex() != 0) - return; - QStringList hashes = downloadingTorrentTab->getSelectedTorrents(); - foreach(const QString &hash, hashes) { - BTSession->increaseDlTorrentPriority(hash); - } - updateLists(); -} - -void GUI::on_actionDecreasePriority_triggered() { - Q_ASSERT(tabs->currentIndex() == 0); - QStringList hashes = downloadingTorrentTab->getSelectedTorrents(); - foreach(const QString &hash, hashes) { - BTSession->decreaseDlTorrentPriority(hash); - } - 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(); - } - qDebug("nb hashes: %d", hashes.size()); - 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; - 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()){ - 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) { @@ -1430,19 +1000,7 @@ void GUI::addUnauthenticatedTracker(QPair tracker) { } } -// 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)))); @@ -1474,7 +1032,7 @@ void GUI::updateLists(bool force) { 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) { @@ -1520,6 +1078,13 @@ void GUI::checkConnectionStatus() { } } +void GUI::showNotificationBaloon(QString title, QString msg) const { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + if(systrayIntegration && settings.value(QString::fromUtf8("Preferences/General/NotificationBaloons"), true).toBool()) { + myTrayIcon->showMessage(title, msg, QSystemTrayIcon::Information, TIME_TRAY_BALLOON); + } +} + /***************************************************** * * * Utils * diff --git a/src/GUI.h b/src/GUI.h index 1c789f7fc..59fd72069 100644 --- a/src/GUI.h +++ b/src/GUI.h @@ -40,8 +40,6 @@ class bittorrent; class createtorrent; class QTimer; -class DownloadingTorrents; -class FinishedTorrents; class downloadFromURL; class SearchEngine; class QLocalServer; @@ -57,6 +55,7 @@ class QLabel; class QModelIndex; class HttpServer; class QFrame; +class TransferListWidget; class GUI : public QMainWindow, private Ui::MainWindow{ Q_OBJECT @@ -73,14 +72,12 @@ class GUI : public QMainWindow, private Ui::MainWindow{ QSystemTrayIcon *myTrayIcon; QPointer systrayCreator; QMenu *myTrayIconMenu; - DownloadingTorrents *downloadingTorrentTab; - FinishedTorrents *finishedTorrentTab; + TransferListWidget *transferList; QLabel *connecStatusLblIcon; bool systrayIntegration; bool displaySpeedInTitle; bool force_exit; - unsigned int refreshInterval; - QTimer *refresher; + //unsigned int refreshInterval; QLabel *dlSpeedLbl; QLabel *upSpeedLbl; QLabel *ratioLbl; @@ -119,21 +116,15 @@ class GUI : public QMainWindow, private Ui::MainWindow{ void on_actionShow_console_triggered(); void readParamsOnSocket(); void acceptConnection(); - void togglePausedState(QString hash); - void torrentDoubleClicked(QString hash, bool finished); - void on_actionPreview_file_triggered(); void previewFile(QString filePath); void balloonClicked(); void writeSettings(); void readSettings(); void on_actionExit_triggered(); void createTrayIcon(); - void updateUnfinishedTorrentNumber(unsigned int nb); - void updateFinishedTorrentNumber(unsigned int nb); void fullDiskError(QTorrentHandle& h, QString msg) const; void handleDownloadFromUrlFailure(QString, QString) const; void createSystrayDelayed(); - void setPaused(QTorrentHandle &h) const; // Keyboard shortcuts void createKeyboardShortcuts(); void displayDownTab() const; @@ -141,17 +132,10 @@ class GUI : public QMainWindow, private Ui::MainWindow{ void displaySearchTab() const; void displayRSSTab() const; // Torrent actions - void on_actionTorrent_Properties_triggered(); - void on_actionPause_triggered(); - void on_actionPause_All_triggered(); - void on_actionStart_triggered(); - void on_actionStart_All_triggered(); - void on_actionOpen_triggered(); - void on_actionDelete_Permanently_triggered(); - void on_actionDelete_triggered(); void on_actionSet_global_upload_limit_triggered(); void on_actionSet_global_download_limit_triggered(); void on_actionDocumentation_triggered() const; + void on_actionOpen_triggered(); void checkConnectionStatus(); void configureSession(bool deleteOptions); void processParams(const QStringList& params); @@ -159,16 +143,9 @@ class GUI : public QMainWindow, private Ui::MainWindow{ void addUnauthenticatedTracker(QPair tracker); void processDownloadedFiles(QString path, QString url); void downloadFromURLList(const QStringList& urls); - void deleteTorrent(QString hash); void finishedTorrent(QTorrentHandle& h) const; - void addedTorrent(QTorrentHandle& h) const; - void checkedTorrent(QTorrentHandle& h) const; - void pausedTorrent(QTorrentHandle& h) const; - void resumedTorrent(QTorrentHandle& h) const; - void updateLists(bool force=false); + //void updateLists(bool force=false); bool initWebUi(QString username, QString password, int port); - void on_actionIncreasePriority_triggered(); - void on_actionDecreasePriority_triggered(); void scrapeTrackers(); // Options slots void on_actionOptions_triggered(); @@ -180,10 +157,8 @@ class GUI : public QMainWindow, private Ui::MainWindow{ public slots: void trackerAuthenticationRequired(QTorrentHandle& h); void setTabText(int index, QString text) const; - void openDestinationFolder() const; - void goBuyPage() const; - void copyMagnetURI() const; void updateRatio(); + void showNotificationBaloon(QString title, QString msg) const; protected: void closeEvent(QCloseEvent *); diff --git a/src/TransferListDelegate.h b/src/TransferListDelegate.h new file mode 100644 index 000000000..e8de0ee36 --- /dev/null +++ b/src/TransferListDelegate.h @@ -0,0 +1,121 @@ +/* + * 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 TRANSFERLISTDELEGATE_H +#define TRANSFERLISTDELEGATE_H + +#include +#include +#include +#include +#include +#include +#include "misc.h" + +// Defines for download list list columns +#define NAME 0 +#define SIZE 1 +#define PROGRESS 2 +#define DLSPEED 3 +#define UPSPEED 4 +#define SEEDSLEECH 5 +#define RATIO 6 +#define ETA 7 +#define PRIORITY 8 +#define HASH 9 + +class TransferListDelegate: public QItemDelegate { + Q_OBJECT + +public: + TransferListDelegate(QObject *parent) : QItemDelegate(parent){} + + ~TransferListDelegate(){} + + void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const{ + QStyleOptionViewItemV2 opt = QItemDelegate::setOptions(index, option); + switch(index.column()){ + case SIZE: + QItemDelegate::drawBackground(painter, opt, index); + QItemDelegate::drawDisplay(painter, opt, option.rect, misc::friendlyUnit(index.data().toLongLong())); + break; + case ETA: + QItemDelegate::drawBackground(painter, opt, index); + QItemDelegate::drawDisplay(painter, opt, option.rect, misc::userFriendlyDuration(index.data().toLongLong())); + break; + case UPSPEED: + case DLSPEED:{ + QItemDelegate::drawBackground(painter, opt, index); + double speed = index.data().toDouble(); + QItemDelegate::drawDisplay(painter, opt, opt.rect, QString(QByteArray::number(speed/1024., 'f', 1))+QString::fromUtf8(" ")+tr("KiB/s")); + break; + } + case RATIO:{ + QItemDelegate::drawBackground(painter, opt, index); + double ratio = index.data().toDouble(); + if(ratio > 100.) + QItemDelegate::drawDisplay(painter, opt, opt.rect, QString::fromUtf8("∞")); + else + QItemDelegate::drawDisplay(painter, opt, opt.rect, QString(QByteArray::number(ratio, 'f', 1))); + break; + } + case PRIORITY: { + int priority = index.data().toInt(); + if(priority >= 0) + QItemDelegate::paint(painter, option, index); + break; + } + case PROGRESS:{ + QStyleOptionProgressBarV2 newopt; + double progress = index.data().toDouble()*100.; + newopt.rect = opt.rect; + newopt.text = QString(QByteArray::number(progress, 'f', 1))+QString::fromUtf8("%"); + newopt.progress = (int)progress; + newopt.maximum = 100; + newopt.minimum = 0; + newopt.state |= QStyle::State_Enabled; + newopt.textVisible = true; + QApplication::style()->drawControl(QStyle::CE_ProgressBar, &newopt, + painter); + break; + } + default: + QItemDelegate::paint(painter, option, index); + } + } + + QWidget* createEditor(QWidget*, const QStyleOptionViewItem &, const QModelIndex &) const { + // No editor here + return 0; + } + +}; + +#endif // TRANSFERLISTDELEGATE_H diff --git a/src/TransferListWidget.cpp b/src/TransferListWidget.cpp new file mode 100644 index 000000000..34f516436 --- /dev/null +++ b/src/TransferListWidget.cpp @@ -0,0 +1,537 @@ +/* + * Bittorrent Client using Qt4 and libtorrent. + * Copyright (C) 2006 Christophe Dumez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + * + * Contact : chris@qbittorrent.org + */ + +#include "TransferListWidget.h" +#include "TransferListDelegate.h" +#include "bittorrent.h" +#include "torrentPersistentData.h" +#include "previewSelect.h" +#include "options_imp.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +TransferListWidget::TransferListWidget(QWidget *parent, bittorrent *_BTSession): QTreeView(parent) { + QSettings settings("qBittorrent", "qBittorrent"); + BTSession = _BTSession; + + // Create and apply delegate + listDelegate = new TransferListDelegate(this); + setItemDelegate(listDelegate); + + // Create transfer list model + listModel = new QStandardItemModel(0,10); + listModel->setHeaderData(NAME, Qt::Horizontal, tr("Name", "i.e: file name")); + listModel->setHeaderData(SIZE, Qt::Horizontal, tr("Size", "i.e: file size")); + listModel->setHeaderData(PROGRESS, Qt::Horizontal, tr("Progress", "i.e: % downloaded")); + listModel->setHeaderData(DLSPEED, Qt::Horizontal, tr("DL Speed", "i.e: Download speed")); + listModel->setHeaderData(UPSPEED, Qt::Horizontal, tr("UP Speed", "i.e: Upload speed")); + listModel->setHeaderData(SEEDSLEECH, Qt::Horizontal, tr("Seeds/Leechers", "i.e: full/partial sources")); + listModel->setHeaderData(RATIO, Qt::Horizontal, tr("Ratio")); + listModel->setHeaderData(ETA, Qt::Horizontal, tr("ETA", "i.e: Estimated Time of Arrival / Time left")); + listModel->setHeaderData(PRIORITY, Qt::Horizontal, "#"); + + // Set Sort/Filter proxy + proxyModel = new QSortFilterProxyModel(); + proxyModel->setDynamicSortFilter(true); + proxyModel->setSourceModel(listModel); + setModel(proxyModel); + + // Visual settings + setRootIsDecorated(false); + setAllColumnsShowFocus(true); + setSortingEnabled(true); + hideColumn(PRIORITY); + hideColumn(HASH); + loadHiddenColumns(); + setContextMenuPolicy(Qt::CustomContextMenu); + + // Listen for BTSession events + connect(BTSession, SIGNAL(addedTorrent(QTorrentHandle&)), this, SLOT(addTorrent(QTorrentHandle&))); + connect(BTSession, SIGNAL(finishedTorrent(QTorrentHandle&)), this, SLOT(setFinished(QTorrentHandle&))); + + // Listen for list events + connect(this, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(torrentDoubleClicked(QModelIndex))); + connect(header(), SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayDLHoSMenu(const QPoint&))); + + // Refresh timer + refreshTimer = new QBasicTimer(); + refreshTimer->start(settings.value("Preferences/General/RefreshInterval", 1500).toInt(), this); +} + +TransferListWidget::~TransferListWidget() { + saveHiddenColumns(); + delete refreshTimer; + delete proxyModel; + delete listModel; + delete listDelegate; +} + +void TransferListWidget::timerEvent(QTimerEvent*) { + refreshList(); +} + +void TransferListWidget::addTorrent(QTorrentHandle& h) { + if(!h.is_valid()) return; + int row = listModel->rowCount(); + try { + // Adding torrent to transfer list + listModel->insertRow(row); + listModel->setData(listModel->index(row, NAME), QVariant(h.name())); + listModel->setData(listModel->index(row, SIZE), QVariant((qlonglong)h.actual_size())); + if(BTSession->isQueueingEnabled() && !h.is_seed()) + listModel->setData(listModel->index(row, PRIORITY), QVariant((int)BTSession->getDlTorrentPriority(h.hash()))); + listModel->setData(listModel->index(row, HASH), QVariant(h.hash())); + // Pause torrent if it is + if(h.is_paused()) { + listModel->setData(listModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/paused.png"))), Qt::DecorationRole); + //setRowColor(row, QString::fromUtf8("red")); + }else{ + listModel->setData(listModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/stalled.png"))), Qt::DecorationRole); + //setRowColor(row, QString::fromUtf8("grey")); + } + } catch(invalid_handle e) { + // Remove added torrent + listModel->removeRow(row); + } +} + +/*void TransferListWidget::setRowColor(int row, QColor color) { + unsigned int nbColumns = listModel->columnCount()-1; + for(unsigned int i=0; isetData(listModel->index(row, i), QVariant(color), Qt::ForegroundRole); + } +}*/ + +void TransferListWidget::deleteTorrent(int row) { + listModel->removeRow(row); +} + +void TransferListWidget::pauseTorrent(QString hash) { + pauseTorrent(getRowFromHash(hash)); +} + +void TransferListWidget::pauseTorrent(int row) { + qDebug("Torrent visibly paused"); + listModel->setData(listModel->index(row, DLSPEED), QVariant((double)0.0)); + listModel->setData(listModel->index(row, UPSPEED), QVariant((double)0.0)); + listModel->setData(listModel->index(row, ETA), QVariant((qlonglong)-1)); + listModel->setData(listModel->index(row, NAME), QIcon(QString::fromUtf8(":/Icons/skin/paused.png")), Qt::DecorationRole); + listModel->setData(listModel->index(row, SEEDSLEECH), QVariant(QString::fromUtf8("0/0"))); + //setRowColor(row, QString::fromUtf8("red")); +} + +void TransferListWidget::resumeTorrent(int row) { + QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(row)); + if(!h.is_valid()) return; + if(h.is_seed()) + listModel->setData(listModel->index(row, NAME), QVariant(QIcon(":/Icons/skin/seeding.png")), Qt::DecorationRole); + updateTorrent(row); +} + +void TransferListWidget::updateTorrent(int row) { + QString hash = getHashFromRow(row); + QTorrentHandle h = BTSession->getTorrentHandle(hash); + if(!h.is_valid()) { + // Delete torrent + deleteTorrent(row); + return; + } + try { + if(h.is_paused()) return; + if(!h.is_seed()) { + // Queueing code + if(BTSession->isQueueingEnabled()) { + listModel->setData(listModel->index(row, PRIORITY), QVariant((int)BTSession->getDlTorrentPriority(hash))); + if(h.is_queued()) { + if(h.state() == torrent_status::checking_files || h.state() == torrent_status::queued_for_checking) { + listModel->setData(listModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/oxygen/time.png"))), Qt::DecorationRole); + listModel->setData(listModel->index(row, PROGRESS), QVariant((double)h.progress())); + }else { + listModel->setData(listModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/queued.png"))), Qt::DecorationRole); + listModel->setData(listModel->index(row, ETA), QVariant((qlonglong)-1)); + } + // Reset speeds and seeds/leech + listModel->setData(listModel->index(row, DLSPEED), QVariant((double)0.)); + listModel->setData(listModel->index(row, UPSPEED), QVariant((double)0.)); + listModel->setData(listModel->index(row, SEEDSLEECH), QVariant("0/0")); + //setRowColor(row, QString::fromUtf8("grey")); + return; + } + } + // Update + listModel->setData(listModel->index(row, PROGRESS), QVariant((double)h.progress())); + listModel->setData(listModel->index(row, DLSPEED), QVariant((double)h.download_payload_rate())); + + // Parse download state + switch(h.state()) { + case torrent_status::checking_files: + case torrent_status::queued_for_checking: + case torrent_status::checking_resume_data: + listModel->setData(listModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/oxygen/time.png"))), Qt::DecorationRole); + //setRowColor(row, QString::fromUtf8("grey")); + break; + case torrent_status::downloading: + case torrent_status::downloading_metadata: + if(h.download_payload_rate() > 0) { + listModel->setData(listModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png"))), Qt::DecorationRole); + listModel->setData(listModel->index(row, ETA), QVariant((qlonglong)BTSession->getETA(hash))); + //setRowColor(row, QString::fromUtf8("green")); + }else{ + listModel->setData(listModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/stalled.png"))), Qt::DecorationRole); + listModel->setData(listModel->index(row, ETA), QVariant((qlonglong)-1)); + //setRowColor(row, QApplication::palette().color(QPalette::WindowText)); + } + listModel->setData(listModel->index(row, UPSPEED), QVariant((double)h.upload_payload_rate())); + break; + default: + listModel->setData(listModel->index(row, ETA), QVariant((qlonglong)-1)); + } + } + + // Common to both downloads and uploads + QString tmp = misc::toQString(h.num_seeds(), true); + if(h.num_complete() >= 0) + tmp.append(QString("(")+misc::toQString(h.num_complete())+QString(")")); + tmp.append(QString("/")+misc::toQString(h.num_peers() - h.num_seeds(), true)); + if(h.num_incomplete() >= 0) + tmp.append(QString("(")+misc::toQString(h.num_incomplete())+QString(")")); + listModel->setData(listModel->index(row, SEEDSLEECH), QVariant(tmp)); + listModel->setData(listModel->index(row, RATIO), QVariant(misc::toQString(BTSession->getRealRatio(hash)))); + listModel->setData(listModel->index(row, UPSPEED), QVariant((double)h.upload_payload_rate())); + // FIXME: Add all_time_upload column + }catch(invalid_handle e) { + deleteTorrent(row); + qDebug("Caught Invalid handle exception, lucky us."); + } +} + +void TransferListWidget::setFinished(QTorrentHandle &h) { + int row = -1; + try { + row = getRowFromHash(h.hash()); + if(row >= 0) { + if(h.is_paused()) { + listModel->setData(listModel->index(row, NAME), QIcon(":/Icons/skin/paused.png"), Qt::DecorationRole); + //setRowColor(row, "red"); + }else{ + listModel->setData(listModel->index(row, NAME), QVariant(QIcon(":/Icons/skin/seeding.png")), Qt::DecorationRole); + //setRowColor(row, "orange"); + } + listModel->setData(listModel->index(row, ETA), QVariant((qlonglong)-1)); + listModel->setData(listModel->index(row, DLSPEED), QVariant((double)0.)); + listModel->setData(listModel->index(row, PROGRESS), QVariant((double)1.)); + listModel->setData(listModel->index(row, PRIORITY), QVariant((int)-1)); + } + } catch(invalid_handle e) { + if(row >= 0) deleteTorrent(row); + } +} + +void TransferListWidget::setRefreshInterval(int t) { + refreshTimer->start(t, this); +} + +void TransferListWidget::refreshList() { + for(int i=0; irowCount(); ++i) { + updateTorrent(i); + } +} + +int TransferListWidget::getRowFromHash(QString hash) const{ + QList items = listModel->findItems(hash, Qt::MatchExactly, HASH); + if(items.empty()) return -1; + Q_ASSERT(items.size() == 1); + return items.first()->row(); +} + +QString TransferListWidget::getHashFromRow(int row) const { + return listModel->data(listModel->index(row, HASH)).toString(); +} + +void TransferListWidget::torrentDoubleClicked(QModelIndex index) { + int row = proxyModel->mapToSource(index).row(); + QString hash = getHashFromRow(row); + QTorrentHandle h = BTSession->getTorrentHandle(hash); + if(!h.is_valid()) return; + int action; + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + if(h.is_seed()) { + action = settings.value(QString::fromUtf8("Preferences/Downloads/DblClOnTorFN"), 0).toInt(); + } else { + action = settings.value(QString::fromUtf8("Preferences/Downloads/DblClOnTorDl"), 0).toInt(); + } + + switch(action) { + case TOGGLE_PAUSE: + if(h.is_paused()) { + h.resume(); + resumeTorrent(row); + } else { + h.pause(); + pauseTorrent(row); + } + break; + case OPEN_DEST: + QDesktopServices::openUrl(QUrl(h.save_path())); + break; + } +} + +void TransferListWidget::startSelectedTorrents() { + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + foreach(const QModelIndex &index, selectedIndexes) { + // Get the file hash + QString hash = getHashFromRow(index.row()); + QTorrentHandle h = BTSession->getTorrentHandle(hash); + if(h.is_valid() && h.is_paused()) { + h.resume(); + resumeTorrent(index.row()); + } + } +} + +void TransferListWidget::startAllTorrents() { + for(int i=0; irowCount(); ++i) { + QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(i)); + if(h.is_valid() && h.is_paused()) { + h.resume(); + resumeTorrent(i); + } + } +} + +void TransferListWidget::pauseSelectedTorrents() { + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + foreach(const QModelIndex &index, selectedIndexes) { + // Get the file hash + QString hash = getHashFromRow(index.row()); + QTorrentHandle h = BTSession->getTorrentHandle(hash); + if(h.is_valid() && !h.is_paused()) { + h.pause(); + qDebug("row: %d", index.row()); + pauseTorrent(index.row()); + } + } +} + +void TransferListWidget::pauseAllTorrents() { + for(int i=0; irowCount(); ++i) { + QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(i)); + if(h.is_valid() && !h.is_paused()) { + h.pause(); + pauseTorrent(i); + } + } +} + +void TransferListWidget::deleteSelectedTorrents() { + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + if(!selectedIndexes.empty()) { + int ret = QMessageBox::question( + this, + tr("Deletion confirmation"), + tr("Are you sure you want to delete the selected torrents from transfer list?"), + tr("&Yes"), tr("&No"), + QString(), 0, 1); + if(ret) return; + foreach(const QModelIndex &index, selectedIndexes) { + // Get the file hash + QString hash = getHashFromRow(index.row()); + deleteTorrent(index.row()); + BTSession->deleteTorrent(hash, false); + } + } +} + +void TransferListWidget::deletePermSelectedTorrents() { + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + if(!selectedIndexes.empty()) { + int ret = QMessageBox::question( + this, + tr("Deletion confirmation"), + tr("Are you sure you want to delete the selected torrents from transfe list and hard disk?"), + tr("&Yes"), tr("&No"), + QString(), 0, 1); + if(ret) return; + foreach(const QModelIndex &index, selectedIndexes) { + // Get the file hash + QString hash = getHashFromRow(index.row()); + deleteTorrent(index.row()); + BTSession->deleteTorrent(hash, true); + } + } +} + +// FIXME: Should work only if the tab is displayed +void TransferListWidget::increasePrioSelectedTorrents() { + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + foreach(const QModelIndex &index, selectedIndexes) { + QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(index.row())); + if(h.is_valid() && !h.is_seed()) { + BTSession->increaseDlTorrentPriority(h.hash()); + updateTorrent(index.row()); + } + } +} + +// FIXME: Should work only if the tab is displayed +void TransferListWidget::decreasePrioSelectedTorrents() { + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + foreach(const QModelIndex &index, selectedIndexes) { + QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(index.row())); + if(h.is_valid() && !h.is_seed()) { + BTSession->decreaseDlTorrentPriority(h.hash()); + updateTorrent(index.row()); + } + } +} + +// FIXME: Use this function +void TransferListWidget::buySelectedTorrents() const { + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + foreach(const QModelIndex &index, selectedIndexes) { + QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(index.row())); + if(h.is_valid()) + QDesktopServices::openUrl("http://match.sharemonkey.com/?info_hash="+h.hash()+"&n="+h.name()+"&cid=33"); + } +} + +//FIXME: Use this function +void TransferListWidget::copySelectedMagnetURIs() const { + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + QStringList magnet_uris; + foreach(const QModelIndex &index, selectedIndexes) { + QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(index.row())); + if(h.is_valid()) + magnet_uris << misc::toQString(make_magnet_uri(h.get_torrent_info())); + } + qApp->clipboard()->setText(magnet_uris.join("\n")); +} + +void TransferListWidget::hidePriorityColumn(bool hide) { + setColumnHidden(PRIORITY, hide); +} + +// FIXME: Use it +void TransferListWidget::openSelectedTorrentsFolder() const { + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + QStringList pathsList; + foreach(const QModelIndex &index, selectedIndexes) { + QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(index.row())); + if(h.is_valid()) { + QString savePath = h.save_path(); + if(!pathsList.contains(savePath)) { + pathsList.append(savePath); + QDesktopServices::openUrl(QUrl(QString("file://")+savePath)); + } + } + } +} + +// FIXME: Use it +void TransferListWidget::previewSelectedTorrents() { + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + QStringList pathsList; + foreach(const QModelIndex &index, selectedIndexes) { + QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(index.row())); + if(h.is_valid()) { + new previewSelect(this, h); + } + } +} + +// save the hidden columns in settings +void TransferListWidget::saveHiddenColumns() { + QSettings settings("qBittorrent", "qBittorrent"); + QStringList ishidden_list; + short nbColumns = listModel->columnCount()-1; + + for(short i=0; icolumnCount()-1) { + for(unsigned int i=0; iisQueueingEnabled()) { + lastCol = PRIORITY; + } else { + lastCol = ETA; + } + QList actions; + for(int i=0; i <= lastCol; ++i) { + QIcon icon; + if(isColumnHidden(i)) + icon = QIcon(QString::fromUtf8(":/Icons/oxygen/button_cancel.png")); + else + icon = QIcon(QString::fromUtf8(":/Icons/oxygen/button_ok.png")); + actions.append(hideshowColumn.addAction(icon, listModel->headerData(i, Qt::Horizontal).toString())); + } + // Call menu + QAction *act = hideshowColumn.exec(QCursor::pos()); + int col = actions.indexOf(act); + setColumnHidden(col, !isColumnHidden(col)); +} diff --git a/src/TransferListWidget.h b/src/TransferListWidget.h new file mode 100644 index 000000000..5f463ac36 --- /dev/null +++ b/src/TransferListWidget.h @@ -0,0 +1,95 @@ +/* + * 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 TRANSFERLISTWIDGET_H +#define TRANSFERLISTWIDGET_H + +#include +#include "qtorrenthandle.h" + +class TransferListDelegate; +class QStandardItemModel; +class QSortFilterProxyModel; +class bittorrent; +class QBasicTimer; + +class TransferListWidget: public QTreeView { + Q_OBJECT + +private: + TransferListDelegate *listDelegate; + QStandardItemModel *listModel; + QSortFilterProxyModel *proxyModel; + bittorrent* BTSession; + QBasicTimer *refreshTimer; + +public: + TransferListWidget(QWidget *parent, bittorrent* BTSession); + ~TransferListWidget(); + +protected: + void timerEvent(QTimerEvent*); + int getRowFromHash(QString hash) const; + QString getHashFromRow(int row) const; + +protected slots: + void updateTorrent(int row); + void deleteTorrent(int row); + void pauseTorrent(int row); + void resumeTorrent(int row); + void torrentDoubleClicked(QModelIndex index); + bool loadHiddenColumns(); + void saveHiddenColumns(); + //void setRowColor(int row, QColor color); + +public slots: + void refreshList(); + void addTorrent(QTorrentHandle& h); + void setFinished(QTorrentHandle &h); + void setRefreshInterval(int t); + void startSelectedTorrents(); + void startAllTorrents(); + void pauseSelectedTorrents(); + void pauseAllTorrents(); + void pauseTorrent(QString hash); + void deleteSelectedTorrents(); + void deletePermSelectedTorrents(); + void increasePrioSelectedTorrents(); + void decreasePrioSelectedTorrents(); + void buySelectedTorrents() const; + void copySelectedMagnetURIs() const; + void openSelectedTorrentsFolder() const; + void previewSelectedTorrents(); + void hidePriorityColumn(bool hide); + void displayDLHoSMenu(const QPoint&); + +}; + +#endif // TRANSFERLISTWIDGET_H diff --git a/src/bittorrent.cpp b/src/bittorrent.cpp index 281de1b89..c241b0ebf 100644 --- a/src/bittorrent.cpp +++ b/src/bittorrent.cpp @@ -243,32 +243,15 @@ QTorrentHandle bittorrent::getTorrentHandle(QString hash) const{ return QTorrentHandle(s->find_torrent(misc::fromString((hash.toStdString())))); } -unsigned int bittorrent::getFinishedPausedTorrentsNb() const { - unsigned int nbPaused = 0; +bool bittorrent::hasActiveTorrents() const { 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; - } - } - 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; - } + if(h.is_valid() && !h.is_paused() && !h.is_queued()) + return true; } - return nbPaused; + return false; } // Delete a torrent from the session, given its hash diff --git a/src/bittorrent.h b/src/bittorrent.h index 7e753adf7..6aaab3254 100644 --- a/src/bittorrent.h +++ b/src/bittorrent.h @@ -97,8 +97,7 @@ class bittorrent : public QObject { session* getSession() const; QHash getTrackersErrors(QString hash) const; bool has_filtered_files(QString hash) const; - unsigned int getFinishedPausedTorrentsNb() const; - unsigned int getUnfinishedPausedTorrentsNb() const; + bool hasActiveTorrents() const; bool isQueueingEnabled() const; int getDlTorrentPriority(QString hash) const; int getUpTorrentPriority(QString hash) const; diff --git a/src/downloadingTorrents.cpp b/src/downloadingTorrents.cpp index 697b2c393..c824f7633 100644 --- a/src/downloadingTorrents.cpp +++ b/src/downloadingTorrents.cpp @@ -380,14 +380,6 @@ void DownloadingTorrents::hideOrShowColumn(int index) { } } -void DownloadingTorrents::hidePriorityColumn(bool hide) { - downloadList->setColumnHidden(PRIORITY, hide); - if(hide) - getActionHoSCol(PRIORITY)->setIcon(QIcon(QString::fromUtf8(":/Icons/oxygen/button_cancel.png"))); - else - getActionHoSCol(PRIORITY)->setIcon(QIcon(QString::fromUtf8(":/Icons/oxygen/button_ok.png"))); -} - // save the hidden columns in settings void DownloadingTorrents::saveHiddenColumns() { QSettings settings("qBittorrent", "qBittorrent"); @@ -778,3 +770,5 @@ int DownloadingTorrents::getRowFromHash(QString hash) const{ } return -1; } + + diff --git a/src/downloadingTorrents.h b/src/downloadingTorrents.h index 0004ee408..7acaa9ac3 100644 --- a/src/downloadingTorrents.h +++ b/src/downloadingTorrents.h @@ -97,7 +97,6 @@ class DownloadingTorrents : public QWidget, public Ui::downloading{ void propertiesSelection(); void updateFileSizeAndProgress(QString hash); void showPropertiesFromHash(QString hash); - void hidePriorityColumn(bool hide); void saveLastSortedColumn(); void loadLastSortedColumn(); void addTorrent(QString hash); diff --git a/src/src.pro b/src/src.pro index 115cc1b1b..f6ba38b57 100644 --- a/src/src.pro +++ b/src/src.pro @@ -185,7 +185,9 @@ HEADERS += GUI.h \ torrentPersistentData.h \ FeedDownloader.h \ feedList.h \ - supportedEngines.h + supportedEngines.h \ + TransferListWidget.h \ + TransferListDelegate.h FORMS += MainWindow.ui \ options.ui \ about.ui \ @@ -228,5 +230,6 @@ SOURCES += GUI.cpp \ eventmanager.cpp \ SearchTab.cpp \ ico.cpp \ - rss.cpp + rss.cpp \ + TransferListWidget.cpp DESTDIR = .