diff --git a/TODO b/TODO index 3e36c78b9..4724e8dbc 100644 --- a/TODO +++ b/TODO @@ -76,4 +76,6 @@ LANGUAGES UPDATED: - Korean *BETA5* beta5->beta6 changelog: +- FEATURE: Split GUI class from download tab - BUGFIX: Made torrent deletion from hard-drive safer +- BUGFIX: Fixed a bug when switching from finished to downloading list diff --git a/src/FinishedTorrents.cpp b/src/FinishedTorrents.cpp index b72c0ae5e..5c3d6a014 100644 --- a/src/FinishedTorrents.cpp +++ b/src/FinishedTorrents.cpp @@ -20,21 +20,24 @@ */ #include "FinishedTorrents.h" #include "misc.h" -#include "GUI.h" #include "properties_imp.h" #include "bittorrent.h" #include "allocationDlg.h" +#include "FinishedListDelegate.h" +#include "GUI.h" #include #include #include #include +#include FinishedTorrents::FinishedTorrents(QObject *parent, bittorrent *BTSession){ setupUi(this); nbFinished = 0; - this->parent = parent; this->BTSession = BTSession; + this->parent = parent; + connect(BTSession, SIGNAL(addedTorrent(QString, QTorrentHandle&, bool)), this, SLOT(torrentAdded(QString, QTorrentHandle&, bool))); finishedListModel = new QStandardItemModel(0,7); finishedListModel->setHeaderData(F_NAME, Qt::Horizontal, tr("Name", "i.e: file name")); finishedListModel->setHeaderData(F_SIZE, Qt::Horizontal, tr("Size", "i.e: file size")); @@ -56,7 +59,7 @@ FinishedTorrents::FinishedTorrents(QObject *parent, bittorrent *BTSession){ finishedListDelegate = new FinishedListDelegate(finishedList); finishedList->setItemDelegate(finishedListDelegate); connect(finishedList, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayFinishedListMenu(const QPoint&))); - connect(finishedList, SIGNAL(doubleClicked(const QModelIndex&)), parent, SLOT(togglePausedState(const QModelIndex&))); + connect(finishedList, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(notifyTorrentDoubleClicked(const QModelIndex&))); actionDelete->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/delete.png"))); actionPreview_file->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/preview.png"))); actionDelete_Permanently->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/delete_perm.png"))); @@ -74,7 +77,16 @@ FinishedTorrents::~FinishedTorrents(){ delete finishedListModel; } -void FinishedTorrents::addFinishedTorrent(QString hash){ +void FinishedTorrents::notifyTorrentDoubleClicked(const QModelIndex& index) { + unsigned int row = index.row(); + QString hash = getHashFromRow(row); + emit torrentDoubleClicked(hash); +} + +void FinishedTorrents::addTorrent(QString hash){ + if(!BTSession->isFinished(hash)){ + BTSession->setFinishedTorrent(hash); + } int row = getRowFromHash(hash); if(row != -1) return; row = finishedListModel->rowCount(); @@ -101,7 +113,14 @@ void FinishedTorrents::addFinishedTorrent(QString hash){ finished_file.close(); // Update the number of finished torrents ++nbFinished; - ((GUI*)parent)->setTabText(1, tr("Finished") +" ("+QString::fromUtf8(misc::toString(nbFinished).c_str())+")"); + emit finishedTorrentsNumberChanged(nbFinished); +} + +void FinishedTorrents::torrentAdded(QString, QTorrentHandle& h, bool) { + QString hash = h.hash(); + if(BTSession->isFinished(hash)) { + addTorrent(hash); + } } // Set the color of a row in data model @@ -111,6 +130,25 @@ void FinishedTorrents::setRowColor(int row, QString color){ } } +QStringList FinishedTorrents::getSelectedTorrents(bool only_one) const{ + QStringList res; + QModelIndex index; + QModelIndexList selectedIndexes = finishedList->selectionModel()->selectedIndexes(); + foreach(index, selectedIndexes) { + if(index.column() == F_NAME) { + // Get the file hash + QString hash = finishedListModel->data(finishedListModel->index(index.row(), F_HASH)).toString(); + res << hash; + if(only_one) break; + } + } + return res; +} + +unsigned int FinishedTorrents::getNbTorrentsInList() const { + return nbFinished; +} + // Load columns width in a file that were saved previously // (finished list) bool FinishedTorrents::loadColWidthFinishedList(){ @@ -158,7 +196,6 @@ void FinishedTorrents::on_actionSet_upload_limit_triggered(){ } void FinishedTorrents::updateFinishedList(){ - Q_ASSERT(((GUI*)parent)->getCurrentTabIndex() == 1); QString hash; QStringList finishedSHAs = BTSession->getFinishedTorrents(); foreach(hash, finishedSHAs){ @@ -170,17 +207,18 @@ void FinishedTorrents::updateFinishedList(){ int row = getRowFromHash(hash); if(row == -1){ qDebug("Cannot find torrent in finished list, adding it"); - addFinishedTorrent(hash); - continue; + addTorrent(hash); + row = getRowFromHash(hash); } + Q_ASSERT(row != -1); if(h.is_paused()) continue; Q_ASSERT(h.progress() <= 1. && h.progress() >= 0.); if(h.state() == torrent_status::downloading || (h.state() != torrent_status::checking_files && h.state() != torrent_status::queued_for_checking && h.progress() < 1.)) { // What are you doing here? go back to download tab! qDebug("Info: a torrent was moved from finished to download tab"); - deleteFromFinishedList(hash, true); + deleteTorrent(hash); BTSession->setFinishedTorrent(hash); - emit torrentMovedFromFinishedList(h); + emit torrentMovedFromFinishedList(hash); continue; } finishedListModel->setData(finishedListModel->index(row, F_UPSPEED), QVariant((double)h.upload_payload_rate())); @@ -199,24 +237,36 @@ int FinishedTorrents::getRowFromHash(QString hash) const{ return -1; } -// Will move it to download tab -void FinishedTorrents::deleteFromFinishedList(QString hash, bool switchTab){ +// Note: does not actually pause the torrent in BT Session +void FinishedTorrents::pauseTorrent(QString hash) { int row = getRowFromHash(hash); Q_ASSERT(row != -1); - finishedListModel->removeRow(row); - QFile::remove(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".finished"); - --nbFinished; - ((GUI*)parent)->setTabText(1, tr("Finished") +" ("+QString::fromUtf8(misc::toString(nbFinished).c_str())+")"); - if(switchTab) - BTSession->setUnfinishedTorrent(hash); + finishedListModel->setData(finishedListModel->index(row, F_UPSPEED), QVariant((double)0.0)); + finishedListModel->setData(finishedListModel->index(row, F_NAME), QIcon(QString::fromUtf8(":/Icons/skin/paused.png")), Qt::DecorationRole); + finishedListModel->setData(finishedListModel->index(row, F_SEEDSLEECH), QVariant(QString::fromUtf8("0/0"))); + setRowColor(row, QString::fromUtf8("red")); } -QTreeView* FinishedTorrents::getFinishedList(){ - return finishedList; +void FinishedTorrents::resumeTorrent(QString hash) { + int row = getRowFromHash(hash); + Q_ASSERT(row != -1); + finishedListModel->setData(finishedListModel->index(row, F_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/seeding.png"))), Qt::DecorationRole); + setRowColor(row, QString::fromUtf8("orange")); } -QStandardItemModel* FinishedTorrents::getFinishedListModel(){ - return finishedListModel; +QString FinishedTorrents::getHashFromRow(unsigned int row) const { + Q_ASSERT(row < (unsigned int)finishedListModel->rowCount()); + return finishedListModel->data(finishedListModel->index(row, F_HASH)).toString(); +} + +// Will move it to download tab +void FinishedTorrents::deleteTorrent(QString hash){ + int row = getRowFromHash(hash); + Q_ASSERT(row != -1); + finishedListModel->removeRow(row); + QFile::remove(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".finished"); + --nbFinished; + emit finishedTorrentsNumberChanged(nbFinished); } // Show torrent properties dialog @@ -225,7 +275,6 @@ void FinishedTorrents::showProperties(const QModelIndex &index){ QString hash = finishedListModel->data(finishedListModel->index(row, F_HASH)).toString(); QTorrentHandle h = BTSession->getTorrentHandle(hash); properties *prop = new properties(this, BTSession, h); - connect(prop, SIGNAL(mustHaveFullAllocationMode(QTorrentHandle)), BTSession, SLOT(reloadTorrent(QTorrentHandle))); connect(prop, SIGNAL(filteredFilesChanged(QString)), this, SLOT(updateFileSize(QString))); prop->show(); } diff --git a/src/FinishedTorrents.h b/src/FinishedTorrents.h index c32c2a6b4..2c1b31057 100644 --- a/src/FinishedTorrents.h +++ b/src/FinishedTorrents.h @@ -23,7 +23,6 @@ #define SEEDING_H #include "ui_seeding.h" -#include "FinishedListDelegate.h" #include "qtorrenthandle.h" class QStandardItemModel; @@ -32,30 +31,27 @@ class FinishedListDelegate; using namespace libtorrent; -class FinishedTorrents : public QWidget, public Ui::seeding{ +class FinishedTorrents : public QWidget, public Ui::seeding { Q_OBJECT private: - QObject *parent; bittorrent *BTSession; FinishedListDelegate *finishedListDelegate; QStandardItemModel *finishedListModel; unsigned int nbFinished; + QObject *parent; public: FinishedTorrents(QObject *parent, bittorrent *BTSession); ~FinishedTorrents(); // Methods - QTreeView* getFinishedList(); - QStandardItemModel* getFinishedListModel(); bool loadColWidthFinishedList(); int getRowFromHash(QString hash) const; + QStringList getSelectedTorrents(bool only_one=false) const; + unsigned int getNbTorrentsInList() const; + QString getHashFromRow(unsigned int row) const; - public slots: - void addFinishedTorrent(QString hash); - void updateFinishedList(); - void deleteFromFinishedList(QString hash, bool switchTab=false); + protected slots: void showProperties(const QModelIndex &index); - void propertiesSelection(); void displayFinishedListMenu(const QPoint&); void setRowColor(int row, QString color); void saveColWidthFinishedList() const; @@ -63,12 +59,22 @@ class FinishedTorrents : public QWidget, public Ui::seeding{ void sortFinishedListFloat(int index, Qt::SortOrder sortOrder); void sortFinishedListString(int index, Qt::SortOrder sortOrder); void updateFileSize(QString hash); - - protected slots: + void torrentAdded(QString path, QTorrentHandle& h, bool fastResume); void on_actionSet_upload_limit_triggered(); + void notifyTorrentDoubleClicked(const QModelIndex& index); + + public slots: + void addTorrent(QString hash); + void updateFinishedList(); + void pauseTorrent(QString hash); + void resumeTorrent(QString hash); + void propertiesSelection(); + void deleteTorrent(QString hash); signals: - void torrentMovedFromFinishedList(QTorrentHandle); + void torrentMovedFromFinishedList(QString); + void torrentDoubleClicked(QString hash); + void finishedTorrentsNumberChanged(unsigned int); }; diff --git a/src/GUI.cpp b/src/GUI.cpp index d0f1537ac..2b8a39735 100644 --- a/src/GUI.cpp +++ b/src/GUI.cpp @@ -19,7 +19,6 @@ * Contact : chris@qbittorrent.org */ #include -#include #include #include #include @@ -28,13 +27,14 @@ #include #include #include -#include +#include +#include #include "GUI.h" +#include "downloadingTorrents.h" #include "misc.h" #include "createtorrent_imp.h" #include "properties_imp.h" -#include "DLListDelegate.h" #include "downloadThread.h" #include "downloadFromURLImp.h" #include "torrentAddition.h" @@ -45,8 +45,8 @@ #include "bittorrent.h" #include "about_imp.h" #include "trackerLogin.h" -#include "previewSelect.h" #include "options_imp.h" +#include "previewSelect.h" using namespace libtorrent; namespace fs = boost::filesystem; @@ -72,17 +72,6 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent) { systrayIntegration = false; qDebug("Info: System tray unavailable\n"); } - delayedSorting = false; - BTSession = new bittorrent(); - // Finished torrents tab - finishedTorrentTab = new FinishedTorrents(this, BTSession); - tabs->addTab(finishedTorrentTab, tr("Finished")); - tabs->setTabIcon(1, QIcon(QString::fromUtf8(":/Icons/skin/seeding.png"))); - connect(finishedTorrentTab, SIGNAL(torrentMovedFromFinishedList(QTorrentHandle)), this, SLOT(restoreInDownloadList(QTorrentHandle))); - // Tabs text - nbTorrents = 0; - tabs->setTabText(0, tr("Downloads") + QString::fromUtf8(" (0)")); - tabs->setTabText(1, tr("Finished") + QString::fromUtf8(" (0)")); // Setting icons this->setWindowIcon(QIcon(QString::fromUtf8(":/Icons/qbittorrent32.png"))); actionOpen->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/open.png"))); @@ -112,56 +101,42 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent) { actionDelete_Permanently->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/delete_perm.png"))); actionTorrent_Properties->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/properties.png"))); actionCreate_torrent->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/new.png"))); -// tabBottom->setTabIcon(0, QIcon(QString::fromUtf8(":/Icons/log.png"))); -// tabBottom->setTabIcon(1, QIcon(QString::fromUtf8(":/Icons/filter.png"))); - tabs->setTabIcon(0, QIcon(QString::fromUtf8(":/Icons/skin/downloading.png"))); - // Set default ratio - lbl_ratio_icon->setPixmap(QPixmap(QString::fromUtf8(":/Icons/stare.png"))); // Fix Tool bar layout toolBar->layout()->setSpacing(7); - // Set Download list model - DLListModel = new QStandardItemModel(0,9); - DLListModel->setHeaderData(NAME, Qt::Horizontal, tr("Name", "i.e: file name")); - DLListModel->setHeaderData(SIZE, Qt::Horizontal, tr("Size", "i.e: file size")); - DLListModel->setHeaderData(PROGRESS, Qt::Horizontal, tr("Progress", "i.e: % downloaded")); - DLListModel->setHeaderData(DLSPEED, Qt::Horizontal, tr("DL Speed", "i.e: Download speed")); - DLListModel->setHeaderData(UPSPEED, Qt::Horizontal, tr("UP Speed", "i.e: Upload speed")); - DLListModel->setHeaderData(SEEDSLEECH, Qt::Horizontal, tr("Seeds/Leechs", "i.e: full/partial sources")); - DLListModel->setHeaderData(RATIO, Qt::Horizontal, tr("Ratio")); - DLListModel->setHeaderData(ETA, Qt::Horizontal, tr("ETA", "i.e: Estimated Time of Arrival / Time left")); - downloadList->setModel(DLListModel); - DLDelegate = new DLListDelegate(downloadList); - downloadList->setItemDelegate(DLDelegate); - // Hide hash column - downloadList->hideColumn(HASH); - - connect(BTSession, SIGNAL(addedTorrent(QString, QTorrentHandle&, bool)), this, SLOT(torrentAdded(QString, QTorrentHandle&, bool))); - connect(BTSession, SIGNAL(duplicateTorrent(QString)), this, SLOT(torrentDuplicate(QString))); - connect(BTSession, SIGNAL(invalidTorrent(QString)), this, SLOT(torrentCorrupted(QString))); - connect(BTSession, SIGNAL(finishedTorrent(QTorrentHandle&)), this, SLOT(finishedTorrent(QTorrentHandle&))); + // creating options + options = new options_imp(this); + connect(options, SIGNAL(status_changed(QString, bool)), this, SLOT(OptionsSaved(QString, bool))); + force_exit = false; + BTSession = new bittorrent(); connect(BTSession, SIGNAL(fullDiskError(QTorrentHandle&)), this, SLOT(fullDiskError(QTorrentHandle&))); - connect(BTSession, SIGNAL(portListeningFailure()), this, SLOT(portListeningFailure())); + connect(BTSession, SIGNAL(finishedTorrent(QTorrentHandle&)), this, SLOT(finishedTorrent(QTorrentHandle&))); + connect(BTSession, SIGNAL(torrentFinishedChecking(QString)), this, SLOT(torrentChecked(QString))); connect(BTSession, SIGNAL(trackerAuthenticationRequired(QTorrentHandle&)), this, SLOT(trackerAuthenticationRequired(QTorrentHandle&))); - connect(BTSession, SIGNAL(peerBlocked(QString)), this, SLOT(addLogPeerBlocked(const QString))); - connect(BTSession, SIGNAL(fastResumeDataRejected(QString)), this, SLOT(addFastResumeRejectedAlert(QString))); connect(BTSession, SIGNAL(scanDirFoundTorrents(const QStringList&)), this, SLOT(processScannedFiles(const QStringList&))); 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(aboutToDownloadFromUrl(QString)), this, SLOT(displayDownloadingUrlInfos(QString))); - connect(BTSession, SIGNAL(urlSeedProblem(QString, QString)), this, SLOT(addUrlSeedError(QString, QString))); - connect(BTSession, SIGNAL(torrentFinishedChecking(QString)), this, SLOT(torrentChecked(QString))); - // creating options - options = new options_imp(this); - connect(options, SIGNAL(status_changed(QString, bool)), this, SLOT(OptionsSaved(QString, bool))); + qDebug("create tabWidget"); + tabs = new QTabWidget(); + // Download torrents tab + downloadingTorrentTab = new DownloadingTorrents(this, BTSession); + tabs->addTab(downloadingTorrentTab, tr("Downloads") + QString::fromUtf8(" (0)")); + tabs->setTabIcon(0, 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)), this, SLOT(togglePausedState(QString))); + // Finished torrents tab + finishedTorrentTab = new FinishedTorrents(this, BTSession); + tabs->addTab(finishedTorrentTab, tr("Finished") + QString::fromUtf8(" (0)")); + tabs->setTabIcon(1, QIcon(QString::fromUtf8(":/Icons/skin/seeding.png"))); + connect(finishedTorrentTab, SIGNAL(torrentDoubleClicked(QString)), this, SLOT(togglePausedState(QString))); + connect(finishedTorrentTab, SIGNAL(finishedTorrentsNumberChanged(unsigned int)), this, SLOT(updateFinishedTorrentNumber(unsigned int))); + // Smooth torrent switching between tabs Downloading <--> Finished + connect(downloadingTorrentTab, SIGNAL(torrentFinished(QString)), finishedTorrentTab, SLOT(addTorrent(QString))); + connect(finishedTorrentTab, SIGNAL(torrentMovedFromFinishedList(QString)), downloadingTorrentTab, SLOT(addTorrent(QString))); // Configure BT session according to options configureSession(true); - force_exit = false; // Resume unfinished torrents BTSession->resumeUnfinishedTorrents(); - // Load last columns width for download list - if(!loadColWidthDLList()) { - downloadList->header()->resizeSection(0, 200); - } // Search engine tab searchEngine = new SearchEngine(BTSession, myTrayIcon, systrayIntegration); tabs->addTab(searchEngine, tr("Search")); @@ -173,18 +148,6 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent) { readSettings(); // Add torrent given on command line processParams(torrentCmdLine); - // Make download list header clickable for sorting - downloadList->header()->setClickable(true); - downloadList->header()->setSortIndicatorShown(true); - // Connecting Actions to slots - connect(downloadList, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(togglePausedState(const QModelIndex&))); - connect(downloadList->header(), SIGNAL(sectionPressed(int)), this, SLOT(sortDownloadList(int))); - connect(downloadList, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayDLListMenu(const QPoint&))); - connect(infoBar, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayInfoBarMenu(const QPoint&))); - // Start download list refresher - refresher = new QTimer(this); - connect(refresher, SIGNAL(timeout()), this, SLOT(updateDlList())); - refresher->start(2000); // Use a tcp server to allow only one instance of qBittorrent tcpServer = new QTcpServer(); if (!tcpServer->listen(QHostAddress::LocalHost, 1666)) { @@ -195,13 +158,14 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent) { checkConnect = new QTimer(this); connect(checkConnect, SIGNAL(timeout()), this, SLOT(checkConnectionStatus())); checkConnect->start(5000); + // Start download list refresher + refresher = new QTimer(this); + connect(refresher, SIGNAL(timeout()), this, SLOT(updateLists())); + refresher->start(2000); previewProcess = new QProcess(this); connect(previewProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(cleanTempPreviewFile(int, QProcess::ExitStatus))); // Accept drag 'n drops setAcceptDrops(true); - // Set info Bar infos - setInfoBar(tr("qBittorrent %1 started.", "e.g: qBittorrent v0.x started.").arg(QString::fromUtf8(""VERSION))); - setInfoBar(tr("Be careful, sharing copyrighted material without permission is against the law."), QString::fromUtf8("red")); show(); createKeyboardShortcuts(); qDebug("GUI Built"); @@ -211,20 +175,20 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent) { GUI::~GUI() { qDebug("GUI destruction"); delete searchEngine; + delete refresher; + delete downloadingTorrentTab; delete finishedTorrentTab; delete checkConnect; - delete refresher; if(systrayIntegration) { delete myTrayIcon; delete myTrayIconMenu; } - delete DLDelegate; - delete DLListModel; delete tcpServer; previewProcess->kill(); previewProcess->waitForFinished(); delete previewProcess; delete connecStatusLblIcon; + delete tabs; // Keyboard shortcuts delete switchSearchShortcut; delete switchSearchShortcut2; @@ -254,6 +218,70 @@ void GUI::writeSettings() { settings.endGroup(); } +// Called when a torrent finished checking +void GUI::torrentChecked(QString hash) { + // Check if the torrent was paused after checking + if(BTSession->isPaused(hash)) { + // Was paused, change its icon/color + if(BTSession->isFinished(hash)) { + // In finished list + qDebug("Automatically paused torrent was in finished list"); + finishedTorrentTab->pauseTorrent(hash); + }else{ + // In download list + downloadingTorrentTab->pauseTorrent(hash); + // Delayed Sorting + downloadingTorrentTab->sortProgressColumnDelayed(); + } + } +} + +// called when a torrent has finished +void GUI::finishedTorrent(QTorrentHandle& h) { + qDebug("In GUI, a torrent has finished"); + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + bool show_msg = true; + QString fileName = h.name(); + int useOSD = settings.value(QString::fromUtf8("Options/OSDEnabled"), 1).toInt(); + // Add it to finished tab + QString hash = h.hash(); + if(QFile::exists(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".finished"))) { + show_msg = false; + qDebug("We received a finished signal for torrent %s, but it already has a .finished file", hash.toUtf8().data()); + } + if(show_msg) + downloadingTorrentTab->setInfoBar(tr("%1 has finished downloading.", "e.g: xxx.avi has finished downloading.").arg(fileName)); + if(BTSession->getUnfinishedTorrents().contains(hash)) { + downloadingTorrentTab->deleteTorrent(hash); + }else{ + qDebug("finished torrent %s is not in download list, nothing to do", hash.toUtf8().data()); + } + finishedTorrentTab->addTorrent(hash); + if(show_msg && systrayIntegration && (useOSD == 1 || (useOSD == 2 && (isMinimized() || isHidden())))) { + myTrayIcon->showMessage(tr("Download finished"), tr("%1 has finished downloading.", "e.g: xxx.avi has finished downloading.").arg(fileName), QSystemTrayIcon::Information, TIME_TRAY_BALLOON); + } +} + +// Notification when disk is full +void GUI::fullDiskError(QTorrentHandle& h) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + int useOSD = settings.value(QString::fromUtf8("Options/OSDEnabled"), 1).toInt(); + if(systrayIntegration && (useOSD == 1 || (useOSD == 2 && (isMinimized() || isHidden())))) { + myTrayIcon->showMessage(tr("I/O Error", "i.e: Input/Output Error"), tr("An error occured when trying to read or write %1. The disk is probably full, download has been paused", "e.g: An error occured when trying to read or write xxx.avi. The disk is probably full, download has been paused").arg(h.name()), 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.toUtf8().data()); + if(BTSession->isFinished(hash)) { + // In finished list + qDebug("Automatically paused torrent was in finished list"); + finishedTorrentTab->pauseTorrent(hash); + }else{ + downloadingTorrentTab->pauseTorrent(hash); + } + downloadingTorrentTab->setInfoBar(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"))); @@ -305,36 +333,6 @@ void GUI::readSettings() { settings.endGroup(); } -void GUI::addLogPeerBlocked(QString ip) { - static unsigned short nbLines = 0; - ++nbLines; - if(nbLines > 200) { - textBlockedUsers->clear(); - nbLines = 1; - } - textBlockedUsers->append(QString::fromUtf8("")+ QTime::currentTime().toString(QString::fromUtf8("hh:mm:ss")) + QString::fromUtf8(" - ")+tr("%1 was blocked", "x.y.z.w was blocked").arg(ip)); -} - -// Update Info Bar information -void GUI::setInfoBar(QString info, QString color) { - static unsigned short nbLines = 0; - ++nbLines; - // Check log size, clear it if too big - if(nbLines > 200) { - infoBar->clear(); - nbLines = 1; - } - infoBar->append(QString::fromUtf8("")+ QTime::currentTime().toString(QString::fromUtf8("hh:mm:ss")) + QString::fromUtf8(" - ") + info + QString::fromUtf8("")); -} - -void GUI::addFastResumeRejectedAlert(QString name) { - setInfoBar(tr("Fast resume data was rejected for torrent %1, checking again...").arg(name), QString::fromUtf8("red")); -} - -void GUI::addUrlSeedError(QString url, QString msg) { - setInfoBar(tr("Url seed lookup failed for url: %1, message: %2").arg(url).arg(msg), QString::fromUtf8("red")); -} - void GUI::balloonClicked() { if(isHidden()) { show(); @@ -359,37 +357,10 @@ void GUI::readParamsOnSocket() { processParams(QString::fromUtf8(params.data()).split(QString::fromUtf8("\n"))); qDebug("Received parameters from another instance"); } + delete clientConnection; } } -void GUI::on_actionSet_download_limit_triggered() { - QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes(); - QModelIndex index; - QStringList hashes; - foreach(index, selectedIndexes) { - if(index.column() == NAME) { - // Get the file hash - hashes << DLListModel->data(DLListModel->index(index.row(), HASH)).toString(); - } - } - Q_ASSERT(hashes.size() > 0); - new BandwidthAllocationDialog(this, false, BTSession, hashes); -} - -void GUI::on_actionSet_upload_limit_triggered() { - QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes(); - QModelIndex index; - QStringList hashes; - foreach(index, selectedIndexes) { - if(index.column() == NAME) { - // Get the file hash - hashes << DLListModel->data(DLListModel->index(index.row(), HASH)).toString(); - } - } - Q_ASSERT(hashes.size() > 0); - new BandwidthAllocationDialog(this, true, BTSession, hashes); -} - 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)); @@ -406,29 +377,19 @@ void GUI::on_actionSet_global_download_limit_triggered() { } void GUI::on_actionPreview_file_triggered() { - if(tabs->currentIndex() > 1) return; - bool inDownloadList = true; - if(tabs->currentIndex()) - inDownloadList = false; - QModelIndex index; - QModelIndexList selectedIndexes; - if(inDownloadList) - selectedIndexes = downloadList->selectionModel()->selectedIndexes(); - else - selectedIndexes = finishedTorrentTab->getFinishedList()->selectionModel()->selectedIndexes(); - foreach(index, selectedIndexes) { - if(index.column() == NAME) { - // Get the file hash - QString hash; - if(inDownloadList) - hash = DLListModel->data(DLListModel->index(index.row(), HASH)).toString(); - else - hash = finishedTorrentTab->getFinishedListModel()->data(finishedTorrentTab->getFinishedListModel()->index(index.row(), F_HASH)).toString(); - QTorrentHandle h = BTSession->getTorrentHandle(hash); - previewSelection = new previewSelect(this, h); + 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::cleanTempPreviewFile(int, QProcess::ExitStatus) { @@ -437,52 +398,6 @@ void GUI::cleanTempPreviewFile(int, QProcess::ExitStatus) { } } -void GUI::displayDLListMenu(const QPoint& pos) { - QMenu myDLLlistMenu(this); - QModelIndex index; - // Enable/disable pause/start action given the DL state - QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes(); - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - QString previewProgram = settings.value(QString::fromUtf8("Options/Misc/PreviewProgram"), QString()).toString(); - bool has_pause = false, has_start = false, has_preview = false; - foreach(index, selectedIndexes) { - if(index.column() == NAME) { - // Get the file name - QString hash = DLListModel->data(DLListModel->index(index.row(), HASH)).toString(); - // Get handle and pause the torrent - QTorrentHandle h = BTSession->getTorrentHandle(hash); - if(!h.is_valid()) continue; - if(h.is_paused()) { - if(!has_start) { - myDLLlistMenu.addAction(actionStart); - has_start = true; - } - }else{ - if(!has_pause) { - myDLLlistMenu.addAction(actionPause); - has_pause = true; - } - } - if(!previewProgram.isEmpty() && BTSession->isFilePreviewPossible(hash) && !has_preview) { - myDLLlistMenu.addAction(actionPreview_file); - has_preview = true; - } - if(has_pause && has_start && has_preview) break; - } - } - myDLLlistMenu.addSeparator(); - myDLLlistMenu.addAction(actionDelete); - myDLLlistMenu.addAction(actionDelete_Permanently); - myDLLlistMenu.addSeparator(); - myDLLlistMenu.addAction(actionSet_download_limit); - myDLLlistMenu.addAction(actionSet_upload_limit); - myDLLlistMenu.addSeparator(); - myDLLlistMenu.addAction(actionTorrent_Properties); - // Call menu - // XXX: why mapToGlobal() is not enough? - myDLLlistMenu.exec(mapToGlobal(pos)+QPoint(22,180)); -} - // Necessary if we want to close the window // in one time if "close to systray" is enabled void GUI::on_actionExit_triggered() { @@ -493,7 +408,7 @@ void GUI::on_actionExit_triggered() { void GUI::previewFile(QString filePath) { // Check if there is already one preview running if(previewProcess->state() == QProcess::NotRunning) { - // First copy temporarily + // First copy temporarily (XXX: is it necessary?) QString tmpPath = QDir::tempPath()+QDir::separator()+QString::fromUtf8("qBT_preview.tmp"); QFile::remove(tmpPath); QFile::copy(filePath, tmpPath); @@ -508,257 +423,16 @@ void GUI::previewFile(QString filePath) { } } -void GUI::on_actionClearLog_triggered() { - infoBar->clear(); -} - -void GUI::displayInfoBarMenu(const QPoint& pos) { - // Log Menu - QMenu myLogMenu(this); - myLogMenu.addAction(actionClearLog); - // XXX: Why mapToGlobal() is not enough? - myLogMenu.exec(mapToGlobal(pos)+QPoint(22,383)); -} - -void GUI::sortProgressColumnDelayed() { - if(delayedSorting) { - sortDownloadListFloat(PROGRESS, delayedSortingOrder); - qDebug("Delayed sorting of progress column"); - } -} - -// get information from torrent handles and -// update download list accordingly -void GUI::updateDlList(bool force) { - char tmp[MAX_CHAR_TMP]; - char tmp2[MAX_CHAR_TMP]; - // update global informations - snprintf(tmp, MAX_CHAR_TMP, "%.1f", BTSession->getPayloadUploadRate()/1024.); - snprintf(tmp2, MAX_CHAR_TMP, "%.1f", BTSession->getPayloadDownloadRate()/1024.); - if(systrayIntegration) { - myTrayIcon->setToolTip(QString::fromUtf8("")+tr("qBittorrent")+QString::fromUtf8("
")+tr("DL speed: %1 KiB/s", "e.g: Download speed: 10 KiB/s").arg(QString::fromUtf8(tmp2))+QString::fromUtf8("
")+tr("UP speed: %1 KiB/s", "e.g: Upload speed: 10 KiB/s").arg(QString::fromUtf8(tmp))); // tray icon - } - if(getCurrentTabIndex() == 1) { - finishedTorrentTab->updateFinishedList(); - return; - } - if(!force && getCurrentTabIndex() != 0) { - // No need to update if qBittorrent DL list is hidden - return; - } - //BTSession->printPausedTorrents(); - LCD_UpSpeed->display(QString::fromUtf8(tmp)); // UP LCD - LCD_DownSpeed->display(QString::fromUtf8(tmp2)); // DL LCD - // browse handles - QStringList unfinishedTorrents = BTSession->getUnfinishedTorrents(); - QString hash; - foreach(hash, unfinishedTorrents) { - QTorrentHandle h = BTSession->getTorrentHandle(hash); - if(!h.is_valid()){ - qDebug("We have an invalid handle for: %s", qPrintable(hash)); - continue; - } - try{ - QString hash = h.hash(); - int row = getRowFromHash(hash); - if(row == -1) { - qDebug("Info: Could not find filename in download list, adding it..."); - restoreInDownloadList(h); - row = getRowFromHash(hash); - } - Q_ASSERT(row != -1); - // No need to update a paused torrent - if(h.is_paused()) continue; - // Parse download state - // Setting download state - switch(h.state()) { - case torrent_status::finished: - case torrent_status::seeding: - qDebug("A torrent that was in download tab just finished, moving it to finished tab"); - BTSession->setFinishedTorrent(hash); - finishedTorrent(h); - continue; - case torrent_status::checking_files: - case torrent_status::queued_for_checking: - if(BTSession->getTorrentsToPauseAfterChecking().indexOf(hash) == -1) { - DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/time.png"))), Qt::DecorationRole); - setRowColor(row, QString::fromUtf8("grey")); - Q_ASSERT(h.progress() <= 1. && h.progress() >= 0.); - DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)h.progress())); - } - break; - case torrent_status::connecting_to_tracker: - if(h.download_payload_rate() > 0) { - // Display "Downloading" status when connecting if download speed > 0 - DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)BTSession->getETA(hash))); - DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png"))), Qt::DecorationRole); - setRowColor(row, QString::fromUtf8("green")); - }else{ - DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1)); - DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/connecting.png"))), Qt::DecorationRole); - setRowColor(row, QString::fromUtf8("grey")); - } - Q_ASSERT(h.progress() <= 1. && h.progress() >= 0.); - DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)h.progress())); - DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)h.download_payload_rate())); - DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)h.upload_payload_rate())); - break; - case torrent_status::downloading: - case torrent_status::downloading_metadata: - if(h.download_payload_rate() > 0) { - DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png"))), Qt::DecorationRole); - DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)BTSession->getETA(hash))); - setRowColor(row, QString::fromUtf8("green")); - }else{ - DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/stalled.png"))), Qt::DecorationRole); - DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1)); - setRowColor(row, QString::fromUtf8("black")); - } - Q_ASSERT(h.progress() <= 1. && h.progress() >= 0.); - DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)h.progress())); - DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)h.download_payload_rate())); - DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)h.upload_payload_rate())); - break; - default: - DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1)); - } - DLListModel->setData(DLListModel->index(row, SEEDSLEECH), QVariant(misc::toQString(h.num_seeds(), true)+QString::fromUtf8("/")+misc::toQString(h.num_peers() - h.num_seeds(), true))); - DLListModel->setData(DLListModel->index(row, RATIO), QVariant(misc::toQString(BTSession->getRealRatio(hash)))); - }catch(invalid_handle e) { - continue; - } - } -} - unsigned int GUI::getCurrentTabIndex() const{ if(isMinimized() || isHidden()) return -1; return tabs->currentIndex(); } -void GUI::restoreInDownloadList(QTorrentHandle h) { - QString hash = h.hash(); - int row = getRowFromHash(hash); - if(row != -1) return; - row = DLListModel->rowCount(); - // Adding torrent to download list - DLListModel->insertRow(row); - DLListModel->setData(DLListModel->index(row, NAME), QVariant(h.name())); - DLListModel->setData(DLListModel->index(row, SIZE), QVariant((qlonglong)h.actual_size())); - DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)0.)); - DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)0.)); - DLListModel->setData(DLListModel->index(row, SEEDSLEECH), QVariant(QString::fromUtf8("0/0"))); - DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1)); - DLListModel->setData(DLListModel->index(row, HASH), QVariant(hash)); - // Pause torrent if it was paused last time - if(BTSession->isPaused(hash)) { - DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/paused.png"))), Qt::DecorationRole); - setRowColor(row, QString::fromUtf8("red")); - }else{ - DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/connecting.png"))), Qt::DecorationRole); - setRowColor(row, QString::fromUtf8("grey")); - } - ++nbTorrents; -} - void GUI::setTabText(int index, QString text) { tabs->setTabText(index, text); } -void GUI::sortDownloadListFloat(int index, Qt::SortOrder sortOrder) { - QList > lines; - // insertion sorting - unsigned int nbRows = DLListModel->rowCount(); - for(unsigned int i=0; i(i, DLListModel->data(DLListModel->index(i, index)).toDouble()), sortOrder); - } - // Insert items in new model, in correct order - unsigned int nbRows_old = lines.size(); - for(unsigned int row=0; rowinsertRow(DLListModel->rowCount()); - unsigned int sourceRow = lines[row].first; - unsigned int nbColumns = DLListModel->columnCount(); - for(unsigned int col=0; colsetData(DLListModel->index(nbRows_old+row, col), DLListModel->data(DLListModel->index(sourceRow, col))); - DLListModel->setData(DLListModel->index(nbRows_old+row, col), DLListModel->data(DLListModel->index(sourceRow, col), Qt::DecorationRole), Qt::DecorationRole); - DLListModel->setData(DLListModel->index(nbRows_old+row, col), DLListModel->data(DLListModel->index(sourceRow, col), Qt::ForegroundRole), Qt::ForegroundRole); - } - } - // Remove old rows - DLListModel->removeRows(0, nbRows_old); -} - -void GUI::sortDownloadListString(int index, Qt::SortOrder sortOrder) { - QList > lines; - // Insertion sorting - unsigned int nbRows = DLListModel->rowCount(); - for(unsigned int i=0; i(i, DLListModel->data(DLListModel->index(i, index)).toString()), sortOrder); - } - // Insert items in new model, in correct order - unsigned int nbRows_old = lines.size(); - for(unsigned int row=0; rowinsertRow(DLListModel->rowCount()); - unsigned int sourceRow = lines[row].first; - unsigned int nbColumns = DLListModel->columnCount(); - for(unsigned int col=0; colsetData(DLListModel->index(nbRows_old+row, col), DLListModel->data(DLListModel->index(sourceRow, col))); - DLListModel->setData(DLListModel->index(nbRows_old+row, col), DLListModel->data(DLListModel->index(sourceRow, col), Qt::DecorationRole), Qt::DecorationRole); - DLListModel->setData(DLListModel->index(nbRows_old+row, col), DLListModel->data(DLListModel->index(sourceRow, col), Qt::ForegroundRole), Qt::ForegroundRole); - } - } - // Remove old rows - DLListModel->removeRows(0, nbRows_old); -} - -void GUI::sortDownloadList(int index, Qt::SortOrder startSortOrder, bool fromLoadColWidth) { - qDebug("Called sort download list"); - static Qt::SortOrder sortOrder = startSortOrder; - if(!fromLoadColWidth && downloadList->header()->sortIndicatorSection() == index) { - if(sortOrder == Qt::AscendingOrder) { - sortOrder = Qt::DescendingOrder; - }else{ - sortOrder = Qt::AscendingOrder; - } - } - QString sortOrderLetter; - if(sortOrder == Qt::AscendingOrder) - sortOrderLetter = QString::fromUtf8("a"); - else - sortOrderLetter = QString::fromUtf8("d"); - if(fromLoadColWidth) { - // XXX: Why is this needed? - if(sortOrder == Qt::DescendingOrder) - downloadList->header()->setSortIndicator(index, Qt::AscendingOrder); - else - downloadList->header()->setSortIndicator(index, Qt::DescendingOrder); - } else { - downloadList->header()->setSortIndicator(index, sortOrder); - } - switch(index) { - case SIZE: - case ETA: - case UPSPEED: - case DLSPEED: - sortDownloadListFloat(index, sortOrder); - break; - case PROGRESS: - if(fromLoadColWidth) { - // Progress sorting must be delayed until files are checked (on startup) - delayedSorting = true; - qDebug("Delayed sorting of the progress column"); - delayedSortingOrder = sortOrder; - }else{ - sortDownloadListFloat(index, sortOrder); - } - break; - default: - sortDownloadListString(index, sortOrder); - } - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - settings.setValue(QString::fromUtf8("DownloadListSortedCol"), misc::toQString(index)+sortOrderLetter); -} - // Toggle Main window visibility void GUI::toggleVisibility(QSystemTrayIcon::ActivationReason e) { if(e == QSystemTrayIcon::Trigger || e == QSystemTrayIcon::DoubleClick) { @@ -795,57 +469,10 @@ QPoint GUI::screenCenter() const{ return QPoint((desk.width() - this->frameGeometry().width()) / 2, (desk.height() - this->frameGeometry().height()) / 2); } -// Save columns width in a file to remember them -// (download list) -void GUI::saveColWidthDLList() const{ - qDebug("Saving columns width in download list"); - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - QStringList width_list; - unsigned int nbColumns = DLListModel->columnCount()-1; - for(unsigned int i=0; icolumnWidth(i)); - } - settings.setValue(QString::fromUtf8("DownloadListColsWidth"), width_list.join(QString::fromUtf8(" "))); - qDebug("Download list columns width saved"); -} - -// Load columns width in a file that were saved previously -// (download list) -bool GUI::loadColWidthDLList() { - qDebug("Loading columns width for download list"); - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - QString line = settings.value(QString::fromUtf8("DownloadListColsWidth"), QString()).toString(); - if(line.isEmpty()) - return false; - QStringList width_list = line.split(QString::fromUtf8(" ")); - if(width_list.size() != DLListModel->columnCount()-1) { - qDebug("Corrupted values for download list columns sizes"); - return false; - } - unsigned int listSize = width_list.size(); - for(unsigned int i=0; iheader()->resizeSection(i, width_list.at(i).toInt()); - } - // Loading last sorted column - QString sortedCol = settings.value(QString::fromUtf8("DownloadListSortedCol"), QString()).toString(); - if(!sortedCol.isEmpty()) { - Qt::SortOrder sortOrder; - if(sortedCol.endsWith(QString::fromUtf8("d"))) - sortOrder = Qt::DescendingOrder; - else - sortOrder = Qt::AscendingOrder; - sortedCol = sortedCol.left(sortedCol.size()-1); - int index = sortedCol.toInt(); - sortDownloadList(index, sortOrder, true); - } - qDebug("Download list columns width loaded"); - return true; -} - // Display About Dialog void GUI::on_actionAbout_triggered() { //About dialog - aboutdlg = new about(this); + new about(this); } // Called when we close the program @@ -858,7 +485,7 @@ void GUI::closeEvent(QCloseEvent *e) { e->ignore(); return; } - if(settings.value(QString::fromUtf8("Options/Misc/Behaviour/ConfirmOnExit"), true).toBool() && nbTorrents != 0) { + if(settings.value(QString::fromUtf8("Options/Misc/Behaviour/ConfirmOnExit"), true).toBool() && downloadingTorrentTab->getNbTorrentsInList()) { show(); if(!isMaximized()) showNormal(); @@ -878,7 +505,6 @@ void GUI::closeEvent(QCloseEvent *e) { } // Save window size, columns size writeSettings(); - saveColWidthDLList(); // Accept exit e->accept(); qApp->exit(); @@ -886,7 +512,7 @@ void GUI::closeEvent(QCloseEvent *e) { // Display window to create a torrent void GUI::on_actionCreate_torrent_triggered() { - createWindow = new createtorrent(this); + new createtorrent(this); } // Called when we minimize the program @@ -917,7 +543,7 @@ void GUI::dropEvent(QDropEvent *event) { if(useTorrentAdditionDialog) { torrentAdditionDialog *dialog = new torrentAdditionDialog(this); connect(dialog, SIGNAL(torrentAddition(QString, bool, QString)), BTSession, SLOT(addTorrent(QString, bool, QString))); - connect(dialog, SIGNAL(setInfoBarGUI(QString, QString)), this, SLOT(setInfoBar(QString, QString))); + connect(dialog, SIGNAL(setInfoBarGUI(QString, QString)), downloadingTorrentTab, SLOT(setInfoBar(QString, QString))); dialog->showLoad(file); }else{ BTSession->addTorrent(file); @@ -956,7 +582,7 @@ void GUI::on_actionOpen_triggered() { if(useTorrentAdditionDialog) { torrentAdditionDialog *dialog = new torrentAdditionDialog(this); connect(dialog, SIGNAL(torrentAddition(QString, bool, QString)), BTSession, SLOT(addTorrent(QString, bool, QString))); - connect(dialog, SIGNAL(setInfoBarGUI(QString, QString)), this, SLOT(setInfoBar(QString, QString))); + connect(dialog, SIGNAL(setInfoBarGUI(QString, QString)), downloadingTorrentTab, SLOT(setInfoBar(QString, QString))); dialog->showLoad(pathsList.at(i)); }else{ BTSession->addTorrent(pathsList.at(i)); @@ -971,194 +597,108 @@ void GUI::on_actionOpen_triggered() { // delete from download list AND from hard drive void GUI::on_actionDelete_Permanently_triggered() { - if(tabs->currentIndex() > 1) return; - QModelIndexList selectedIndexes; - bool inDownloadList; - if(tabs->currentIndex() == 0) { - selectedIndexes = downloadList->selectionModel()->selectedIndexes(); - inDownloadList = true; - } else { - selectedIndexes = finishedTorrentTab->getFinishedList()->selectionModel()->selectedIndexes(); - inDownloadList = false; - } - if(!selectedIndexes.isEmpty()) { - int ret; + QStringList hashes; + bool inDownloadList = true; + switch(tabs->currentIndex()){ + case 0: + hashes = downloadingTorrentTab->getSelectedTorrents(); + break; + case 1: + hashes = finishedTorrentTab->getSelectedTorrents(); + inDownloadList = false; + 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 + QString hash; + foreach(hash, hashes) { + // Get the file name + QTorrentHandle h = BTSession->getTorrentHandle(hash); + QString fileName = h.name(); + // Remove the torrent + BTSession->deleteTorrent(hash, true); + // Delete item from list 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 == 0) { - //User clicked YES - QModelIndex index; - QStringList hashesToDelete; - foreach(index, selectedIndexes) { - if(index.column() == NAME) { - if(inDownloadList) - hashesToDelete << DLListModel->data(DLListModel->index(index.row(), HASH)).toString(); - else - hashesToDelete << finishedTorrentTab->getFinishedListModel()->data(finishedTorrentTab->getFinishedListModel()->index(index.row(), F_HASH)).toString(); - } - } - QString hash; - foreach(hash, hashesToDelete) { - // Get the file name & hash - QString fileName; - int row = -1; - if(inDownloadList) { - row = getRowFromHash(hash); - fileName = DLListModel->data(DLListModel->index(row, NAME)).toString(); - }else{ - row = finishedTorrentTab->getRowFromHash(hash); - fileName = finishedTorrentTab->getFinishedListModel()->data(finishedTorrentTab->getFinishedListModel()->index(row, F_NAME)).toString(); - } - Q_ASSERT(row != -1); - // Remove the torrent - BTSession->deleteTorrent(hash, true); - // Delete item from download list - if(inDownloadList) { - DLListModel->removeRow(row); - --nbTorrents; - tabs->setTabText(0, tr("Downloads") +QString::fromUtf8(" (")+misc::toQString(nbTorrents)+QString::fromUtf8(")")); - } else { - finishedTorrentTab->deleteFromFinishedList(hash, false); - } - // Update info bar - setInfoBar(tr("'%1' was removed permanently.", "'xxx.avi' was removed permanently.").arg(fileName)); - } + downloadingTorrentTab->deleteTorrent(hash); + } else { + finishedTorrentTab->deleteTorrent(hash); } + // Update info bar + downloadingTorrentTab->setInfoBar(tr("'%1' was removed permanently.", "'xxx.avi' was removed permanently.").arg(fileName)); } } // delete selected items in the list void GUI::on_actionDelete_triggered() { - if(tabs->currentIndex() == 2) return; // No deletion in search tab - if(tabs->currentIndex() == 3) { - rssWidget->on_delStream_button_clicked(); - return; - } - QModelIndexList selectedIndexes; - bool inDownloadList; - if(tabs->currentIndex() == 0) { - selectedIndexes = downloadList->selectionModel()->selectedIndexes(); - inDownloadList = true; + QStringList hashes; + bool inDownloadList = true; + switch(tabs->currentIndex()){ + case 3: //RSSImp + rssWidget->on_delStream_button_clicked(); + return; + case 0: // DL + hashes = downloadingTorrentTab->getSelectedTorrents(); + break; + case 1: // SEED + hashes = finishedTorrentTab->getSelectedTorrents(); + inDownloadList = false; + break; + 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 { - selectedIndexes = finishedTorrentTab->getFinishedList()->selectionModel()->selectedIndexes(); - inDownloadList = false; - } - if(!selectedIndexes.isEmpty()) { - int ret; + 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 + QString hash; + foreach(hash, hashes) { + // Get the file name + QTorrentHandle h = BTSession->getTorrentHandle(hash); + QString fileName = h.name(); + // Remove the torrent + BTSession->deleteTorrent(hash, false); + // Delete item from list 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); + downloadingTorrentTab->deleteTorrent(hash); } 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); + finishedTorrentTab->deleteTorrent(hash); } - if(ret == 0) { - //User clicked YES - QModelIndex index; - QStringList hashesToDelete; - foreach(index, selectedIndexes) { - if(index.column() == NAME) { - if(inDownloadList) - hashesToDelete << DLListModel->data(DLListModel->index(index.row(), HASH)).toString(); - else - hashesToDelete << finishedTorrentTab->getFinishedListModel()->data(finishedTorrentTab->getFinishedListModel()->index(index.row(), F_HASH)).toString(); - } - } - QString hash; - foreach(hash, hashesToDelete) { - // Get the file name & hash - QString fileName; - int row = -1; - if(inDownloadList) { - row = getRowFromHash(hash); - fileName = DLListModel->data(DLListModel->index(row, NAME)).toString(); - }else{ - row = finishedTorrentTab->getRowFromHash(hash); - fileName = finishedTorrentTab->getFinishedListModel()->data(finishedTorrentTab->getFinishedListModel()->index(row, F_NAME)).toString(); - } - Q_ASSERT(row != -1); - // Remove the torrent - BTSession->deleteTorrent(hash, false); - // Delete item from download list - if(inDownloadList) { - DLListModel->removeRow(row); - --nbTorrents; - tabs->setTabText(0, tr("Downloads") +QString::fromUtf8(" (")+misc::toQString(nbTorrents)+QString::fromUtf8(")")); - } else { - finishedTorrentTab->deleteFromFinishedList(hash, false); - } - // Update info bar - setInfoBar(tr("'%1' was removed.", "'xxx.avi' was removed.").arg(fileName)); - } - } - } -} - -// Called when a torrent is added -void GUI::torrentAdded(QString path, QTorrentHandle& h, bool fastResume) { - QString hash = h.hash(); - if(BTSession->isFinished(hash)) { - finishedTorrentTab->addFinishedTorrent(hash); - return; - } - int row = DLListModel->rowCount(); - // Adding torrent to download list - DLListModel->insertRow(row); - DLListModel->setData(DLListModel->index(row, NAME), QVariant(h.name())); - DLListModel->setData(DLListModel->index(row, SIZE), QVariant((qlonglong)h.actual_size())); - DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)0.)); - DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)0.)); - DLListModel->setData(DLListModel->index(row, SEEDSLEECH), QVariant(QString::fromUtf8("0/0"))); - DLListModel->setData(DLListModel->index(row, RATIO), QVariant(misc::toQString(BTSession->getRealRatio(hash)))); - DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1)); - DLListModel->setData(DLListModel->index(row, HASH), QVariant(hash)); - // Pause torrent if it was paused last time - // Not using isPaused function because torrents are paused after checking now - if(QFile::exists(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".paused"))) { - DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/paused.png"))), Qt::DecorationRole); - setRowColor(row, QString::fromUtf8("red")); - }else{ - DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/connecting.png"))), Qt::DecorationRole); - setRowColor(row, QString::fromUtf8("grey")); - } - if(!fastResume) { - setInfoBar(tr("'%1' added to download list.", "'/home/y/xxx.torrent' was added to download list.").arg(path)); - }else{ - setInfoBar(tr("'%1' resumed. (fast resume)", "'/home/y/xxx.torrent' was resumed. (fast resume)").arg(path)); + // Update info bar + downloadingTorrentTab->setInfoBar(tr("'%1' was removed.", "'xxx.avi' was removed.").arg(fileName)); } - ++nbTorrents; - tabs->setTabText(0, tr("Downloads") +QString::fromUtf8(" (")+misc::toQString(nbTorrents)+QString::fromUtf8(")")); -} - -// Called when trying to add a duplicate torrent -void GUI::torrentDuplicate(QString path) { - setInfoBar(tr("'%1' is already in download list.", "e.g: 'xxx.avi' is already in download list.").arg(path)); -} - -void GUI::torrentCorrupted(QString path) { - setInfoBar(tr("Unable to decode torrent file: '%1'", "e.g: Unable to decode torrent file: '/home/y/xxx.torrent'").arg(path), QString::fromUtf8("red")); - setInfoBar(tr("This file is either corrupted or this isn't a torrent."),QString::fromUtf8("red")); } // As program parameters, we can get paths or urls. @@ -1177,7 +717,7 @@ void GUI::processParams(const QStringList& params) { if(useTorrentAdditionDialog) { torrentAdditionDialog *dialog = new torrentAdditionDialog(this); connect(dialog, SIGNAL(torrentAddition(QString, bool, QString)), BTSession, SLOT(addTorrent(QString, bool, QString))); - connect(dialog, SIGNAL(setInfoBarGUI(QString, QString)), this, SLOT(setInfoBar(QString, QString))); + connect(dialog, SIGNAL(setInfoBarGUI(QString, QString)), downloadingTorrentTab, SLOT(setInfoBar(QString, QString))); dialog->showLoad(param); }else{ BTSession->addTorrent(param); @@ -1194,7 +734,7 @@ void GUI::processScannedFiles(const QStringList& params) { if(useTorrentAdditionDialog) { torrentAdditionDialog *dialog = new torrentAdditionDialog(this); connect(dialog, SIGNAL(torrentAddition(QString, bool, QString)), BTSession, SLOT(addTorrent(QString, bool, QString))); - connect(dialog, SIGNAL(setInfoBarGUI(QString, QString)), this, SLOT(setInfoBar(QString, QString))); + connect(dialog, SIGNAL(setInfoBarGUI(QString, QString)), downloadingTorrentTab, SLOT(setInfoBar(QString, QString))); dialog->showLoad(param, true); }else{ BTSession->addTorrent(param, true); @@ -1208,32 +748,13 @@ void GUI::processDownloadedFiles(QString path, QString url) { if(useTorrentAdditionDialog) { torrentAdditionDialog *dialog = new torrentAdditionDialog(this); connect(dialog, SIGNAL(torrentAddition(QString, bool, QString)), BTSession, SLOT(addTorrent(QString, bool, QString))); - connect(dialog, SIGNAL(setInfoBarGUI(QString, QString)), this, SLOT(setInfoBar(QString, QString))); + connect(dialog, SIGNAL(setInfoBarGUI(QString, QString)), downloadingTorrentTab, SLOT(setInfoBar(QString, QString))); dialog->showLoad(path, false, url); }else{ BTSession->addTorrent(path, false, url); } } -// Show torrent properties dialog -void GUI::showProperties(const QModelIndex &index) { - int row = index.row(); - QString hash = DLListModel->data(DLListModel->index(row, HASH)).toString(); - QTorrentHandle h = BTSession->getTorrentHandle(hash); - properties *prop = new properties(this, BTSession, h); - connect(prop, SIGNAL(filteredFilesChanged(QString)), this, SLOT(updateFileSizeAndProgress(QString))); - prop->show(); -} - -void GUI::updateFileSizeAndProgress(QString hash) { - int row = getRowFromHash(hash); - Q_ASSERT(row != -1); - QTorrentHandle h = BTSession->getTorrentHandle(hash); - DLListModel->setData(DLListModel->index(row, SIZE), QVariant((qlonglong)h.actual_size())); - Q_ASSERT(h.progress() <= 1.); - DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)h.progress())); -} - // Set BT session configuration void GUI::configureSession(bool deleteOptions) { qDebug("Configuring session"); @@ -1248,7 +769,7 @@ void GUI::configureSession(bool deleteOptions) { BTSession->setListeningPortsRange(options->getPorts()); new_listenPort = BTSession->getListenPort(); if(new_listenPort != old_listenPort) { - setInfoBar(tr("qBittorrent is bind to port: %1", "e.g: qBittorrent is bind to port: 1666").arg( misc::toQString(new_listenPort))); + downloadingTorrentTab->setInfoBar(tr("qBittorrent is bind to port: %1", "e.g: qBittorrent is bind to port: 1666").arg( misc::toQString(new_listenPort))); } // Apply max connec limit (-1 if disabled) BTSession->setMaxConnections(options->getMaxConnec()); @@ -1273,16 +794,16 @@ void GUI::configureSession(bool deleteOptions) { BTSession->setGlobalRatio(options->getRatio()); // DHT (Trackerless) if(options->isDHTEnabled()) { - setInfoBar(tr("DHT support [ON], port: %1").arg(options->getDHTPort()), QString::fromUtf8("blue")); + downloadingTorrentTab->setInfoBar(tr("DHT support [ON], port: %1").arg(options->getDHTPort()), QString::fromUtf8("blue")); BTSession->enableDHT(); // Set DHT Port BTSession->setDHTPort(options->getDHTPort()); }else{ - setInfoBar(tr("DHT support [OFF]"), QString::fromUtf8("blue")); + downloadingTorrentTab->setInfoBar(tr("DHT support [OFF]"), QString::fromUtf8("blue")); BTSession->disableDHT(); } // UPnP can't be disabled - setInfoBar(tr("UPnP support [ON]"), QString::fromUtf8("blue")); + downloadingTorrentTab->setInfoBar(tr("UPnP support [ON]"), QString::fromUtf8("blue")); // Encryption settings int encryptionState = options->getEncryptionSetting(); // The most secure, rc4 only so that all streams and encrypted @@ -1292,36 +813,35 @@ void GUI::configureSession(bool deleteOptions) { case 0: //Enabled encryptionSettings.out_enc_policy = pe_settings::enabled; encryptionSettings.in_enc_policy = pe_settings::enabled; - setInfoBar(tr("Encryption support [ON]"), QString::fromUtf8("blue")); + downloadingTorrentTab->setInfoBar(tr("Encryption support [ON]"), QString::fromUtf8("blue")); break; case 1: // Forced encryptionSettings.out_enc_policy = pe_settings::forced; encryptionSettings.in_enc_policy = pe_settings::forced; - setInfoBar(tr("Encryption support [FORCED]"), QString::fromUtf8("blue")); + downloadingTorrentTab->setInfoBar(tr("Encryption support [FORCED]"), QString::fromUtf8("blue")); break; default: // Disabled encryptionSettings.out_enc_policy = pe_settings::disabled; encryptionSettings.in_enc_policy = pe_settings::disabled; - setInfoBar(tr("Encryption support [OFF]"), QString::fromUtf8("blue")); + downloadingTorrentTab->setInfoBar(tr("Encryption support [OFF]"), QString::fromUtf8("blue")); } BTSession->applyEncryptionSettings(encryptionSettings); // PeX if(!options->isPeXDisabled()) { qDebug("Enabling Peer eXchange (PeX)"); - setInfoBar(tr("PeX support [ON]"), QString::fromUtf8("blue")); + downloadingTorrentTab->setInfoBar(tr("PeX support [ON]"), QString::fromUtf8("blue")); BTSession->enablePeerExchange(); }else{ - setInfoBar(tr("PeX support [OFF]"), QString::fromUtf8("blue")); + downloadingTorrentTab->setInfoBar(tr("PeX support [OFF]"), QString::fromUtf8("blue")); qDebug("Peer eXchange (PeX) disabled"); } // Apply filtering settings if(options->isFilteringEnabled()) { BTSession->enableIPFilter(options->getFilter()); - tabBottom->setTabEnabled(1, true); + downloadingTorrentTab->setBottomTabEnabled(1, true); }else{ BTSession->disableIPFilter(); - tabBottom->setCurrentIndex(0); - tabBottom->setTabEnabled(1, false); + downloadingTorrentTab->setBottomTabEnabled(1, false); } // Apply Proxy settings if(options->isProxyEnabled()) { @@ -1360,196 +880,140 @@ void GUI::configureSession(bool deleteOptions) { qDebug("Session configured"); } +void GUI::updateUnfinishedTorrentNumber(unsigned int nb) { + tabs->setTabText(0, tr("Downloads") +QString::fromUtf8(" (")+misc::toQString(nb)+QString::fromUtf8(")")); +} + +void GUI::updateFinishedTorrentNumber(unsigned int nb) { + tabs->setTabText(1, tr("Finished") +QString::fromUtf8(" (")+misc::toQString(nb)+QString::fromUtf8(")")); +} + // Toggle paused state of selected torrent -void GUI::togglePausedState(const QModelIndex& index) { - int row = index.row(); - bool inDownloadList = true; +void GUI::togglePausedState(QString hash) { if(tabs->currentIndex() > 1) return; + bool inDownloadList = true; if(tabs->currentIndex() == 1) inDownloadList = false; - QString hash; - if(inDownloadList) - hash = DLListModel->data(DLListModel->index(row, HASH)).toString(); - else - hash = finishedTorrentTab->getFinishedListModel()->data(finishedTorrentTab->getFinishedListModel()->index(row, F_HASH)).toString(); + QTorrentHandle h = BTSession->getTorrentHandle(hash); if(BTSession->isPaused(hash)) { BTSession->resumeTorrent(hash); - setInfoBar(tr("'%1' resumed.", "e.g: xxx.avi resumed.").arg(BTSession->getTorrentHandle(hash).name())); + downloadingTorrentTab->setInfoBar(tr("'%1' resumed.", "e.g: xxx.avi resumed.").arg(h.name())); if(inDownloadList) { - DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/connecting.png"))), Qt::DecorationRole); - setRowColor(row, QString::fromUtf8("grey")); + downloadingTorrentTab->resumeTorrent(hash); }else{ - finishedTorrentTab->getFinishedListModel()->setData(finishedTorrentTab->getFinishedListModel()->index(row, F_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/seeding.png"))), Qt::DecorationRole); - finishedTorrentTab->setRowColor(row, QString::fromUtf8("orange")); + finishedTorrentTab->resumeTorrent(hash); } }else{ BTSession->pauseTorrent(hash); if(inDownloadList) { - DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)0.0)); - DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)0.0)); - DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1)); - DLListModel->setData(DLListModel->index(row, NAME), QIcon(QString::fromUtf8(":/Icons/skin/paused.png")), Qt::DecorationRole); - DLListModel->setData(DLListModel->index(row, SEEDSLEECH), QVariant(QString::fromUtf8("0/0"))); - setRowColor(row, QString::fromUtf8("red")); + downloadingTorrentTab->pauseTorrent(hash); }else{ - finishedTorrentTab->getFinishedListModel()->setData(finishedTorrentTab->getFinishedListModel()->index(row, F_UPSPEED), QVariant((double)0.0)); - finishedTorrentTab->getFinishedListModel()->setData(finishedTorrentTab->getFinishedListModel()->index(row, F_NAME), QIcon(QString::fromUtf8(":/Icons/skin/paused.png")), Qt::DecorationRole); - finishedTorrentTab->getFinishedListModel()->setData(finishedTorrentTab->getFinishedListModel()->index(row, F_SEEDSLEECH), QVariant(QString::fromUtf8("0/0"))); - setRowColor(row, QString::fromUtf8("red")); + finishedTorrentTab->pauseTorrent(hash); } - setInfoBar(tr("'%1' paused.", "xxx.avi paused.").arg(BTSession->getTorrentHandle(hash).name())); + downloadingTorrentTab->setInfoBar(tr("'%1' paused.", "xxx.avi paused.").arg(h.name())); } } // Pause All Downloads in DL list void GUI::on_actionPause_All_triggered() { - QString hash; bool change = false; bool inDownloadList = true; if(tabs->currentIndex() > 1) return; if(tabs->currentIndex() == 1) inDownloadList = false; - unsigned int nbRows; - if(inDownloadList) - nbRows = DLListModel->rowCount(); - else - nbRows = finishedTorrentTab->getFinishedListModel()->rowCount(); - for(unsigned int i=0; idata(DLListModel->index(i, HASH)).toString(); - else - hash = finishedTorrentTab->getFinishedListModel()->data(finishedTorrentTab->getFinishedListModel()->index(i, F_HASH)).toString(); - if(BTSession->pauseTorrent(hash)) { - if(inDownloadList) { - // Update DL list items - DLListModel->setData(DLListModel->index(i, DLSPEED), QVariant((double)0.)); - DLListModel->setData(DLListModel->index(i, UPSPEED), QVariant((double)0.)); - DLListModel->setData(DLListModel->index(i, ETA), QVariant((qlonglong)-1)); - DLListModel->setData(DLListModel->index(i, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/paused.png"))), Qt::DecorationRole); - DLListModel->setData(DLListModel->index(i, SEEDSLEECH), QVariant(QString::fromUtf8("0/0"))); - setRowColor(i, QString::fromUtf8("red")); - }else{ - // Update finished list items - finishedTorrentTab->getFinishedListModel()->setData(finishedTorrentTab->getFinishedListModel()->index(i, F_UPSPEED), QVariant((double)0.)); - finishedTorrentTab->getFinishedListModel()->setData(finishedTorrentTab->getFinishedListModel()->index(i, F_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/paused.png"))), Qt::DecorationRole); - finishedTorrentTab->getFinishedListModel()->setData(finishedTorrentTab->getFinishedListModel()->index(i, F_SEEDSLEECH), QVariant(QString::fromUtf8("0/0"))); - finishedTorrentTab->setRowColor(i, QString::fromUtf8("red")); - } + QStringList hashes; + if(inDownloadList) { + hashes = BTSession->getUnfinishedTorrents(); + } else { + hashes = BTSession->getFinishedTorrents(); + } + QString hash; + foreach(hash, hashes) { + if(BTSession->pauseTorrent(hash)){ change = true; + if(inDownloadList) + downloadingTorrentTab->pauseTorrent(hash); + else + finishedTorrentTab->pauseTorrent(hash); } } if(change) - setInfoBar(tr("All downloads were paused.")); + downloadingTorrentTab->setInfoBar(tr("All downloads were paused.")); } // pause selected items in the list void GUI::on_actionPause_triggered() { - QModelIndexList selectedIndexes; bool inDownloadList = true; if(tabs->currentIndex() > 1) return; if(tabs->currentIndex() == 1) inDownloadList = false; - if (inDownloadList) - selectedIndexes = downloadList->selectionModel()->selectedIndexes(); - else - selectedIndexes = finishedTorrentTab->getFinishedList()->selectionModel()->selectedIndexes(); - QModelIndex index; - foreach(index, selectedIndexes) { - if(index.column() == NAME) { - // Get the file name - QString hash; - if(inDownloadList) - hash = DLListModel->data(DLListModel->index(index.row(), HASH)).toString(); - else - hash = finishedTorrentTab->getFinishedListModel()->data(finishedTorrentTab->getFinishedListModel()->index(index.row(), F_HASH)).toString(); - if(BTSession->pauseTorrent(hash)) { - // Update DL status - int row = index.row(); - if(inDownloadList) { - DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)0.0)); - DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)0.0)); - DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1)); - DLListModel->setData(DLListModel->index(row, NAME), QIcon(QString::fromUtf8(":/Icons/skin/paused.png")), Qt::DecorationRole); - DLListModel->setData(DLListModel->index(row, SEEDSLEECH), QVariant(QString::fromUtf8("0/0"))); - setRowColor(row, QString::fromUtf8("red")); - }else{ - finishedTorrentTab->getFinishedListModel()->setData(finishedTorrentTab->getFinishedListModel()->index(row, F_UPSPEED), QVariant((double)0.0)); - finishedTorrentTab->getFinishedListModel()->setData(finishedTorrentTab->getFinishedListModel()->index(row, F_NAME), QIcon(QString::fromUtf8(":/Icons/skin/paused.png")), Qt::DecorationRole); - finishedTorrentTab->getFinishedListModel()->setData(finishedTorrentTab->getFinishedListModel()->index(row, F_SEEDSLEECH), QVariant(QString::fromUtf8("0/0"))); - finishedTorrentTab->setRowColor(row, QString::fromUtf8("red")); - } - setInfoBar(tr("'%1' paused.", "xxx.avi paused.").arg(BTSession->getTorrentHandle(hash).name())); + QStringList hashes; + if(inDownloadList) { + hashes = downloadingTorrentTab->getSelectedTorrents(); + } else { + hashes = finishedTorrentTab->getSelectedTorrents(); + } + QString hash; + foreach(hash, hashes) { + if(BTSession->pauseTorrent(hash)){ + if(inDownloadList) { + downloadingTorrentTab->pauseTorrent(hash); + } else { + finishedTorrentTab->pauseTorrent(hash); } + downloadingTorrentTab->setInfoBar(tr("'%1' paused.", "xxx.avi paused.").arg(BTSession->getTorrentHandle(hash).name())); } } } // Resume All Downloads in DL list void GUI::on_actionStart_All_triggered() { - QString hash; bool change = false; bool inDownloadList = true; if(tabs->currentIndex() > 1) return; if(tabs->currentIndex() == 1) inDownloadList = false; - unsigned int nbRows; - if(inDownloadList) - nbRows = DLListModel->rowCount(); - else - nbRows = finishedTorrentTab->getFinishedListModel()->rowCount(); - for(unsigned int i=0; idata(DLListModel->index(i, HASH)).toString(); - else - hash = finishedTorrentTab->getFinishedListModel()->data(finishedTorrentTab->getFinishedListModel()->index(i, F_HASH)).toString(); - // Remove .paused file - if(BTSession->resumeTorrent(hash)) { - if(inDownloadList) { - DLListModel->setData(DLListModel->index(i, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/connecting.png"))), Qt::DecorationRole); - setRowColor(i, QString::fromUtf8("grey")); - }else{ - finishedTorrentTab->getFinishedListModel()->setData(finishedTorrentTab->getFinishedListModel()->index(i, F_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/seeding.png"))), Qt::DecorationRole); - finishedTorrentTab->setRowColor(i, QString::fromUtf8("orange")); - } + QStringList hashes; + if(inDownloadList) { + hashes = BTSession->getUnfinishedTorrents(); + } else { + hashes = BTSession->getFinishedTorrents(); + } + QString hash; + foreach(hash, hashes) { + if(BTSession->resumeTorrent(hash)){ change = true; + if(inDownloadList) + downloadingTorrentTab->resumeTorrent(hash); + else + finishedTorrentTab->resumeTorrent(hash); } } if(change) - setInfoBar(tr("All downloads were resumed.")); + downloadingTorrentTab->setInfoBar(tr("All downloads were resumed.")); } // start selected items in the list void GUI::on_actionStart_triggered() { - QModelIndexList selectedIndexes; bool inDownloadList = true; if(tabs->currentIndex() > 1) return; if(tabs->currentIndex() == 1) inDownloadList = false; - if (inDownloadList) - selectedIndexes = downloadList->selectionModel()->selectedIndexes(); - else - selectedIndexes = finishedTorrentTab->getFinishedList()->selectionModel()->selectedIndexes(); - QModelIndex index; - foreach(index, selectedIndexes) { - if(index.column() == NAME) { - // Get the file name - QString hash; - if(inDownloadList) - hash = DLListModel->data(DLListModel->index(index.row(), HASH)).toString(); - else - hash = finishedTorrentTab->getFinishedListModel()->data(finishedTorrentTab->getFinishedListModel()->index(index.row(), F_HASH)).toString(); - if(BTSession->resumeTorrent(hash)) { - // Update DL status - int row = index.row(); - if(inDownloadList) { - DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/connecting.png"))), Qt::DecorationRole); - setRowColor(row, QString::fromUtf8("grey")); - }else{ - finishedTorrentTab->getFinishedListModel()->setData(finishedTorrentTab->getFinishedListModel()->index(row, F_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/seeding.png"))), Qt::DecorationRole); - finishedTorrentTab->setRowColor(row, QString::fromUtf8("orange")); - } - setInfoBar(tr("'%1' resumed.", "e.g: xxx.avi resumed.").arg(BTSession->getTorrentHandle(hash).name())); + QStringList hashes; + if(inDownloadList) { + hashes = downloadingTorrentTab->getSelectedTorrents(); + } else { + hashes = finishedTorrentTab->getSelectedTorrents(); + } + QString hash; + foreach(hash, hashes) { + if(BTSession->resumeTorrent(hash)){ + if(inDownloadList) { + downloadingTorrentTab->resumeTorrent(hash); + } else { + finishedTorrentTab->resumeTorrent(hash); } + downloadingTorrentTab->setInfoBar(tr("'%1' resumed.", "e.g: xxx.avi resumed.").arg(BTSession->getTorrentHandle(hash).name())); } } } @@ -1564,131 +1028,26 @@ void GUI::addUnauthenticatedTracker(QPair tracker) { // display properties of selected items void GUI::on_actionTorrent_Properties_triggered() { if(tabs->currentIndex() > 1) return; - if(tabs->currentIndex() == 1) { - finishedTorrentTab->propertiesSelection(); - return; - } - QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes(); - QModelIndex index; - foreach(index, selectedIndexes) { - if(index.column() == NAME) { - showProperties(index); - } - } -} - -// called when a torrent has finished -void GUI::finishedTorrent(QTorrentHandle& h) { - qDebug("In GUI, a torrent has finished"); - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - bool show_msg = true; - QString fileName = h.name(); - int useOSD = settings.value(QString::fromUtf8("Options/OSDEnabled"), 1).toInt(); - // Add it to finished tab - QString hash = h.hash(); - if(QFile::exists(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".finished"))) { - show_msg = false; - qDebug("We received a finished signal for torrent %s, but it already has a .finished file", hash.toUtf8().data()); - } - if(show_msg) - setInfoBar(tr("%1 has finished downloading.", "e.g: xxx.avi has finished downloading.").arg(fileName)); - int row = getRowFromHash(hash); - if(row != -1) { - DLListModel->removeRow(row); - --nbTorrents; - tabs->setTabText(0, tr("Downloads") +QString::fromUtf8(" (")+misc::toQString(nbTorrents)+QString::fromUtf8(")")); - }else{ - qDebug("finished torrent %s is not in download list, nothing to do", hash.toUtf8().data()); - } - finishedTorrentTab->addFinishedTorrent(hash); - if(show_msg && systrayIntegration && (useOSD == 1 || (useOSD == 2 && (isMinimized() || isHidden())))) { - myTrayIcon->showMessage(tr("Download finished"), tr("%1 has finished downloading.", "e.g: xxx.avi has finished downloading.").arg(fileName), QSystemTrayIcon::Information, TIME_TRAY_BALLOON); - } -} - -// Called when a torrent finished checking -void GUI::torrentChecked(QString hash) { - // Check if the torrent was paused after checking - if(BTSession->isPaused(hash)) { - // Was paused, change its icon/color - if(BTSession->isFinished(hash)) { - // In finished list - qDebug("Automatically paused torrent was in finished list"); - int row = finishedTorrentTab->getRowFromHash(hash); - if(row == -1) { - finishedTorrentTab->addFinishedTorrent(hash); - row = finishedTorrentTab->getRowFromHash(hash); - } - Q_ASSERT(row != -1); - finishedTorrentTab->getFinishedListModel()->setData(finishedTorrentTab->getFinishedListModel()->index(row, F_UPSPEED), QVariant((double)0.0)); - finishedTorrentTab->getFinishedListModel()->setData(finishedTorrentTab->getFinishedListModel()->index(row, F_NAME), QIcon(QString::fromUtf8(":/Icons/skin/paused.png")), Qt::DecorationRole); - finishedTorrentTab->setRowColor(row, QString::fromUtf8("red")); - }else{ - // In download list - int row = getRowFromHash(hash); - QTorrentHandle h = BTSession->getTorrentHandle(hash); - if(row ==-1) { - restoreInDownloadList(h); - row = getRowFromHash(hash); - } - Q_ASSERT(row != -1); - DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)0.0)); - DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)0.0)); - DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1)); - DLListModel->setData(DLListModel->index(row, NAME), QIcon(QString::fromUtf8(":/Icons/skin/paused.png")), Qt::DecorationRole); - setRowColor(row, QString::fromUtf8("red")); - // Update progress in download list - Q_ASSERT(h.progress() <= 1. && h.progress() >= 0.); - DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)h.progress())); - // Delayed Sorting - sortProgressColumnDelayed(); - } + switch(tabs->currentIndex()){ + case 1: // DL List + finishedTorrentTab->propertiesSelection(); + break; + default: + downloadingTorrentTab->propertiesSelection(); } } -// Notification when disk is full -void GUI::fullDiskError(QTorrentHandle& h) { - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - int useOSD = settings.value(QString::fromUtf8("Options/OSDEnabled"), 1).toInt(); - if(systrayIntegration && (useOSD == 1 || (useOSD == 2 && (isMinimized() || isHidden())))) { - myTrayIcon->showMessage(tr("I/O Error", "i.e: Input/Output Error"), tr("An error occured when trying to read or write %1. The disk is probably full, download has been paused", "e.g: An error occured when trying to read or write xxx.avi. The disk is probably full, download has been paused").arg(h.name()), 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.toUtf8().data()); - if(BTSession->isFinished(hash)) { - // In finished list - qDebug("Automatically paused torrent was in finished list"); - int row = finishedTorrentTab->getRowFromHash(hash); - if(row == -1) { - finishedTorrentTab->addFinishedTorrent(hash); - row = finishedTorrentTab->getRowFromHash(hash); - } - Q_ASSERT(row != -1); - finishedTorrentTab->getFinishedListModel()->setData(finishedTorrentTab->getFinishedListModel()->index(row, F_UPSPEED), QVariant((double)0.0)); - finishedTorrentTab->getFinishedListModel()->setData(finishedTorrentTab->getFinishedListModel()->index(row, F_NAME), QIcon(QString::fromUtf8(":/Icons/skin/paused.png")), Qt::DecorationRole); - finishedTorrentTab->setRowColor(row, QString::fromUtf8("red")); - }else{ - // In download list - int row = getRowFromHash(hash); - if(row == -1) { - restoreInDownloadList(BTSession->getTorrentHandle(hash)); - row = getRowFromHash(hash); - } - Q_ASSERT(row != -1); - DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)0.0)); - DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)0.0)); - DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1)); - DLListModel->setData(DLListModel->index(row, NAME), QIcon(QString::fromUtf8(":/Icons/skin/paused.png")), Qt::DecorationRole); - setRowColor(row, QString::fromUtf8("red")); +void GUI::updateLists() { + switch(getCurrentTabIndex()){ + case 0: + downloadingTorrentTab->updateDlList(); + break; + case 1: + finishedTorrentTab->updateFinishedList(); + break; + default: + return; } - setInfoBar(tr("An error occured (full disk?), '%1' paused.", "e.g: An error occured (full disk?), 'xxx.avi' paused.").arg(h.name())); -} - -// Called when we couldn't listen on any port -// in the given range. -void GUI::portListeningFailure() { - setInfoBar(tr("Couldn't listen on any of the given ports."), QString::fromUtf8("red")); } // Called when a tracker requires authentication @@ -1702,31 +1061,18 @@ void GUI::trackerAuthenticationRequired(QTorrentHandle& h) { // Check connection status and display right icon void GUI::checkConnectionStatus() { // qDebug("Checking connection status"); + // Update Ratio + downloadingTorrentTab->updateRatio(); + // Update systemTray char tmp[MAX_CHAR_TMP]; - session_status sessionStatus = BTSession->getSessionStatus(); - // Update ratio info - float ratio = 1.; - 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.; - } - snprintf(tmp, MAX_CHAR_TMP, "%.1f", ratio); - LCD_Ratio->display(tmp); - if(ratio < 0.5) { - lbl_ratio_icon->setPixmap(QPixmap(QString::fromUtf8(":/Icons/unhappy.png"))); - }else{ - if(ratio > 1.0) { - lbl_ratio_icon->setPixmap(QPixmap(QString::fromUtf8(":/Icons/smile.png"))); - }else{ - lbl_ratio_icon->setPixmap(QPixmap(QString::fromUtf8(":/Icons/stare.png"))); - } + char tmp2[MAX_CHAR_TMP]; + // update global informations + snprintf(tmp, MAX_CHAR_TMP, "%.1f", BTSession->getPayloadUploadRate()/1024.); + snprintf(tmp2, MAX_CHAR_TMP, "%.1f", BTSession->getPayloadDownloadRate()/1024.); + if(systrayIntegration) { + myTrayIcon->setToolTip(QString::fromUtf8("")+tr("qBittorrent")+QString::fromUtf8("
")+tr("DL speed: %1 KiB/s", "e.g: Download speed: 10 KiB/s").arg(QString::fromUtf8(tmp2))+QString::fromUtf8("
")+tr("UP speed: %1 KiB/s", "e.g: Upload speed: 10 KiB/s").arg(QString::fromUtf8(tmp))); // tray icon } + session_status sessionStatus = BTSession->getSessionStatus(); if(sessionStatus.has_incoming_connections) { // Connection OK connecStatusLblIcon->setPixmap(QPixmap(QString::fromUtf8(":/Icons/skin/connected.png"))); @@ -1750,34 +1096,10 @@ void GUI::checkConnectionStatus() { * * *****************************************************/ -// Set the color of a row in data model -void GUI::setRowColor(int row, QString color) { - unsigned int nbColumns = DLListModel->columnCount(); - for(unsigned int i=0; isetData(DLListModel->index(row, i), QVariant(QColor(color)), Qt::ForegroundRole); - } -} - -// return the row of in data model -// corresponding to the given the hash -int GUI::getRowFromHash(QString hash) const{ - unsigned int nbRows = DLListModel->rowCount(); - for(unsigned int i=0; idata(DLListModel->index(i, HASH)) == hash) { - return i; - } - } - return -1; -} - void GUI::downloadFromURLList(const QStringList& urls) { BTSession->downloadFromURLList(urls); } -void GUI::displayDownloadingUrlInfos(QString url) { - setInfoBar(tr("Downloading '%1', please wait...", "e.g: Downloading 'xxx.torrent', please wait...").arg(url), QString::fromUtf8("black")); -} - /***************************************************** * * * Options * @@ -1827,7 +1149,7 @@ void GUI::OptionsSaved(QString info, bool deleteOptions) { } systrayIntegration = newSystrayIntegration; // Update info bar - setInfoBar(info); + downloadingTorrentTab->setInfoBar(info); // Update session configureSession(deleteOptions); } @@ -1841,6 +1163,6 @@ void GUI::OptionsSaved(QString info, bool deleteOptions) { // Display an input dialog to prompt user for // an url void GUI::on_actionDownload_from_URL_triggered() { - downloadFromURLDialog = new downloadFromURL(this); + downloadFromURL *downloadFromURLDialog = new downloadFromURL(this); connect(downloadFromURLDialog, SIGNAL(urlsReadyToBeDownloaded(const QStringList&)), BTSession, SLOT(downloadFromURLList(const QStringList&))); } diff --git a/src/GUI.h b/src/GUI.h index d8083d72e..6e13d3298 100644 --- a/src/GUI.h +++ b/src/GUI.h @@ -31,6 +31,7 @@ class bittorrent; class createtorrent; class QTimer; +class DownloadingTorrents; class FinishedTorrents; class DLListDelegate; class downloadThread; @@ -45,6 +46,9 @@ class about; class previewSelect; class options_imp; class QStandardItemModel; +class QTabWidget; +class QLabel; +class QModelIndex; class GUI : public QMainWindow, private Ui::MainWindow{ Q_OBJECT @@ -54,23 +58,17 @@ class GUI : public QMainWindow, private Ui::MainWindow{ bittorrent *BTSession; QTimer *checkConnect; QList > unauthenticated_trackers; - downloadFromURL *downloadFromURLDialog; // GUI related + QTabWidget *tabs; options_imp *options; - createtorrent *createWindow; - QTimer *refresher; QSystemTrayIcon *myTrayIcon; QMenu *myTrayIconMenu; - about *aboutdlg; - QStandardItemModel *DLListModel; - DLListDelegate *DLDelegate; + DownloadingTorrents *downloadingTorrentTab; FinishedTorrents *finishedTorrentTab; - unsigned int nbTorrents; QLabel *connecStatusLblIcon; bool systrayIntegration; bool force_exit; - bool delayedSorting; - Qt::SortOrder delayedSortingOrder; + QTimer *refresher; // Keyboard shortcuts QShortcut *switchSearchShortcut; QShortcut *switchSearchShortcut2; @@ -78,7 +76,6 @@ class GUI : public QMainWindow, private Ui::MainWindow{ QShortcut *switchUpShortcut; QShortcut *switchRSSShortcut; // Preview - previewSelect *previewSelection; QProcess *previewProcess; // Search SearchEngine *searchEngine; @@ -94,22 +91,12 @@ class GUI : public QMainWindow, private Ui::MainWindow{ void dragEnterEvent(QDragEnterEvent *event); void toggleVisibility(QSystemTrayIcon::ActivationReason e); void on_actionAbout_triggered(); - void setInfoBar(QString info, QString color="black"); - void updateDlList(bool force=false); void on_actionCreate_torrent_triggered(); - void on_actionClearLog_triggered(); void on_actionWebsite_triggered(); void on_actionBugReport_triggered(); void readParamsOnSocket(); void acceptConnection(); - void saveColWidthDLList() const; - bool loadColWidthDLList(); - void sortDownloadList(int index, Qt::SortOrder startSortOrder=Qt::AscendingOrder, bool fromLoadColWidth=false); - void sortDownloadListFloat(int index, Qt::SortOrder sortOrder); - void sortDownloadListString(int index, Qt::SortOrder sortOrder); - void displayDLListMenu(const QPoint& pos); - void togglePausedState(const QModelIndex& index); - void displayInfoBarMenu(const QPoint& pos); + void togglePausedState(QString hash); void on_actionPreview_file_triggered(); void previewFile(QString filePath); void cleanTempPreviewFile(int, QProcess::ExitStatus); @@ -118,28 +105,25 @@ class GUI : public QMainWindow, private Ui::MainWindow{ void readSettings(); void on_actionExit_triggered(); void createTrayIcon(); - void addLogPeerBlocked(QString); - void addFastResumeRejectedAlert(QString); + void updateUnfinishedTorrentNumber(unsigned int nb); + void updateFinishedTorrentNumber(unsigned int nb); + void fullDiskError(QTorrentHandle& h); + void handleDownloadFromUrlFailure(QString, QString) const; // Keyboard shortcuts void createKeyboardShortcuts(); void displayDownTab(); void displayUpTab(); void displaySearchTab(); void displayRSSTab(); - void handleDownloadFromUrlFailure(QString, QString) const; // Torrent actions - void showProperties(const QModelIndex &index); void on_actionTorrent_Properties_triggered(); void on_actionPause_triggered(); void on_actionPause_All_triggered(); - void restoreInDownloadList(QTorrentHandle h); 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_download_limit_triggered(); - void on_actionSet_upload_limit_triggered(); void on_actionSet_global_upload_limit_triggered(); void on_actionSet_global_download_limit_triggered(); void on_actionDocumentation_triggered(); @@ -150,10 +134,9 @@ class GUI : public QMainWindow, private Ui::MainWindow{ void processScannedFiles(const QStringList& params); void processDownloadedFiles(QString path, QString url); void downloadFromURLList(const QStringList& urls); - void displayDownloadingUrlInfos(QString url); + void finishedTorrent(QTorrentHandle& h); void torrentChecked(QString hash); - // Utils slots - void setRowColor(int row, QString color); + void updateLists(); // Options slots void on_actionOptions_triggered(); void OptionsSaved(QString info, bool deleteOptions); @@ -162,17 +145,8 @@ class GUI : public QMainWindow, private Ui::MainWindow{ public slots: - void torrentAdded(QString path, QTorrentHandle& h, bool fastResume); - void torrentDuplicate(QString path); - void torrentCorrupted(QString path); - void finishedTorrent(QTorrentHandle& h); - void fullDiskError(QTorrentHandle& h); - void portListeningFailure(); void trackerAuthenticationRequired(QTorrentHandle& h); void setTabText(int index, QString text); - void updateFileSizeAndProgress(QString hash); - void sortProgressColumnDelayed(); - void addUrlSeedError(QString url, QString msg); protected: void closeEvent(QCloseEvent *); @@ -183,7 +157,6 @@ class GUI : public QMainWindow, private Ui::MainWindow{ GUI(QWidget *parent=0, QStringList torrentCmdLine=QStringList()); ~GUI(); // Methods - int getRowFromHash(QString hash) const; unsigned int getCurrentTabIndex() const; QPoint screenCenter() const; }; diff --git a/src/MainWindow.ui b/src/MainWindow.ui index b505fdc49..b0f3cce21 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -17,322 +17,21 @@ - - 9 - 6 - - - - QTabWidget::North - - - 0 - - - - Downloads - - - - 9 - - - 6 - - - - - 0 - - - 6 - - - - - 0 - - - 6 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Total DL Speed: - - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - - - - - - - true - - - QFrame::Raised - - - false - - - 6 - - - QLCDNumber::Flat - - - 0.000000000000000 - - - 0 - - - - - - - KiB/s - - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Session ratio: - - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - - - - - - - true - - - 4 - - - QLCDNumber::Flat - - - 1.000000000000000 - - - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Total UP Speed: - - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - - - - - - - true - - - false - - - 6 - - - QLCDNumber::Flat - - - 0.000000000000000 - - - - - - - KiB/s - - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - 0 - 0 - - - - Qt::CustomContextMenu - - - true - - - QAbstractItemView::ExtendedSelection - - - 1 - - - false - - - - - - - - - - 16777215 - 142 - - - - QTabWidget::West - - - 1 - - - - Log - - - - 9 - - - 6 - - - - - - 7 - 7 - 0 - 0 - - - - - 16777215 - 120 - - - - Qt::CustomContextMenu - - - - - - - - IP filter - - - - 9 - - - 6 - - - - - - 16777215 - 123 - - - - - - - - - - - - + + 9 + + + 9 + + + 9 + + + 9 + @@ -408,7 +107,10 @@ - 4 + TopToolBarArea + + + false diff --git a/src/about_imp.h b/src/about_imp.h index e97185228..691f8b95d 100644 --- a/src/about_imp.h +++ b/src/about_imp.h @@ -29,6 +29,10 @@ class about : public QDialog, private Ui::AboutDlg{ Q_OBJECT public: + ~about() { + qDebug("Deleting about dlg"); + } + about(QWidget *parent): QDialog(parent){ setupUi(this); setAttribute(Qt::WA_DeleteOnClose); diff --git a/src/bittorrent.cpp b/src/bittorrent.cpp index ad27dbeb1..67e49ebc4 100644 --- a/src/bittorrent.cpp +++ b/src/bittorrent.cpp @@ -26,12 +26,12 @@ #include #include - #include #include #include #include #include +#include #include #include "bittorrent.h" @@ -70,9 +70,10 @@ bittorrent::bittorrent() { // To download from urls downloader = new downloadThread(this); connect(downloader, SIGNAL(downloadFinished(QString, QString)), this, SLOT(processDownloadedFile(QString, QString))); - connect(downloader, SIGNAL(downloadFailure(QString, QString)), this, SLOT(HandleDownloadFailure(QString, QString))); + connect(downloader, SIGNAL(downloadFailure(QString, QString)), this, SLOT(handleDownloadFailure(QString, QString))); // File deleter (thread) deleter = new deleteThread(this); + qDebug("* BTSession constructed"); } // Main destructor @@ -106,7 +107,7 @@ void bittorrent::setUploadLimit(QString hash, long val) { saveTorrentSpeedLimits(hash); } -void bittorrent::HandleDownloadFailure(QString url, QString reason) { +void bittorrent::handleDownloadFailure(QString url, QString reason) { emit downloadFromUrlFailure(url, reason); } @@ -366,10 +367,27 @@ void bittorrent::addTorrent(QString path, bool fromScanDir, QString from_url) { entry e = bdecode(std::istream_iterator(in), std::istream_iterator()); // Getting torrent file informations torrent_info t(e); + std::cout << t.info_hash() << "\n"; QString hash = QString::fromUtf8(misc::toString(t.info_hash()).c_str()); if(s->find_torrent(t.info_hash()).is_valid()) { // Update info Bar if(!fromScanDir) { + if(file.startsWith(torrentBackup.path())){ + // Torrent hash has changed. This should not be possible but... + // XXX: Why does this happen sometimes? + QFileInfo fi(file); + QString old_hash = fi.baseName(); + qDebug("Strange, hash changed to %s", old_hash.toUtf8().data()); + QStringList filters; + filters << old_hash+".*"; + QStringList files = torrentBackup.entryList(filters, QDir::Files, QDir::Unsorted); + QString my_f; + foreach(my_f, files) { + qDebug("* deleting %s", my_f.toUtf8().data()); + torrentBackup.remove(my_f); + } + return; + } if(!from_url.isNull()) { // If download from url, remove temp file QFile::remove(file); diff --git a/src/bittorrent.h b/src/bittorrent.h index c71e5996b..ee68409e3 100644 --- a/src/bittorrent.h +++ b/src/bittorrent.h @@ -111,7 +111,7 @@ class bittorrent : public QObject{ void loadTorrentSpeedLimits(QString hash); void saveDownloadUploadForTorrent(QString hash); void loadDownloadUploadForTorrent(QString hash); - void HandleDownloadFailure(QString url, QString reason); + void handleDownloadFailure(QString url, QString reason); void loadWebSeeds(QString fileHash); // Session configuration - Setters void setListeningPortsRange(std::pair ports); diff --git a/src/download.ui b/src/download.ui new file mode 100644 index 000000000..4ef79801a --- /dev/null +++ b/src/download.ui @@ -0,0 +1,386 @@ + + downloading + + + + 0 + 0 + 811 + 453 + + + + Search + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Total DL Speed: + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + true + + + QFrame::Raised + + + false + + + 6 + + + QLCDNumber::Flat + + + 0.000000000000000 + + + 0 + + + + + + + KiB/s + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Session ratio: + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + true + + + 4 + + + QLCDNumber::Flat + + + 1.000000000000000 + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Total UP Speed: + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + true + + + false + + + 6 + + + QLCDNumber::Flat + + + 0.000000000000000 + + + + + + + KiB/s + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + 0 + + + + Qt::CustomContextMenu + + + true + + + QAbstractItemView::ExtendedSelection + + + 1 + + + false + + + + + + + + + + 16777215 + 142 + + + + QTabWidget::West + + + 0 + + + + Log + + + + 6 + + + 9 + + + 9 + + + 9 + + + 9 + + + + + + 0 + 0 + + + + + 16777215 + 120 + + + + Qt::CustomContextMenu + + + + + + + + IP filter + + + + 6 + + + 9 + + + 9 + + + 9 + + + 9 + + + + + + 16777215 + 123 + + + + + + + + + + + + Start + + + + + Pause + + + + + Delete + + + + + Clear + + + + + Preview file + + + + + Set upload limit + + + + + Set download limit + + + + + Delete Permanently + + + + + Torrent Properties + + + + + + diff --git a/src/downloadingTorrents.cpp b/src/downloadingTorrents.cpp new file mode 100644 index 000000000..5b63c04f9 --- /dev/null +++ b/src/downloadingTorrents.cpp @@ -0,0 +1,697 @@ +/* + * 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. + * + * Contact : chris@qbittorrent.org + */ +#include "downloadingTorrents.h" +#include "misc.h" +#include "properties_imp.h" +#include "bittorrent.h" +#include "allocationDlg.h" +#include "DLListDelegate.h" +#include "previewSelect.h" +#include "GUI.h" + +#include +#include +#include +#include +#include +#include + +DownloadingTorrents::DownloadingTorrents(QObject *parent, bittorrent *BTSession) { + setupUi(this); + this->BTSession = BTSession; + this->parent = parent; + delayedSorting = false; + nbTorrents = 0; + // Setting icons + actionStart->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/play.png"))); + actionPause->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/pause.png"))); + actionDelete->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/delete.png"))); + actionClearLog->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/delete.png"))); + actionPreview_file->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/preview.png"))); + actionSet_upload_limit->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/seeding.png"))); + actionSet_download_limit->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png"))); + actionDelete_Permanently->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/delete_perm.png"))); + actionTorrent_Properties->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/properties.png"))); +// tabBottom->setTabIcon(0, QIcon(QString::fromUtf8(":/Icons/log.png"))); +// tabBottom->setTabIcon(1, QIcon(QString::fromUtf8(":/Icons/filter.png"))); + // Set default ratio + lbl_ratio_icon->setPixmap(QPixmap(QString::fromUtf8(":/Icons/stare.png"))); + + // Set Download list model + DLListModel = new QStandardItemModel(0,9); + DLListModel->setHeaderData(NAME, Qt::Horizontal, tr("Name", "i.e: file name")); + DLListModel->setHeaderData(SIZE, Qt::Horizontal, tr("Size", "i.e: file size")); + DLListModel->setHeaderData(PROGRESS, Qt::Horizontal, tr("Progress", "i.e: % downloaded")); + DLListModel->setHeaderData(DLSPEED, Qt::Horizontal, tr("DL Speed", "i.e: Download speed")); + DLListModel->setHeaderData(UPSPEED, Qt::Horizontal, tr("UP Speed", "i.e: Upload speed")); + DLListModel->setHeaderData(SEEDSLEECH, Qt::Horizontal, tr("Seeds/Leechs", "i.e: full/partial sources")); + DLListModel->setHeaderData(RATIO, Qt::Horizontal, tr("Ratio")); + DLListModel->setHeaderData(ETA, Qt::Horizontal, tr("ETA", "i.e: Estimated Time of Arrival / Time left")); + downloadList->setModel(DLListModel); + DLDelegate = new DLListDelegate(downloadList); + downloadList->setItemDelegate(DLDelegate); + // Hide hash column + downloadList->hideColumn(HASH); + + connect(BTSession, SIGNAL(addedTorrent(QString, QTorrentHandle&, bool)), this, SLOT(torrentAdded(QString, QTorrentHandle&, bool))); + connect(BTSession, SIGNAL(duplicateTorrent(QString)), this, SLOT(torrentDuplicate(QString))); + connect(BTSession, SIGNAL(invalidTorrent(QString)), this, SLOT(torrentCorrupted(QString))); + connect(BTSession, SIGNAL(portListeningFailure()), this, SLOT(portListeningFailure())); + connect(BTSession, SIGNAL(peerBlocked(QString)), this, SLOT(addLogPeerBlocked(const QString))); + connect(BTSession, SIGNAL(fastResumeDataRejected(QString)), this, SLOT(addFastResumeRejectedAlert(QString))); + connect(BTSession, SIGNAL(aboutToDownloadFromUrl(QString)), this, SLOT(displayDownloadingUrlInfos(QString))); + connect(BTSession, SIGNAL(urlSeedProblem(QString, QString)), this, SLOT(addUrlSeedError(QString, QString))); + + // Load last columns width for download list + if(!loadColWidthDLList()) { + downloadList->header()->resizeSection(0, 200); + } + // Make download list header clickable for sorting + downloadList->header()->setClickable(true); + downloadList->header()->setSortIndicatorShown(true); + // Connecting Actions to slots + connect(downloadList, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(notifyTorrentDoubleClicked(const QModelIndex&))); + connect(downloadList->header(), SIGNAL(sectionPressed(int)), this, SLOT(sortDownloadList(int))); + connect(downloadList, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayDLListMenu(const QPoint&))); + connect(infoBar, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayInfoBarMenu(const QPoint&))); + // Actions + connect(actionDelete, SIGNAL(triggered()), (GUI*)parent, SLOT(on_actionDelete_triggered())); + connect(actionPreview_file, SIGNAL(triggered()), (GUI*)parent, SLOT(on_actionPreview_file_triggered())); + connect(actionDelete_Permanently, SIGNAL(triggered()), (GUI*)parent, SLOT(on_actionDelete_Permanently_triggered())); + connect(actionTorrent_Properties, SIGNAL(triggered()), this, SLOT(propertiesSelection())); + // Set info Bar infos + setInfoBar(tr("qBittorrent %1 started.", "e.g: qBittorrent v0.x started.").arg(QString::fromUtf8(""VERSION))); + setInfoBar(tr("Be careful, sharing copyrighted material without permission is against the law."), QString::fromUtf8("red")); + qDebug("Download tab built"); +} + +DownloadingTorrents::~DownloadingTorrents() { + saveColWidthDLList(); + delete DLDelegate; + delete DLListModel; +} + + +void DownloadingTorrents::notifyTorrentDoubleClicked(const QModelIndex& index) { + unsigned int row = index.row(); + QString hash = getHashFromRow(row); + emit torrentDoubleClicked(hash); +} + +void DownloadingTorrents::addLogPeerBlocked(QString ip) { + static unsigned short nbLines = 0; + ++nbLines; + if(nbLines > 200) { + textBlockedUsers->clear(); + nbLines = 1; + } + textBlockedUsers->append(QString::fromUtf8("")+ QTime::currentTime().toString(QString::fromUtf8("hh:mm:ss")) + QString::fromUtf8(" - ")+tr("%1 was blocked", "x.y.z.w was blocked").arg(ip)); +} + +unsigned int DownloadingTorrents::getNbTorrentsInList() const { + return nbTorrents; +} + +// Note: do not actually pause the torrent in BT session +void DownloadingTorrents::pauseTorrent(QString hash) { + int row = getRowFromHash(hash); + Q_ASSERT(row != -1); + DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)0.0)); + DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)0.0)); + DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1)); + DLListModel->setData(DLListModel->index(row, NAME), QIcon(QString::fromUtf8(":/Icons/skin/paused.png")), Qt::DecorationRole); + DLListModel->setData(DLListModel->index(row, SEEDSLEECH), QVariant(QString::fromUtf8("0/0"))); + QTorrentHandle h = BTSession->getTorrentHandle(hash); + Q_ASSERT(h.progress() <= 1. && h.progress() >= 0.); + DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)h.progress())); + setRowColor(row, QString::fromUtf8("red")); +} + +QString DownloadingTorrents::getHashFromRow(unsigned int row) const { + Q_ASSERT(row < (unsigned int)DLListModel->rowCount()); + return DLListModel->data(DLListModel->index(row, HASH)).toString(); +} + +void DownloadingTorrents::setBottomTabEnabled(unsigned int index, bool b){ + if(index and !b) + tabBottom->setCurrentIndex(0); + tabBottom->setTabEnabled(index, b); +} + +// Show torrent properties dialog +void DownloadingTorrents::showProperties(const QModelIndex &index) { + int row = index.row(); + QString hash = DLListModel->data(DLListModel->index(row, HASH)).toString(); + QTorrentHandle h = BTSession->getTorrentHandle(hash); + properties *prop = new properties(this, BTSession, h); + connect(prop, SIGNAL(filteredFilesChanged(QString)), this, SLOT(updateFileSizeAndProgress(QString))); + prop->show(); +} + +void DownloadingTorrents::resumeTorrent(QString hash){ + int row = getRowFromHash(hash); + Q_ASSERT(row != -1); + DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/connecting.png"))), Qt::DecorationRole); + setRowColor(row, QString::fromUtf8("grey")); +} + +// Remove a torrent from the download list but NOT from the BT Session +void DownloadingTorrents::deleteTorrent(QString hash) { + int row = getRowFromHash(hash); + Q_ASSERT(row != -1); + DLListModel->removeRow(row); + --nbTorrents; + emit unfinishedTorrentsNumberChanged(nbTorrents); +} + +// Update Info Bar information +void DownloadingTorrents::setInfoBar(QString info, QString color) { + static unsigned short nbLines = 0; + ++nbLines; + // Check log size, clear it if too big + if(nbLines > 200) { + infoBar->clear(); + nbLines = 1; + } + infoBar->append(QString::fromUtf8("")+ QTime::currentTime().toString(QString::fromUtf8("hh:mm:ss")) + QString::fromUtf8(" - ") + info + QString::fromUtf8("")); +} + +void DownloadingTorrents::addFastResumeRejectedAlert(QString name) { + setInfoBar(tr("Fast resume data was rejected for torrent %1, checking again...").arg(name), QString::fromUtf8("red")); +} + +void DownloadingTorrents::addUrlSeedError(QString url, QString msg) { + setInfoBar(tr("Url seed lookup failed for url: %1, message: %2").arg(url).arg(msg), QString::fromUtf8("red")); +} + +void DownloadingTorrents::on_actionSet_download_limit_triggered() { + QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes(); + QModelIndex index; + QStringList hashes; + foreach(index, selectedIndexes) { + if(index.column() == NAME) { + // Get the file hash + hashes << DLListModel->data(DLListModel->index(index.row(), HASH)).toString(); + } + } + Q_ASSERT(hashes.size() > 0); + new BandwidthAllocationDialog(this, false, BTSession, hashes); +} + +void DownloadingTorrents::on_actionSet_upload_limit_triggered() { + QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes(); + QModelIndex index; + QStringList hashes; + foreach(index, selectedIndexes) { + if(index.column() == NAME) { + // Get the file hash + hashes << DLListModel->data(DLListModel->index(index.row(), HASH)).toString(); + } + } + Q_ASSERT(hashes.size() > 0); + new BandwidthAllocationDialog(this, true, BTSession, hashes); +} + +// display properties of selected items +void DownloadingTorrents::propertiesSelection(){ + QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes(); + QModelIndex index; + foreach(index, selectedIndexes){ + if(index.column() == NAME){ + showProperties(index); + } + } +} + +void DownloadingTorrents::displayDLListMenu(const QPoint& pos) { + QMenu myDLLlistMenu(this); + QModelIndex index; + // Enable/disable pause/start action given the DL state + QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes(); + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + QString previewProgram = settings.value(QString::fromUtf8("Options/Misc/PreviewProgram"), QString()).toString(); + bool has_pause = false, has_start = false, has_preview = false; + foreach(index, selectedIndexes) { + if(index.column() == NAME) { + // Get the file name + QString hash = DLListModel->data(DLListModel->index(index.row(), HASH)).toString(); + // Get handle and pause the torrent + QTorrentHandle h = BTSession->getTorrentHandle(hash); + if(!h.is_valid()) continue; + if(h.is_paused()) { + if(!has_start) { + myDLLlistMenu.addAction(actionStart); + has_start = true; + } + }else{ + if(!has_pause) { + myDLLlistMenu.addAction(actionPause); + has_pause = true; + } + } + if(!previewProgram.isEmpty() && BTSession->isFilePreviewPossible(hash) && !has_preview) { + myDLLlistMenu.addAction(actionPreview_file); + has_preview = true; + } + if(has_pause && has_start && has_preview) break; + } + } + myDLLlistMenu.addSeparator(); + myDLLlistMenu.addAction(actionDelete); + myDLLlistMenu.addAction(actionDelete_Permanently); + myDLLlistMenu.addSeparator(); + myDLLlistMenu.addAction(actionSet_download_limit); + myDLLlistMenu.addAction(actionSet_upload_limit); + myDLLlistMenu.addSeparator(); + myDLLlistMenu.addAction(actionTorrent_Properties); + // Call menu + // XXX: why mapToGlobal() is not enough? + myDLLlistMenu.exec(mapToGlobal(pos)+QPoint(10,55)); +} + +void DownloadingTorrents::on_actionClearLog_triggered() { + infoBar->clear(); +} + +QStringList DownloadingTorrents::getSelectedTorrents(bool only_one) const{ + QStringList res; + QModelIndex index; + QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes(); + foreach(index, selectedIndexes) { + if(index.column() == NAME) { + // Get the file hash + QString hash = DLListModel->data(DLListModel->index(index.row(), HASH)).toString(); + res << hash; + if(only_one) break; + } + } + return res; +} + +void DownloadingTorrents::updateRatio() { + char tmp[MAX_CHAR_TMP]; + // 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.; + } + snprintf(tmp, MAX_CHAR_TMP, "%.1f", ratio); + LCD_Ratio->display(tmp); + if(ratio < 0.5) { + lbl_ratio_icon->setPixmap(QPixmap(QString::fromUtf8(":/Icons/unhappy.png"))); + }else{ + if(ratio > 1.0) { + lbl_ratio_icon->setPixmap(QPixmap(QString::fromUtf8(":/Icons/smile.png"))); + }else{ + lbl_ratio_icon->setPixmap(QPixmap(QString::fromUtf8(":/Icons/stare.png"))); + } + } +} + +void DownloadingTorrents::displayInfoBarMenu(const QPoint& pos) { + // Log Menu + QMenu myLogMenu(this); + myLogMenu.addAction(actionClearLog); + // XXX: Why mapToGlobal() is not enough? + myLogMenu.exec(mapToGlobal(pos)+QPoint(22,383)); +} + +void DownloadingTorrents::sortProgressColumnDelayed() { + if(delayedSorting) { + sortDownloadListFloat(PROGRESS, delayedSortingOrder); + qDebug("Delayed sorting of progress column"); + } +} + +// get information from torrent handles and +// update download list accordingly +void DownloadingTorrents::updateDlList() { + char tmp[MAX_CHAR_TMP]; + char tmp2[MAX_CHAR_TMP]; + // update global informations + snprintf(tmp, MAX_CHAR_TMP, "%.1f", BTSession->getPayloadUploadRate()/1024.); + snprintf(tmp2, MAX_CHAR_TMP, "%.1f", BTSession->getPayloadDownloadRate()/1024.); + //BTSession->printPausedTorrents(); + LCD_UpSpeed->display(QString::fromUtf8(tmp)); // UP LCD + LCD_DownSpeed->display(QString::fromUtf8(tmp2)); // DL LCD + // browse handles + QStringList unfinishedTorrents = BTSession->getUnfinishedTorrents(); + QString hash; + foreach(hash, unfinishedTorrents) { + QTorrentHandle h = BTSession->getTorrentHandle(hash); + if(!h.is_valid()){ + qDebug("We have an invalid handle for: %s", qPrintable(hash)); + continue; + } + try{ + QString hash = h.hash(); + int row = getRowFromHash(hash); + if(row == -1) { + qDebug("Info: Could not find filename in download list, adding it..."); + addTorrent(hash); + row = getRowFromHash(hash); + } + Q_ASSERT(row != -1); + // No need to update a paused torrent + if(h.is_paused()) continue; + // Parse download state + // Setting download state + switch(h.state()) { + case torrent_status::finished: + case torrent_status::seeding: + qDebug("A torrent that was in download tab just finished, moving it to finished tab"); + BTSession->setUnfinishedTorrent(hash); + emit torrentFinished(hash); + deleteTorrent(hash); + continue; + case torrent_status::checking_files: + case torrent_status::queued_for_checking: + if(BTSession->getTorrentsToPauseAfterChecking().indexOf(hash) == -1) { + DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/time.png"))), Qt::DecorationRole); + setRowColor(row, QString::fromUtf8("grey")); + Q_ASSERT(h.progress() <= 1. && h.progress() >= 0.); + DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)h.progress())); + } + break; + case torrent_status::connecting_to_tracker: + if(h.download_payload_rate() > 0) { + // Display "Downloading" status when connecting if download speed > 0 + DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)BTSession->getETA(hash))); + DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png"))), Qt::DecorationRole); + setRowColor(row, QString::fromUtf8("green")); + }else{ + DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1)); + DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/connecting.png"))), Qt::DecorationRole); + setRowColor(row, QString::fromUtf8("grey")); + } + Q_ASSERT(h.progress() <= 1. && h.progress() >= 0.); + DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)h.progress())); + DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)h.download_payload_rate())); + DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)h.upload_payload_rate())); + break; + case torrent_status::downloading: + case torrent_status::downloading_metadata: + if(h.download_payload_rate() > 0) { + DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png"))), Qt::DecorationRole); + DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)BTSession->getETA(hash))); + setRowColor(row, QString::fromUtf8("green")); + }else{ + DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/stalled.png"))), Qt::DecorationRole); + DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1)); + setRowColor(row, QString::fromUtf8("black")); + } + Q_ASSERT(h.progress() <= 1. && h.progress() >= 0.); + DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)h.progress())); + DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)h.download_payload_rate())); + DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)h.upload_payload_rate())); + break; + default: + DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1)); + } + DLListModel->setData(DLListModel->index(row, SEEDSLEECH), QVariant(misc::toQString(h.num_seeds(), true)+QString::fromUtf8("/")+misc::toQString(h.num_peers() - h.num_seeds(), true))); + DLListModel->setData(DLListModel->index(row, RATIO), QVariant(misc::toQString(BTSession->getRealRatio(hash)))); + }catch(invalid_handle e) { + continue; + } + } +} + +void DownloadingTorrents::addTorrent(QString hash) { + if(BTSession->isFinished(hash)){ + BTSession->setUnfinishedTorrent(hash); + } + QTorrentHandle h = BTSession->getTorrentHandle(hash); + int row = getRowFromHash(hash); + if(row != -1) return; + row = DLListModel->rowCount(); + // Adding torrent to download list + DLListModel->insertRow(row); + DLListModel->setData(DLListModel->index(row, NAME), QVariant(h.name())); + DLListModel->setData(DLListModel->index(row, SIZE), QVariant((qlonglong)h.actual_size())); + DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)0.)); + DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)0.)); + DLListModel->setData(DLListModel->index(row, SEEDSLEECH), QVariant(QString::fromUtf8("0/0"))); + DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1)); + DLListModel->setData(DLListModel->index(row, HASH), QVariant(hash)); + // Pause torrent if it was paused last time + if(BTSession->isPaused(hash)) { + DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/paused.png"))), Qt::DecorationRole); + setRowColor(row, QString::fromUtf8("red")); + }else{ + DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/connecting.png"))), Qt::DecorationRole); + setRowColor(row, QString::fromUtf8("grey")); + } + ++nbTorrents; + emit unfinishedTorrentsNumberChanged(nbTorrents); +} + +void DownloadingTorrents::sortDownloadListFloat(int index, Qt::SortOrder sortOrder) { + QList > lines; + // insertion sorting + unsigned int nbRows = DLListModel->rowCount(); + for(unsigned int i=0; i(i, DLListModel->data(DLListModel->index(i, index)).toDouble()), sortOrder); + } + // Insert items in new model, in correct order + unsigned int nbRows_old = lines.size(); + for(unsigned int row=0; rowinsertRow(DLListModel->rowCount()); + unsigned int sourceRow = lines[row].first; + unsigned int nbColumns = DLListModel->columnCount(); + for(unsigned int col=0; colsetData(DLListModel->index(nbRows_old+row, col), DLListModel->data(DLListModel->index(sourceRow, col))); + DLListModel->setData(DLListModel->index(nbRows_old+row, col), DLListModel->data(DLListModel->index(sourceRow, col), Qt::DecorationRole), Qt::DecorationRole); + DLListModel->setData(DLListModel->index(nbRows_old+row, col), DLListModel->data(DLListModel->index(sourceRow, col), Qt::ForegroundRole), Qt::ForegroundRole); + } + } + // Remove old rows + DLListModel->removeRows(0, nbRows_old); +} + +void DownloadingTorrents::sortDownloadListString(int index, Qt::SortOrder sortOrder) { + QList > lines; + // Insertion sorting + unsigned int nbRows = DLListModel->rowCount(); + for(unsigned int i=0; i(i, DLListModel->data(DLListModel->index(i, index)).toString()), sortOrder); + } + // Insert items in new model, in correct order + unsigned int nbRows_old = lines.size(); + for(unsigned int row=0; rowinsertRow(DLListModel->rowCount()); + unsigned int sourceRow = lines[row].first; + unsigned int nbColumns = DLListModel->columnCount(); + for(unsigned int col=0; colsetData(DLListModel->index(nbRows_old+row, col), DLListModel->data(DLListModel->index(sourceRow, col))); + DLListModel->setData(DLListModel->index(nbRows_old+row, col), DLListModel->data(DLListModel->index(sourceRow, col), Qt::DecorationRole), Qt::DecorationRole); + DLListModel->setData(DLListModel->index(nbRows_old+row, col), DLListModel->data(DLListModel->index(sourceRow, col), Qt::ForegroundRole), Qt::ForegroundRole); + } + } + // Remove old rows + DLListModel->removeRows(0, nbRows_old); +} + +void DownloadingTorrents::sortDownloadList(int index, Qt::SortOrder startSortOrder, bool fromLoadColWidth) { + qDebug("Called sort download list"); + static Qt::SortOrder sortOrder = startSortOrder; + if(!fromLoadColWidth && downloadList->header()->sortIndicatorSection() == index) { + if(sortOrder == Qt::AscendingOrder) { + sortOrder = Qt::DescendingOrder; + }else{ + sortOrder = Qt::AscendingOrder; + } + } + QString sortOrderLetter; + if(sortOrder == Qt::AscendingOrder) + sortOrderLetter = QString::fromUtf8("a"); + else + sortOrderLetter = QString::fromUtf8("d"); + if(fromLoadColWidth) { + // XXX: Why is this needed? + if(sortOrder == Qt::DescendingOrder) + downloadList->header()->setSortIndicator(index, Qt::AscendingOrder); + else + downloadList->header()->setSortIndicator(index, Qt::DescendingOrder); + } else { + downloadList->header()->setSortIndicator(index, sortOrder); + } + switch(index) { + case SIZE: + case ETA: + case UPSPEED: + case DLSPEED: + sortDownloadListFloat(index, sortOrder); + break; + case PROGRESS: + if(fromLoadColWidth) { + // Progress sorting must be delayed until files are checked (on startup) + delayedSorting = true; + qDebug("Delayed sorting of the progress column"); + delayedSortingOrder = sortOrder; + }else{ + sortDownloadListFloat(index, sortOrder); + } + break; + default: + sortDownloadListString(index, sortOrder); + } + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + settings.setValue(QString::fromUtf8("DownloadListSortedCol"), misc::toQString(index)+sortOrderLetter); +} + +// Save columns width in a file to remember them +// (download list) +void DownloadingTorrents::saveColWidthDLList() const{ + qDebug("Saving columns width in download list"); + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + QStringList width_list; + unsigned int nbColumns = DLListModel->columnCount()-1; + for(unsigned int i=0; icolumnWidth(i)); + } + settings.setValue(QString::fromUtf8("DownloadListColsWidth"), width_list.join(QString::fromUtf8(" "))); + qDebug("Download list columns width saved"); +} + +// Load columns width in a file that were saved previously +// (download list) +bool DownloadingTorrents::loadColWidthDLList() { + qDebug("Loading columns width for download list"); + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + QString line = settings.value(QString::fromUtf8("DownloadListColsWidth"), QString()).toString(); + if(line.isEmpty()) + return false; + QStringList width_list = line.split(QString::fromUtf8(" ")); + if(width_list.size() != DLListModel->columnCount()-1) { + qDebug("Corrupted values for download list columns sizes"); + return false; + } + unsigned int listSize = width_list.size(); + for(unsigned int i=0; iheader()->resizeSection(i, width_list.at(i).toInt()); + } + // Loading last sorted column + QString sortedCol = settings.value(QString::fromUtf8("DownloadListSortedCol"), QString()).toString(); + if(!sortedCol.isEmpty()) { + Qt::SortOrder sortOrder; + if(sortedCol.endsWith(QString::fromUtf8("d"))) + sortOrder = Qt::DescendingOrder; + else + sortOrder = Qt::AscendingOrder; + sortedCol = sortedCol.left(sortedCol.size()-1); + int index = sortedCol.toInt(); + sortDownloadList(index, sortOrder, true); + } + qDebug("Download list columns width loaded"); + return true; +} + +// Called when a torrent is added +void DownloadingTorrents::torrentAdded(QString path, QTorrentHandle& h, bool fastResume) { + QString hash = h.hash(); + if(BTSession->isFinished(hash)) { + return; + } + int row = DLListModel->rowCount(); + // Adding torrent to download list + DLListModel->insertRow(row); + DLListModel->setData(DLListModel->index(row, NAME), QVariant(h.name())); + DLListModel->setData(DLListModel->index(row, SIZE), QVariant((qlonglong)h.actual_size())); + DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)0.)); + DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)0.)); + DLListModel->setData(DLListModel->index(row, SEEDSLEECH), QVariant(QString::fromUtf8("0/0"))); + DLListModel->setData(DLListModel->index(row, RATIO), QVariant(misc::toQString(BTSession->getRealRatio(hash)))); + DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1)); + DLListModel->setData(DLListModel->index(row, HASH), QVariant(hash)); + // Pause torrent if it was paused last time + // Not using isPaused function because torrents are paused after checking now + if(QFile::exists(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".paused"))) { + DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/paused.png"))), Qt::DecorationRole); + setRowColor(row, QString::fromUtf8("red")); + }else{ + DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/connecting.png"))), Qt::DecorationRole); + setRowColor(row, QString::fromUtf8("grey")); + } + if(!fastResume) { + setInfoBar(tr("'%1' added to download list.", "'/home/y/xxx.torrent' was added to download list.").arg(path)); + }else{ + setInfoBar(tr("'%1' resumed. (fast resume)", "'/home/y/xxx.torrent' was resumed. (fast resume)").arg(path)); + } + ++nbTorrents; + emit unfinishedTorrentsNumberChanged(nbTorrents); +} + +// Called when trying to add a duplicate torrent +void DownloadingTorrents::torrentDuplicate(QString path) { + setInfoBar(tr("'%1' is already in download list.", "e.g: 'xxx.avi' is already in download list.").arg(path)); +} + +void DownloadingTorrents::torrentCorrupted(QString path) { + setInfoBar(tr("Unable to decode torrent file: '%1'", "e.g: Unable to decode torrent file: '/home/y/xxx.torrent'").arg(path), QString::fromUtf8("red")); + setInfoBar(tr("This file is either corrupted or this isn't a torrent."),QString::fromUtf8("red")); +} + +void DownloadingTorrents::updateFileSizeAndProgress(QString hash) { + int row = getRowFromHash(hash); + Q_ASSERT(row != -1); + QTorrentHandle h = BTSession->getTorrentHandle(hash); + DLListModel->setData(DLListModel->index(row, SIZE), QVariant((qlonglong)h.actual_size())); + Q_ASSERT(h.progress() <= 1.); + DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)h.progress())); +} + +// Called when we couldn't listen on any port +// in the given range. +void DownloadingTorrents::portListeningFailure() { + setInfoBar(tr("Couldn't listen on any of the given ports."), QString::fromUtf8("red")); +} + +// Set the color of a row in data model +void DownloadingTorrents::setRowColor(int row, QString color) { + unsigned int nbColumns = DLListModel->columnCount(); + for(unsigned int i=0; isetData(DLListModel->index(row, i), QVariant(QColor(color)), Qt::ForegroundRole); + } +} + +// return the row of in data model +// corresponding to the given the hash +int DownloadingTorrents::getRowFromHash(QString hash) const{ + unsigned int nbRows = DLListModel->rowCount(); + for(unsigned int i=0; idata(DLListModel->index(i, HASH)) == hash) { + return i; + } + } + return -1; +} + +void DownloadingTorrents::displayDownloadingUrlInfos(QString url) { + setInfoBar(tr("Downloading '%1', please wait...", "e.g: Downloading 'xxx.torrent', please wait...").arg(url), QString::fromUtf8("black")); +} diff --git a/src/downloadingTorrents.h b/src/downloadingTorrents.h new file mode 100644 index 000000000..d2edab888 --- /dev/null +++ b/src/downloadingTorrents.h @@ -0,0 +1,97 @@ +/* + * 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. + * + * Contact : chris@qbittorrent.org + */ + +#ifndef DOWNLOADINGTORRENTS_H +#define DOWNLOADINGTORRENTS_H + +#include "ui_download.h" +#include "qtorrenthandle.h" + +class QStandardItemModel; +class bittorrent; +class DLListDelegate; + +using namespace libtorrent; + +class DownloadingTorrents : public QWidget, public Ui::downloading{ + Q_OBJECT + private: + bittorrent *BTSession; + DLListDelegate *DLDelegate; + QStandardItemModel *DLListModel; + unsigned int nbTorrents; + bool delayedSorting; + Qt::SortOrder delayedSortingOrder; + QObject *parent; + + public: + DownloadingTorrents(QObject *parent, bittorrent *BTSession); + ~DownloadingTorrents(); + // Methods + bool loadColWidthDLList(); + int getRowFromHash(QString hash) const; + QString getHashFromRow(unsigned int row) const; + QStringList getSelectedTorrents(bool only_one=false) const; + unsigned int getNbTorrentsInList() const; + + signals: + void unfinishedTorrentsNumberChanged(unsigned int); + void torrentDoubleClicked(QString hash); + void torrentFinished(QString hash); + + protected slots: + void addLogPeerBlocked(QString); + void addFastResumeRejectedAlert(QString); + void addUrlSeedError(QString url, QString msg); + void on_actionSet_download_limit_triggered(); + void notifyTorrentDoubleClicked(const QModelIndex& index); + void on_actionSet_upload_limit_triggered(); + void displayDLListMenu(const QPoint& pos); + void on_actionClearLog_triggered(); + void displayInfoBarMenu(const QPoint& pos); + void addTorrent(QString hash); + void sortDownloadList(int index, Qt::SortOrder startSortOrder=Qt::AscendingOrder, bool fromLoadColWidth=false); + void sortDownloadListFloat(int index, Qt::SortOrder sortOrder); + void sortDownloadListString(int index, Qt::SortOrder sortOrder); + void saveColWidthDLList() const; + void torrentAdded(QString path, QTorrentHandle& h, bool fastResume); + void torrentDuplicate(QString path); + void torrentCorrupted(QString path); + void updateFileSizeAndProgress(QString hash); + void portListeningFailure(); + void setRowColor(int row, QString color); + void displayDownloadingUrlInfos(QString url); + void showProperties(const QModelIndex &index); + + public slots: + void updateDlList(); + void setInfoBar(QString info, QString color="black"); + void pauseTorrent(QString hash); + void resumeTorrent(QString hash); + void updateRatio(); + void deleteTorrent(QString hash); + void setBottomTabEnabled(unsigned int index, bool b); + void propertiesSelection(); + void sortProgressColumnDelayed(); + +}; + +#endif diff --git a/src/src.pro b/src/src.pro index b06ae897d..2ca046af3 100644 --- a/src/src.pro +++ b/src/src.pro @@ -144,11 +144,12 @@ HEADERS += GUI.h misc.h options_imp.h about_imp.h \ bittorrent.h searchEngine.h \ rss.h rss_imp.h FinishedTorrents.h \ allocationDlg.h FinishedListDelegate.h \ - qtorrenthandle.h + qtorrenthandle.h downloadingTorrents.h FORMS += MainWindow.ui options.ui about.ui \ properties.ui createtorrent.ui preview.ui \ login.ui downloadFromURL.ui addTorrentDialog.ui \ - search.ui rss.ui seeding.ui bandwidth_limit.ui + search.ui rss.ui seeding.ui bandwidth_limit.ui \ + download.ui SOURCES += GUI.cpp \ main.cpp \ options_imp.cpp \ @@ -158,5 +159,6 @@ SOURCES += GUI.cpp \ searchEngine.cpp \ rss_imp.cpp \ FinishedTorrents.cpp \ - qtorrenthandle.cpp + qtorrenthandle.cpp \ + downloadingTorrents.cpp