diff --git a/src/DLListDelegate.h b/src/DLListDelegate.h deleted file mode 100644 index 641e493c0..000000000 --- a/src/DLListDelegate.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Bittorrent Client using Qt4 and libtorrent. - * Copyright (C) 2006 Christophe Dumez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * In addition, as a special exception, the copyright holders give permission to - * link this program with the OpenSSL project's "OpenSSL" library (or with - * modified versions of it that use the same license as the "OpenSSL" library), - * and distribute the linked executables. You must obey the GNU General Public - * License in all respects for all of the code used other than "OpenSSL". If you - * modify file(s), you may extend this exception to your version of the file(s), - * but you are not obligated to do so. If you do not wish to do so, delete this - * exception statement from your version. - * - * Contact : chris@qbittorrent.org - */ - -#ifndef DLLISTDELEGATE_H -#define DLLISTDELEGATE_H - -#include -#include -#include -#include -#include -#include -#include -#include "misc.h" - -// Defines for download list list columns -#define NAME 0 -#define SIZE 1 -#define PROGRESS 2 -#define DLSPEED 3 -#define UPSPEED 4 -#define SEEDSLEECH 5 -#define RATIO 6 -#define ETA 7 -#define PRIORITY 8 -#define HASH 9 - -class DLListDelegate: public QItemDelegate { - Q_OBJECT - - public: - DLListDelegate(QObject *parent) : QItemDelegate(parent){} - - ~DLListDelegate(){} - - void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const{ - QStyleOptionViewItemV2 opt = QItemDelegate::setOptions(index, option); - switch(index.column()){ - case SIZE: - QItemDelegate::drawBackground(painter, opt, index); - QItemDelegate::drawDisplay(painter, opt, option.rect, misc::friendlyUnit(index.data().toLongLong())); - break; - case ETA: - QItemDelegate::drawBackground(painter, opt, index); - QItemDelegate::drawDisplay(painter, opt, option.rect, misc::userFriendlyDuration(index.data().toLongLong())); - break; - case UPSPEED: - case DLSPEED:{ - QItemDelegate::drawBackground(painter, opt, index); - double speed = index.data().toDouble(); - QItemDelegate::drawDisplay(painter, opt, opt.rect, QString(QByteArray::number(speed/1024., 'f', 1))+QString::fromUtf8(" ")+tr("KiB/s")); - break; - } - case RATIO:{ - QItemDelegate::drawBackground(painter, opt, index); - double ratio = index.data().toDouble(); - if(ratio > 100.) - QItemDelegate::drawDisplay(painter, opt, opt.rect, QString::fromUtf8("∞")); - else - QItemDelegate::drawDisplay(painter, opt, opt.rect, QString(QByteArray::number(ratio, 'f', 1))); - break; - } - case PROGRESS:{ - QStyleOptionProgressBarV2 newopt; - double progress = index.data().toDouble()*100.; - newopt.rect = opt.rect; - newopt.text = QString(QByteArray::number(progress, 'f', 1))+QString::fromUtf8("%"); - newopt.progress = (int)progress; - newopt.maximum = 100; - newopt.minimum = 0; - newopt.state |= QStyle::State_Enabled; - newopt.textVisible = true; - QApplication::style()->drawControl(QStyle::CE_ProgressBar, &newopt, - painter); - break; - } - default: - QItemDelegate::paint(painter, option, index); - } - } - - QWidget* createEditor(QWidget*, const QStyleOptionViewItem &, const QModelIndex &) const { - // No editor here - return 0; - } - -}; - -#endif diff --git a/src/FinishedListDelegate.h b/src/FinishedListDelegate.h deleted file mode 100644 index 0fb0495a4..000000000 --- a/src/FinishedListDelegate.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Bittorrent Client using Qt4 and libtorrent. - * Copyright (C) 2006 Christophe Dumez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * In addition, as a special exception, the copyright holders give permission to - * link this program with the OpenSSL project's "OpenSSL" library (or with - * modified versions of it that use the same license as the "OpenSSL" library), - * and distribute the linked executables. You must obey the GNU General Public - * License in all respects for all of the code used other than "OpenSSL". If you - * modify file(s), you may extend this exception to your version of the file(s), - * but you are not obligated to do so. If you do not wish to do so, delete this - * exception statement from your version. - * - * Contact : chris@qbittorrent.org - */ - -#ifndef FINISHEDLISTDELEGATE_H -#define FINISHEDLISTDELEGATE_H - -#include -#include -#include -#include -#include -#include -#include -#include "misc.h" - -// Defines for download list list columns -#define F_NAME 0 -#define F_SIZE 1 -#define F_UPSPEED 2 -#define F_SWARM 3 -#define F_PEERS 4 -#define F_UPLOAD 5 -#define F_RATIO 6 -#define F_HASH 7 - -#define MAX_RATIO 100. - -class FinishedListDelegate: public QItemDelegate { - Q_OBJECT - - public: - FinishedListDelegate(QObject *parent) : QItemDelegate(parent){} - - ~FinishedListDelegate(){} - - void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const{ - QStyleOptionViewItemV2 opt = QItemDelegate::setOptions(index, option); - switch(index.column()){ - case F_SIZE: - case F_UPLOAD: - QItemDelegate::drawBackground(painter, opt, index); - QItemDelegate::drawDisplay(painter, opt, option.rect, misc::friendlyUnit(index.data().toLongLong())); - break; - case F_UPSPEED:{ - QItemDelegate::drawBackground(painter, opt, index); - double speed = index.data().toDouble(); - QItemDelegate::drawDisplay(painter, opt, opt.rect, QString(QByteArray::number(speed/1024., 'f', 1))+QString::fromUtf8(" ")+tr("KiB/s")); - break; - } - case F_RATIO:{ - QItemDelegate::drawBackground(painter, opt, index); - double ratio = index.data().toDouble(); - if(ratio > MAX_RATIO) - QItemDelegate::drawDisplay(painter, opt, opt.rect, QString::fromUtf8("∞")); - else - QItemDelegate::drawDisplay(painter, opt, opt.rect, QString(QByteArray::number(ratio, 'f', 1))); - break; - } - default: - QItemDelegate::paint(painter, option, index); - } - } - - QWidget* createEditor(QWidget*, const QStyleOptionViewItem &, const QModelIndex &) const { - // No editor here - return 0; - } - -}; - -#endif diff --git a/src/FinishedTorrents.cpp b/src/FinishedTorrents.cpp deleted file mode 100644 index 9feace584..000000000 --- a/src/FinishedTorrents.cpp +++ /dev/null @@ -1,699 +0,0 @@ -/* - * Bittorrent Client using Qt4 and libtorrent. - * Copyright (C) 2006 Christophe Dumez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * In addition, as a special exception, the copyright holders give permission to - * link this program with the OpenSSL project's "OpenSSL" library (or with - * modified versions of it that use the same license as the "OpenSSL" library), - * and distribute the linked executables. You must obey the GNU General Public - * License in all respects for all of the code used other than "OpenSSL". If you - * modify file(s), you may extend this exception to your version of the file(s), - * but you are not obligated to do so. If you do not wish to do so, delete this - * exception statement from your version. - * - * Contact : chris@qbittorrent.org - */ -#include "FinishedTorrents.h" -#include "misc.h" -#include "properties_imp.h" -#include "bittorrent.h" -#include "allocationDlg.h" -#include "FinishedListDelegate.h" -#include "GUI.h" - -#include -#include -#include -#include -#include -#include -#include - -FinishedTorrents::FinishedTorrents(QObject *parent, bittorrent *BTSession) : parent(parent), BTSession(BTSession), nbFinished(0){ - setupUi(this); - actionStart->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/play.png"))); - actionPause->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/pause.png"))); - finishedListModel = new QStandardItemModel(0,8); - finishedListModel->setHeaderData(F_NAME, Qt::Horizontal, tr("Name", "i.e: file name")); - finishedListModel->setHeaderData(F_SIZE, Qt::Horizontal, tr("Size", "i.e: file size")); - finishedListModel->setHeaderData(F_UPSPEED, Qt::Horizontal, tr("UP Speed", "i.e: Upload speed")); - finishedListModel->setHeaderData(F_SWARM, Qt::Horizontal, tr("Seeds / Leechers")); - finishedListModel->setHeaderData(F_PEERS, Qt::Horizontal, tr("Connected peers")); - finishedListModel->setHeaderData(F_UPLOAD, Qt::Horizontal, tr("Total uploaded", "i.e: Total amount of uploaded data")); - finishedListModel->setHeaderData(F_RATIO, Qt::Horizontal, tr("Ratio")); - - proxyModel = new QSortFilterProxyModel(); - proxyModel->setDynamicSortFilter(true); - proxyModel->setSourceModel(finishedListModel); - finishedList->setModel(proxyModel); - - finishedList->setRootIsDecorated(false); - finishedList->setAllColumnsShowFocus(true); - finishedList->setSortingEnabled(true); - - loadHiddenColumns(); - // Hide hash column - finishedList->hideColumn(F_HASH); - // Load last columns width for download list - if(!loadColWidthFinishedList()){ - finishedList->header()->resizeSection(0, 200); - } - // Connect BTSession signals - connect(BTSession, SIGNAL(metadataReceived(QTorrentHandle&)), this, SLOT(updateMetadata(QTorrentHandle&))); - // Make download list header clickable for sorting - finishedList->header()->setClickable(true); - finishedList->header()->setSortIndicatorShown(true); - finishedListDelegate = new FinishedListDelegate(finishedList); - finishedList->setItemDelegate(finishedListDelegate); - connect(finishedList, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayFinishedListMenu(const QPoint&))); - finishedList->header()->setContextMenuPolicy(Qt::CustomContextMenu); - connect(finishedList->header(), SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayFinishedHoSMenu(const QPoint&))); - 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"))); - actionTorrent_Properties->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/properties.png"))); - actionSet_upload_limit->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/seeding.png"))); - actionCopy_magnet_link->setIcon(QIcon(QString::fromUtf8(":/Icons/magnet.png"))); - - connect(actionPause, SIGNAL(triggered()), (GUI*)parent, SLOT(on_actionPause_triggered())); - connect(actionStart, SIGNAL(triggered()), (GUI*)parent, SLOT(on_actionStart_triggered())); - 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(actionOpen_destination_folder, SIGNAL(triggered()), (GUI*)parent, SLOT(openDestinationFolder())); - connect(actionBuy_it, SIGNAL(triggered()), (GUI*)parent, SLOT(goBuyPage())); - connect(actionTorrent_Properties, SIGNAL(triggered()), this, SLOT(propertiesSelection())); - connect(actionForce_recheck, SIGNAL(triggered()), this, SLOT(forceRecheck())); - connect(actionCopy_magnet_link, SIGNAL(triggered()), (GUI*)parent, SLOT(copyMagnetURI())); - - connect(actionHOSColName, SIGNAL(triggered()), this, SLOT(hideOrShowColumnName())); - connect(actionHOSColSize, SIGNAL(triggered()), this, SLOT(hideOrShowColumnSize())); - connect(actionHOSColUpSpeed, SIGNAL(triggered()), this, SLOT(hideOrShowColumnUpSpeed())); - connect(actionHOSColSwarm, SIGNAL(triggered()), this, SLOT(hideOrShowColumnSwarm())); - connect(actionHOSColPeers, SIGNAL(triggered()), this, SLOT(hideOrShowColumnPeers())); - connect(actionHOSColUpload, SIGNAL(triggered()), this, SLOT(hideOrShowColumnUpload())); - connect(actionHOSColRatio, SIGNAL(triggered()), this, SLOT(hideOrShowColumnRatio())); -} - -FinishedTorrents::~FinishedTorrents(){ - saveLastSortedColumn(); - saveColWidthFinishedList(); - saveHiddenColumns(); - delete finishedListDelegate; - delete proxyModel; - delete finishedListModel; -} - -void FinishedTorrents::notifyTorrentDoubleClicked(const QModelIndex& index) { - unsigned int row = index.row(); - QString hash = getHashFromRow(row); - emit torrentDoubleClicked(hash, true); -} - -void FinishedTorrents::addTorrent(QString hash){ - int row = getRowFromHash(hash); - if(row != -1) return; - row = finishedListModel->rowCount(); - QTorrentHandle h = BTSession->getTorrentHandle(hash); - // Adding torrent to download list - finishedListModel->insertRow(row); - finishedListModel->setData(finishedListModel->index(row, F_NAME), QVariant(h.name())); - finishedListModel->setData(finishedListModel->index(row, F_SIZE), QVariant((qlonglong)h.actual_size())); - finishedListModel->setData(finishedListModel->index(row, F_UPSPEED), QVariant((double)0.)); - finishedListModel->setData(finishedListModel->index(row, F_SWARM), QVariant("-1/-1")); - finishedListModel->setData(finishedListModel->index(row, F_PEERS), QVariant("0")); - finishedListModel->setData(finishedListModel->index(row, F_UPLOAD), QVariant((qlonglong)h.all_time_upload())); - finishedListModel->setData(finishedListModel->index(row, F_RATIO), QVariant(QString::fromUtf8(misc::toString(BTSession->getRealRatio(hash)).c_str()))); - finishedListModel->setData(finishedListModel->index(row, F_HASH), QVariant(hash)); - if(h.is_paused()) { - finishedListModel->setData(finishedListModel->index(row, F_NAME), QIcon(":/Icons/skin/paused.png"), Qt::DecorationRole); - setRowColor(row, "red"); - }else{ - finishedListModel->setData(finishedListModel->index(row, F_NAME), QVariant(QIcon(":/Icons/skin/seeding.png")), Qt::DecorationRole); - setRowColor(row, "orange"); - } - // Update the number of finished torrents - ++nbFinished; - emit finishedTorrentsNumberChanged(nbFinished); - - loadLastSortedColumn(); -} - -// Set the color of a row in data model -void FinishedTorrents::setRowColor(int row, QString color){ - unsigned int nbColumns = finishedListModel->columnCount()-1; - for(unsigned int i=0; isetData(finishedListModel->index(row, i), QVariant(QColor(color)), Qt::ForegroundRole); - } -} - -QStringList FinishedTorrents::getSelectedTorrents(bool only_one) const{ - QStringList res; - QModelIndexList selectedIndexes = finishedList->selectionModel()->selectedIndexes(); - foreach(const QModelIndex &index, selectedIndexes) { - if(index.column() == F_NAME) { - // Get the file hash - QString hash = getHashFromRow(index.row()); - 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(){ - qDebug("Loading columns width for finished list"); - QSettings settings("qBittorrent", "qBittorrent"); - QString line = settings.value("FinishedListColsWidth", QString()).toString(); - if(line.isEmpty()) - return false; - QStringList width_list = line.split(' '); - if(width_list.size() < finishedListModel->columnCount()-1) - return false; - unsigned int listSize = width_list.size(); - for(unsigned int i=0; iheader()->resizeSection(i, width_list.at(i).toInt()); - } - loadLastSortedColumn(); - QVariantList visualIndexes = settings.value(QString::fromUtf8("FinishedListVisualIndexes"), QVariantList()).toList(); - if(visualIndexes.size() != finishedListModel->columnCount()-1) { - qDebug("Corrupted values for download list columns sizes"); - return false; - } - bool change = false; - do { - change = false; - for(int i=0;iheader()->logicalIndex(i)).toInt(); - if(i != new_visual_index) { - qDebug("Moving column from %d to %d", finishedList->header()->logicalIndex(i), new_visual_index); - finishedList->header()->moveSection(i, new_visual_index); - change = true; - } - } - }while(change); - qDebug("Finished list columns width loaded"); - return true; -} - -void FinishedTorrents::saveLastSortedColumn() { - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - Qt::SortOrder sortOrder = finishedList->header()->sortIndicatorOrder(); - QString sortOrderLetter; - if(sortOrder == Qt::AscendingOrder) - sortOrderLetter = QString::fromUtf8("a"); - else - sortOrderLetter = QString::fromUtf8("d"); - int index = finishedList->header()->sortIndicatorSection(); - settings.setValue(QString::fromUtf8("FinishedListSortedCol"), misc::toQString(index)+sortOrderLetter); -} - -void FinishedTorrents::loadLastSortedColumn() { - // Loading last sorted column - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - QString sortedCol = settings.value(QString::fromUtf8("FinishedListSortedCol"), 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(); - finishedList->sortByColumn(index, sortOrder); - } -} - -// Save columns width in a file to remember them -// (finished list) -void FinishedTorrents::saveColWidthFinishedList() const{ - qDebug("Saving columns width in finished list"); - QSettings settings("qBittorrent", "qBittorrent"); - QStringList width_list; - QStringList new_width_list; - short nbColumns = finishedListModel->columnCount()-1; - - QString line = settings.value("FinishedListColsWidth", QString()).toString(); - if(!line.isEmpty()) { - width_list = line.split(' '); - } - for(short i=0; icolumnWidth(i)<1 && width_list.size() == nbColumns && width_list.at(i).toInt()>=1) { - // load the former width - new_width_list << width_list.at(i); - } else if(finishedList->columnWidth(i)>=1) { - // usual case, save the current width - new_width_list << QString::fromUtf8(misc::toString(finishedList->columnWidth(i)).c_str()); - } else { - // default width - finishedList->resizeColumnToContents(i); - new_width_list << QString::fromUtf8(misc::toString(finishedList->columnWidth(i)).c_str()); - } - } - settings.setValue("FinishedListColsWidth", new_width_list.join(" ")); - QVariantList visualIndexes; - for(int i=0; iheader()->visualIndex(i)); - } - settings.setValue(QString::fromUtf8("FinishedListVisualIndexes"), visualIndexes); - qDebug("Finished list columns width saved"); -} - -void FinishedTorrents::on_actionSet_upload_limit_triggered(){ - QModelIndexList selectedIndexes = finishedList->selectionModel()->selectedIndexes(); - QStringList hashes; - foreach(const QModelIndex &index, selectedIndexes){ - if(index.column() == F_NAME){ - // Get the file hash - hashes << getHashFromRow(index.row()); - } - } - new BandwidthAllocationDialog(this, true, BTSession, hashes); -} - -void FinishedTorrents::updateMetadata(QTorrentHandle &h) { - QString hash = h.hash(); - int row = getRowFromHash(hash); - if(row != -1) { - qDebug("Updating torrent metadata in download list"); - finishedListModel->setData(finishedListModel->index(row, F_NAME), QVariant(h.name())); - finishedListModel->setData(finishedListModel->index(row, F_SIZE), QVariant((qlonglong)h.actual_size())); - } -} - -void FinishedTorrents::updateTorrent(QTorrentHandle h) { - if(!h.is_valid()) return; - QString hash = h.hash(); - int row = getRowFromHash(hash); - if(row == -1){ - qDebug("Cannot find torrent in finished list, adding it"); - addTorrent(hash); - row = getRowFromHash(hash); - } - Q_ASSERT(row != -1); - if(!finishedList->isColumnHidden(F_SWARM)) { - finishedListModel->setData(finishedListModel->index(row, F_SWARM), misc::toQString(h.num_complete())+QString("/")+misc::toQString(h.num_incomplete())); - } - if(h.is_paused()) return; - // Update queued torrent - if(BTSession->isQueueingEnabled() && h.is_queued()) { - if(h.state() == torrent_status::checking_files || h.state() == torrent_status::queued_for_checking){ - finishedListModel->setData(finishedListModel->index(row, F_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/oxygen/time.png"))), Qt::DecorationRole); - } else { - finishedListModel->setData(finishedListModel->index(row, F_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/queued.png"))), Qt::DecorationRole); - } - // Reset upload speed and seeds/leech - finishedListModel->setData(finishedListModel->index(row, F_UPSPEED), 0.); - finishedListModel->setData(finishedListModel->index(row, F_PEERS), "0"); - setRowColor(row, QString::fromUtf8("grey")); - return; - } - if(h.state() == torrent_status::checking_files || h.state() == torrent_status::queued_for_checking){ - finishedListModel->setData(finishedListModel->index(row, F_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/oxygen/time.png"))), Qt::DecorationRole); - setRowColor(row, QString::fromUtf8("grey")); - return; - } - setRowColor(row, QString::fromUtf8("orange")); - finishedListModel->setData(finishedListModel->index(row, F_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/seeding.png"))), Qt::DecorationRole); - if(!finishedList->isColumnHidden(F_UPSPEED)) { - finishedListModel->setData(finishedListModel->index(row, F_UPSPEED), QVariant((double)h.upload_payload_rate())); - } - if(!finishedList->isColumnHidden(F_PEERS)) { - finishedListModel->setData(finishedListModel->index(row, F_PEERS), misc::toQString(h.num_peers() - h.num_seeds(), true)); - } - if(!finishedList->isColumnHidden(F_UPLOAD)) { - finishedListModel->setData(finishedListModel->index(row, F_UPLOAD), QVariant((double)h.all_time_upload())); - } - if(!finishedList->isColumnHidden(F_RATIO)) { - finishedListModel->setData(finishedListModel->index(row, F_RATIO), QVariant(misc::toQString(BTSession->getRealRatio(hash)))); - } -} - -int FinishedTorrents::getRowFromHash(QString hash) const{ - unsigned int nbRows = finishedListModel->rowCount(); - for(unsigned int i=0; idata(finishedListModel->index(i, F_HASH)) == hash){ - return i; - } - } - return -1; -} - -// Note: does not actually pause the torrent in BT Session -void FinishedTorrents::pauseTorrent(QString hash) { - int row = getRowFromHash(hash); - if(row == -1) - return; - 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_PEERS), QVariant(QString::fromUtf8("0"))); - setRowColor(row, QString::fromUtf8("red")); -} - -QString FinishedTorrents::getHashFromRow(unsigned int row) const { - Q_ASSERT(row < (unsigned int)proxyModel->rowCount()); - return proxyModel->data(proxyModel->index(row, F_HASH)).toString(); -} - -// Will move it to download tab -void FinishedTorrents::deleteTorrent(QString hash){ - int row = getRowFromHash(hash); - if(row == -1){ - qDebug("Torrent is not in finished list, nothing to delete"); - return; - } - // Select item just under (or above nothing under) the one that was deleted - QModelIndex current_prox_index = proxyModel->mapFromSource(finishedListModel->index(row, 0, finishedList->rootIndex())); - bool was_selected = finishedList->selectionModel()->isSelected(current_prox_index); - if(finishedListModel->rowCount() > 1 && was_selected) { - QModelIndex under_prox_index; - if(current_prox_index.row() == finishedListModel->rowCount()-1) - under_prox_index = proxyModel->index(current_prox_index.row()-1, 0); - else - under_prox_index = proxyModel->index(current_prox_index.row()+1, 0); - //downloadList->selectionModel()->select(under_prox_index, QItemSelectionModel::Current|QItemSelectionModel::Columns|QItemSelectionModel::Select); - finishedList->setCurrentIndex(under_prox_index); - finishedList->update(); - } - // Actually delete the row - finishedListModel->removeRow(row); - --nbFinished; - emit finishedTorrentsNumberChanged(nbFinished); -} - -// Show torrent properties dialog -void FinishedTorrents::showProperties(const QModelIndex &index){ - showPropertiesFromHash(getHashFromRow(index.row())); -} - -void FinishedTorrents::showPropertiesFromHash(QString hash){ - QTorrentHandle h = BTSession->getTorrentHandle(hash); - properties *prop = new properties(this, BTSession, h); - connect(prop, SIGNAL(filteredFilesChanged(QString)), this, SLOT(updateFileSize(QString))); - connect(prop, SIGNAL(trackersChanged(QString)), BTSession, SLOT(saveTrackerFile(QString))); - prop->show(); -} - -void FinishedTorrents::updateFileSize(QString hash){ - int row = getRowFromHash(hash); - QTorrentHandle h = BTSession->getTorrentHandle(hash); - finishedListModel->setData(finishedListModel->index(row, F_SIZE), QVariant((qlonglong)h.actual_size())); -} - -// display properties of selected items -void FinishedTorrents::propertiesSelection(){ - QModelIndexList selectedIndexes = finishedList->selectionModel()->selectedIndexes(); - foreach(const QModelIndex &index, selectedIndexes){ - if(index.column() == F_NAME){ - showProperties(index); - } - } -} - -void FinishedTorrents::forceRecheck(){ - QModelIndexList selectedIndexes = finishedList->selectionModel()->selectedIndexes(); - foreach(const QModelIndex &index, selectedIndexes){ - if(index.column() == F_NAME){ - QString hash = getHashFromRow(index.row()); - QTorrentHandle h = BTSession->getTorrentHandle(hash); - qDebug("Forcing recheck for torrent %s", hash.toLocal8Bit().data()); - h.force_recheck(); - } - } -} - -void FinishedTorrents::displayFinishedListMenu(const QPoint&){ - QMenu myFinishedListMenu(this); - // Enable/disable pause/start action given the DL state - QModelIndexList selectedIndexes = finishedList->selectionModel()->selectedIndexes(); - bool has_pause = false, has_start = false, has_preview = false, hide_uper_seeding = false, super_seeding_enabled = false; - bool first_torrent = true; - foreach(const QModelIndex &index, selectedIndexes) { - if(index.column() == F_NAME) { - // Get the file name - QString hash = getHashFromRow(index.row()); - // Get handle and pause the torrent - QTorrentHandle h = BTSession->getTorrentHandle(hash); - if(!h.is_valid()) continue; - if(h.is_paused()) { - if(!has_start) { - myFinishedListMenu.addAction(actionStart); - has_start = true; - } - }else{ - if(!has_pause) { - myFinishedListMenu.addAction(actionPause); - has_pause = true; - } - } - if(BTSession->isFilePreviewPossible(hash) && !has_preview) { - myFinishedListMenu.addAction(actionPreview_file); - has_preview = true; - } - if(h.super_seeding()) { - if(first_torrent) { - super_seeding_enabled = true; - } else { - if(!super_seeding_enabled) hide_uper_seeding = true; - } - } else { - if(!first_torrent) { - if(super_seeding_enabled) hide_uper_seeding = true; - } - } - first_torrent = false; - if(has_pause && has_start && has_preview && hide_uper_seeding) break; - } - } - myFinishedListMenu.addSeparator(); - myFinishedListMenu.addAction(actionDelete); - myFinishedListMenu.addAction(actionDelete_Permanently); - myFinishedListMenu.addSeparator(); - if(!hide_uper_seeding) { - QAction *act; - if(super_seeding_enabled) - act = myFinishedListMenu.addAction(QIcon(":/Icons/oxygen/button_ok.png"), tr("Super seeding mode")); - else - act = myFinishedListMenu.addAction(QIcon(":/Icons/oxygen/button_cancel.png"), tr("Super seeding mode")); - // Bind signal / slot - connect(act, SIGNAL(triggered()), this, SLOT(toggleSuperSeedingMode())); - } - myFinishedListMenu.addAction(actionSet_upload_limit); - myFinishedListMenu.addSeparator(); - myFinishedListMenu.addAction(actionForce_recheck); - myFinishedListMenu.addSeparator(); - myFinishedListMenu.addAction(actionOpen_destination_folder); - myFinishedListMenu.addAction(actionTorrent_Properties); - myFinishedListMenu.addSeparator(); - myFinishedListMenu.addAction(actionCopy_magnet_link); - myFinishedListMenu.addAction(actionBuy_it); - - // Call menu - myFinishedListMenu.exec(QCursor::pos()); -} - - -/* - * Hiding Columns functions - */ - -// hide/show columns menu -void FinishedTorrents::displayFinishedHoSMenu(const QPoint&){ - QMenu hideshowColumn(this); - hideshowColumn.setTitle(tr("Hide or Show Column")); - int lastCol = F_RATIO; - for(int i=0; i<=lastCol; i++) { - hideshowColumn.addAction(getActionHoSCol(i)); - } - // Call menu - hideshowColumn.exec(QCursor::pos()); -} - -void FinishedTorrents::toggleSuperSeedingMode() { - QModelIndexList selectedIndexes = finishedList->selectionModel()->selectedIndexes(); - bool super_seeding_enabled = false, first_torrent=true; - // Check whether we should disable or enable super seeding mode - foreach(const QModelIndex &index, selectedIndexes) { - if(index.column() == F_NAME) { - // Get the file name - QString hash = getHashFromRow(index.row()); - // Get handle and pause the torrent - QTorrentHandle h = BTSession->getTorrentHandle(hash); - if(!h.is_valid()) continue; - if(h.super_seeding()) { - if(first_torrent) { - super_seeding_enabled = true; - } - } else { - if(!first_torrent) { - if(super_seeding_enabled) super_seeding_enabled = false; - } - } - first_torrent = false; - } - } - // Toggling super seeding mode - foreach(const QModelIndex &index, selectedIndexes) { - if(index.column() == F_NAME) { - // Get the file name - QString hash = getHashFromRow(index.row()); - // Get handle and pause the torrent - QTorrentHandle h = BTSession->getTorrentHandle(hash); - if(!h.is_valid()) continue; - qDebug("Seeding mode=%d for torrent %s",!super_seeding_enabled, h.name().toLocal8Bit().data()); - h.super_seeding(!super_seeding_enabled); - } - } -} - -// toggle hide/show a column -void FinishedTorrents::hideOrShowColumn(int index) { - unsigned int nbVisibleColumns = 0; - unsigned int nbCols = finishedListModel->columnCount(); - // Count visible columns - for(unsigned int i=0; iisColumnHidden(i)) - ++nbVisibleColumns; - } - if(!finishedList->isColumnHidden(index)) { - // User wants to hide the column - // Is there at least one other visible column? - if(nbVisibleColumns <= 1) return; - // User can hide the column, do it. - finishedList->setColumnHidden(index, true); - getActionHoSCol(index)->setIcon(QIcon(QString::fromUtf8(":/Icons/oxygen/button_cancel.png"))); - --nbVisibleColumns; - } else { - // User want to display the column - finishedList->setColumnHidden(index, false); - getActionHoSCol(index)->setIcon(QIcon(QString::fromUtf8(":/Icons/oxygen/button_ok.png"))); - ++nbVisibleColumns; - } - //resize all others non-hidden columns - for(unsigned int i=0; iisColumnHidden(i)) { - finishedList->setColumnWidth(i, (int)ceil(finishedList->columnWidth(i)+(finishedList->columnWidth(index)/nbVisibleColumns))); - } - } -} - -void FinishedTorrents::hideOrShowColumnName() { - hideOrShowColumn(F_NAME); -} - -void FinishedTorrents::hideOrShowColumnSize() { - hideOrShowColumn(F_SIZE); -} - -void FinishedTorrents::hideOrShowColumnUpSpeed() { - hideOrShowColumn(F_UPSPEED); -} - -void FinishedTorrents::hideOrShowColumnSwarm() { - hideOrShowColumn(F_SWARM); -} - -void FinishedTorrents::hideOrShowColumnPeers() { - hideOrShowColumn(F_PEERS); -} - -void FinishedTorrents::hideOrShowColumnUpload() { - hideOrShowColumn(F_UPLOAD); -} - -void FinishedTorrents::hideOrShowColumnRatio() { - hideOrShowColumn(F_RATIO); -} - -// load the previous settings, and hide the columns -bool FinishedTorrents::loadHiddenColumns() { - bool loaded = false; - QSettings settings("qBittorrent", "qBittorrent"); - QString line = settings.value("FinishedListColsHoS", QString()).toString(); - QStringList ishidden_list; - if(!line.isEmpty()) { - ishidden_list = line.split(' '); - if(ishidden_list.size() == finishedListModel->columnCount()-1) { - unsigned int listSize = ishidden_list.size(); - for(unsigned int i=0; iheader()->resizeSection(i, ishidden_list.at(i).toInt()); - } - loaded = true; - } - } - for(int i=0; icolumnCount()-1; i++) { - if(loaded && ishidden_list.at(i) == "0") { - finishedList->setColumnHidden(i, true); - getActionHoSCol(i)->setIcon(QIcon(QString::fromUtf8(":/Icons/oxygen/button_cancel.png"))); - } else { - getActionHoSCol(i)->setIcon(QIcon(QString::fromUtf8(":/Icons/oxygen/button_ok.png"))); - } - } - return loaded; -} - -// save the hidden columns in settings -void FinishedTorrents::saveHiddenColumns() { - QSettings settings("qBittorrent", "qBittorrent"); - QStringList ishidden_list; - short nbColumns = finishedListModel->columnCount()-1; - - for(short i=0; iisColumnHidden(i)) { - ishidden_list << QString::fromUtf8(misc::toString(0).c_str()); - } else { - ishidden_list << QString::fromUtf8(misc::toString(1).c_str()); - } - } - settings.setValue("FinishedListColsHoS", ishidden_list.join(" ")); -} - -// getter, return the action hide or show whose id is index -QAction* FinishedTorrents::getActionHoSCol(int index) { - switch(index) { - case F_NAME : - return actionHOSColName; - break; - case F_SIZE : - return actionHOSColSize; - break; - case F_UPSPEED : - return actionHOSColUpSpeed; - break; - case F_SWARM : - return actionHOSColSwarm; - break; - case F_PEERS : - return actionHOSColPeers; - break; - case F_UPLOAD : - return actionHOSColUpload; - break; - case F_RATIO : - return actionHOSColRatio; - break; - default : - return NULL; - } -} diff --git a/src/FinishedTorrents.h b/src/FinishedTorrents.h deleted file mode 100644 index f28cac0a7..000000000 --- a/src/FinishedTorrents.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Bittorrent Client using Qt4 and libtorrent. - * Copyright (C) 2006 Christophe Dumez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * In addition, as a special exception, the copyright holders give permission to - * link this program with the OpenSSL project's "OpenSSL" library (or with - * modified versions of it that use the same license as the "OpenSSL" library), - * and distribute the linked executables. You must obey the GNU General Public - * License in all respects for all of the code used other than "OpenSSL". If you - * modify file(s), you may extend this exception to your version of the file(s), - * but you are not obligated to do so. If you do not wish to do so, delete this - * exception statement from your version. - * - * Contact : chris@qbittorrent.org - */ - -#ifndef SEEDING_H -#define SEEDING_H - -#include "ui_seeding.h" -#include "qtorrenthandle.h" - -class QStandardItemModel; -class QSortFilterProxyModel; -class bittorrent; -class FinishedListDelegate; - -using namespace libtorrent; - -class FinishedTorrents : public QWidget, public Ui::seeding { - Q_OBJECT - private: - QObject *parent; - bittorrent *BTSession; - FinishedListDelegate *finishedListDelegate; - QStandardItemModel *finishedListModel; - QSortFilterProxyModel *proxyModel; - unsigned int nbFinished; - void hideOrShowColumn(int index); - bool loadHiddenColumns(); - void saveHiddenColumns(); - QAction* getActionHoSCol(int index); - - public: - FinishedTorrents(QObject *parent, bittorrent *BTSession); - ~FinishedTorrents(); - // Methods - bool loadColWidthFinishedList(); - int getRowFromHash(QString hash) const; - QStringList getSelectedTorrents(bool only_one=false) const; - unsigned int getNbTorrentsInList() const; - QString getHashFromRow(unsigned int row) const; - - protected slots: - void showProperties(const QModelIndex &index); - void displayFinishedListMenu(const QPoint&); - void displayFinishedHoSMenu(const QPoint&); - void setRowColor(int row, QString color); - void saveColWidthFinishedList() const; - void updateFileSize(QString hash); - void on_actionSet_upload_limit_triggered(); - void notifyTorrentDoubleClicked(const QModelIndex& index); - void hideOrShowColumnName(); - void hideOrShowColumnSize(); - void hideOrShowColumnUpSpeed(); - void hideOrShowColumnSwarm(); - void hideOrShowColumnPeers(); - void hideOrShowColumnUpload(); - void hideOrShowColumnRatio(); - void forceRecheck(); - void toggleSuperSeedingMode(); - - public slots: - void addTorrent(QString hash); - void updateTorrent(QTorrentHandle h); - void pauseTorrent(QString hash); - void propertiesSelection(); - void deleteTorrent(QString hash); - void showPropertiesFromHash(QString hash); - void loadLastSortedColumn(); - void saveLastSortedColumn(); - void updateMetadata(QTorrentHandle &h); - - signals: - void torrentMovedFromFinishedList(QString); - void torrentDoubleClicked(QString hash, bool finished); - void finishedTorrentsNumberChanged(unsigned int); - -}; - -#endif diff --git a/src/GUI.cpp b/src/GUI.cpp index 62f98af5c..4ce60dc65 100644 --- a/src/GUI.cpp +++ b/src/GUI.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -46,24 +47,24 @@ #include #include "GUI.h" -#include "downloadingTorrents.h" +#include "TransferListWidget.h" #include "misc.h" #include "createtorrent_imp.h" #include "downloadFromURLImp.h" #include "torrentAddition.h" #include "searchEngine.h" #include "rss_imp.h" -#include "FinishedTorrents.h" #include "bittorrent.h" #include "about_imp.h" #include "trackerLogin.h" #include "options_imp.h" -#include "previewSelect.h" #include "allocationDlg.h" #include #include "console_imp.h" #include "httpserver.h" #include "torrentPersistentData.h" +#include "TransferListFiltersWidget.h" +#include "propertieswidget.h" using namespace libtorrent; @@ -74,7 +75,7 @@ using namespace libtorrent; *****************************************************/ // Constructor -GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), displaySpeedInTitle(false), force_exit(false), refreshInterval(1500) { +GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), displaySpeedInTitle(false), force_exit(false) { setupUi(this); setWindowTitle(tr("qBittorrent %1", "e.g: qBittorrent v0.x").arg(QString::fromUtf8(VERSION))); QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); @@ -131,47 +132,55 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), dis BTSession = new bittorrent(); connect(BTSession, SIGNAL(fullDiskError(QTorrentHandle&, QString)), this, SLOT(fullDiskError(QTorrentHandle&, QString))); connect(BTSession, SIGNAL(finishedTorrent(QTorrentHandle&)), this, SLOT(finishedTorrent(QTorrentHandle&))); - connect(BTSession, SIGNAL(addedTorrent(QTorrentHandle&)), this, SLOT(addedTorrent(QTorrentHandle&))); - connect(BTSession, SIGNAL(pausedTorrent(QTorrentHandle&)), this, SLOT(pausedTorrent(QTorrentHandle&))); - connect(BTSession, SIGNAL(resumedTorrent(QTorrentHandle&)), this, SLOT(resumedTorrent(QTorrentHandle&))); - connect(BTSession, SIGNAL(torrentFinishedChecking(QTorrentHandle&)), this, SLOT(checkedTorrent(QTorrentHandle&))); connect(BTSession, SIGNAL(trackerAuthenticationRequired(QTorrentHandle&)), this, SLOT(trackerAuthenticationRequired(QTorrentHandle&))); connect(BTSession, SIGNAL(newDownloadedTorrent(QString, QString)), this, SLOT(processDownloadedFiles(QString, QString))); connect(BTSession, SIGNAL(downloadFromUrlFailure(QString, QString)), this, SLOT(handleDownloadFromUrlFailure(QString, QString))); - connect(BTSession, SIGNAL(deletedTorrent(QString)), this, SLOT(deleteTorrent(QString))); - connect(BTSession, SIGNAL(torrentPaused(QTorrentHandle&)), this, SLOT(setPaused(QTorrentHandle&))); + qDebug("create tabWidget"); tabs = new QTabWidget(); - // Download torrents tab - downloadingTorrentTab = new DownloadingTorrents(this, BTSession); - tabs->addTab(downloadingTorrentTab, tr("Downloads") + QString::fromUtf8(" (0/0)")); - tabs->setTabIcon(0, QIcon(QString::fromUtf8(":/Icons/skin/downloading.png"))); + vSplitter = new QSplitter(Qt::Horizontal); + rightPanel = new QWidget(vSplitter); + hSplitter = new QVBoxLayout(vSplitter); + rightPanel->setLayout(hSplitter); + + // Transfer List tab + transferList = new TransferListWidget(rightPanel, BTSession); + properties = new PropertiesWidget(rightPanel, transferList, BTSession); + transferListFilters = new TransferListFiltersWidget(vSplitter, transferList); + hSplitter->addWidget(transferList); + hSplitter->addWidget(properties); + vSplitter->addWidget(transferListFilters); + vSplitter->addWidget(rightPanel); + tabs->addTab(vSplitter, QIcon(QString::fromUtf8(":/Icons/oxygen/folder-remote.png")), tr("Transfers")); + vboxLayout->addWidget(tabs); - connect(downloadingTorrentTab, SIGNAL(unfinishedTorrentsNumberChanged(unsigned int)), this, SLOT(updateUnfinishedTorrentNumber(unsigned int))); - connect(downloadingTorrentTab, SIGNAL(torrentDoubleClicked(QString, bool)), this, SLOT(torrentDoubleClicked(QString, bool))); - // Finished torrents tab - finishedTorrentTab = new FinishedTorrents(this, BTSession); - tabs->addTab(finishedTorrentTab, tr("Uploads") + QString::fromUtf8(" (0/0)")); - tabs->setTabIcon(1, QIcon(QString::fromUtf8(":/Icons/skin/seeding.png"))); - connect(finishedTorrentTab, SIGNAL(torrentDoubleClicked(QString, bool)), this, SLOT(torrentDoubleClicked(QString, bool))); - connect(finishedTorrentTab, SIGNAL(finishedTorrentsNumberChanged(unsigned int)), this, SLOT(updateFinishedTorrentNumber(unsigned int))); + + // Transfer list slots + connect(actionStart, SIGNAL(triggered()), transferList, SLOT(startSelectedTorrents())); + connect(actionStart_All, SIGNAL(triggered()), transferList, SLOT(startAllTorrents())); + connect(actionPause, SIGNAL(triggered()), transferList, SLOT(pauseSelectedTorrents())); + connect(actionPause_All, SIGNAL(triggered()), transferList, SLOT(pauseAllTorrents())); + connect(actionDelete, SIGNAL(triggered()), transferList, SLOT(deleteSelectedTorrents())); + connect(actionDelete_Permanently, SIGNAL(triggered()), transferList, SLOT(deletePermSelectedTorrents())); + connect(actionIncreasePriority, SIGNAL(triggered()), transferList, SLOT(increasePrioSelectedTorrents())); + connect(actionDecreasePriority, SIGNAL(triggered()), transferList, SLOT(decreasePrioSelectedTorrents())); + + //connect(downloadingTorrentTab, SIGNAL(unfinishedTorrentsNumberChanged(unsigned int)), this, SLOT(updateUnfinishedTorrentNumber(unsigned int))); + //connect(downloadingTorrentTab, SIGNAL(torrentDoubleClicked(QString, bool)), this, SLOT(torrentDoubleClicked(QString, bool))); // Search engine tab searchEngine = new SearchEngine(BTSession, myTrayIcon, systrayIntegration); - tabs->addTab(searchEngine, tr("Search")); - tabs->setTabIcon(2, QIcon(QString::fromUtf8(":/Icons/oxygen/edit-find.png"))); - readSettings(); + tabs->addTab(searchEngine, QIcon(QString::fromUtf8(":/Icons/oxygen/edit-find.png")), tr("Search")); + // RSS Tab rssWidget = 0; - // Start download list refresher - refresher = new QTimer(this); - connect(refresher, SIGNAL(timeout()), this, SLOT(updateLists())); - refresher->start(1500); + // Configure BT session according to options configureSession(true); // Resume unfinished torrents BTSession->startUpTorrents(); - downloadingTorrentTab->loadLastSortedColumn(); - finishedTorrentTab->loadLastSortedColumn(); + // FIXME: Sorting + //downloadingTorrentTab->loadLastSortedColumn(); + //finishedTorrentTab->loadLastSortedColumn(); // Add torrent given on command line processParams(torrentCmdLine); // Initialize Web UI @@ -233,10 +242,17 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), dis QMainWindow::statusBar()->addPermanentWidget(upSpeedLbl); QMainWindow::statusBar()->addPermanentWidget(statusSep4); QMainWindow::statusBar()->addPermanentWidget(ratioLbl); + show(); + + // Load Window state and sizes + readSettings(); + properties->readSettings(); + if(settings.value(QString::fromUtf8("Preferences/General/StartMinimized"), false).toBool()) { this->setWindowState(Qt::WindowMinimized); } + scrapeTimer = new QTimer(this); connect(scrapeTimer, SIGNAL(timeout()), this, SLOT(scrapeTrackers())); scrapeTimer->start(20000); @@ -264,9 +280,12 @@ GUI::~GUI() { if(rssWidget != 0) delete rssWidget; delete searchEngine; - delete refresher; - delete downloadingTorrentTab; - delete finishedTorrentTab; + delete transferListFilters; + delete transferList; + delete properties; + delete hSplitter; + delete rightPanel; + delete vSplitter; delete checkConnect; qDebug("1"); if(systrayCreator) { @@ -301,8 +320,8 @@ void GUI::displayRSSTab(bool enable) { // RSS tab if(rssWidget == 0) { rssWidget = new RSSImp(BTSession); - tabs->addTab(rssWidget, tr("RSS")); - tabs->setTabIcon(3, QIcon(QString::fromUtf8(":/Icons/rss32.png"))); + int index_tab = tabs->addTab(rssWidget, tr("RSS")); + tabs->setTabIcon(index_tab, QIcon(QString::fromUtf8(":/Icons/rss32.png"))); } } else { if(rssWidget != 0) { @@ -358,97 +377,32 @@ void GUI::writeSettings() { settings.beginGroup(QString::fromUtf8("MainWindow")); settings.setValue(QString::fromUtf8("size"), size()); settings.setValue(QString::fromUtf8("pos"), pos()); + // Splitter size + QStringList sizes_str; + sizes_str << QString::number(vSplitter->sizes().first()); + sizes_str << QString::number(vSplitter->sizes().last()); + settings.setValue(QString::fromUtf8("vSplitterSizes"), sizes_str); settings.endGroup(); } // called when a torrent has finished void GUI::finishedTorrent(QTorrentHandle& h) const { - qDebug("In GUI, a torrent has finished"); - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - bool show_msg = true; - if(TorrentPersistentData::isSeed(h.hash())) - show_msg = false; - QString fileName = h.name(); - bool useNotificationBalloons = settings.value(QString::fromUtf8("Preferences/General/NotificationBaloons"), true).toBool(); - // Add it to finished tab - QString hash = h.hash(); - if(show_msg) - BTSession->addConsoleMessage(tr("%1 has finished downloading.", "e.g: xxx.avi has finished downloading.").arg(fileName)); - downloadingTorrentTab->deleteTorrent(hash); - finishedTorrentTab->addTorrent(hash); - if(show_msg && systrayIntegration && useNotificationBalloons) { - myTrayIcon->showMessage(tr("Download finished"), tr("%1 has finished downloading.", "e.g: xxx.avi has finished downloading.").arg(fileName), QSystemTrayIcon::Information, TIME_TRAY_BALLOON); - } -} - -void GUI::addedTorrent(QTorrentHandle& h) const { - if(h.is_seed()) { - finishedTorrentTab->addTorrent(h.hash()); - } else { - downloadingTorrentTab->addTorrent(h.hash()); - } -} - -void GUI::pausedTorrent(QTorrentHandle& h) const { - if(h.is_seed()) { - finishedTorrentTab->pauseTorrent(h.hash()); - } else { - downloadingTorrentTab->pauseTorrent(h.hash()); - } -} - -void GUI::resumedTorrent(QTorrentHandle& h) const { - if(h.is_seed()) { - finishedTorrentTab->updateTorrent(h); - } else { - downloadingTorrentTab->updateTorrent(h); - } -} - -void GUI::checkedTorrent(QTorrentHandle& h) const { - if(h.is_seed()) { - // Move torrent to finished tab - downloadingTorrentTab->deleteTorrent(h.hash()); - finishedTorrentTab->addTorrent(h.hash()); - } else { - // Move torrent back to download list (if necessary) - if(TorrentPersistentData::isSeed(h.hash())) { - TorrentPersistentData::saveSeedStatus(h); - finishedTorrentTab->deleteTorrent(h.hash()); - downloadingTorrentTab->addTorrent(h.hash()); - } - } + if(!TorrentPersistentData::isSeed(h.hash())) + showNotificationBaloon(tr("Download completion"), tr("%1 has finished downloading.", "e.g: xxx.avi has finished downloading.").arg(h.name())); } // Notification when disk is full void GUI::fullDiskError(QTorrentHandle& h, QString msg) const { - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - bool useNotificationBalloons = settings.value(QString::fromUtf8("Preferences/General/NotificationBaloons"), true).toBool(); - if(systrayIntegration && useNotificationBalloons) { - myTrayIcon->showMessage(tr("I/O Error", "i.e: Input/Output Error"), tr("An I/O error occured for torrent %1.\n Reason: %2", "e.g: An error occured for torrent xxx.avi.\n Reason: disk is full.").arg(h.name()).arg(msg), QSystemTrayIcon::Critical, TIME_TRAY_BALLOON); - } + if(!h.is_valid()) return; + showNotificationBaloon(tr("I/O Error", "i.e: Input/Output Error"), tr("An I/O error occured for torrent %1.\n Reason: %2", "e.g: An error occured for torrent xxx.avi.\n Reason: disk is full.").arg(h.name()).arg(msg)); // Download will be paused by libtorrent. Updating GUI information accordingly QString hash = h.hash(); qDebug("Full disk error, pausing torrent %s", hash.toLocal8Bit().data()); - setPaused(h); + h.pause(); + transferList->pauseTorrent(h.hash()); BTSession->addConsoleMessage(tr("An error occured (full disk?), '%1' paused.", "e.g: An error occured (full disk?), 'xxx.avi' paused.").arg(h.name())); } -void GUI::setPaused(QTorrentHandle &h) const { - if(!h.is_paused()) { - // FIXME in v1.6.0: Add Error state and stop using pause for this - h.pause(); - } - qDebug("Marking torrent %s as paused", h.hash().toLocal8Bit().data()); - if(h.is_seed()) { - // In finished list - qDebug("Automatically paused torrent was in finished list"); - finishedTorrentTab->pauseTorrent(h.hash()); - }else{ - downloadingTorrentTab->pauseTorrent(h.hash()); - } -} - void GUI::createKeyboardShortcuts() { actionCreate_torrent->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+N"))); actionOpen->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+O"))); @@ -499,6 +453,18 @@ void GUI::readSettings() { settings.beginGroup(QString::fromUtf8("MainWindow")); resize(settings.value(QString::fromUtf8("size"), size()).toSize()); move(settings.value(QString::fromUtf8("pos"), screenCenter()).toPoint()); + QStringList sizes_str = settings.value("vSplitterSizes", QStringList()).toStringList(); + // Splitter size + QList sizes; + if(sizes_str.size() == 2) { + sizes << sizes_str.first().toInt(); + sizes << sizes_str.last().toInt(); + } else { + qDebug("Default splitter size"); + sizes << 120; + sizes << vSplitter->width()-120; + } + vSplitter->setSizes(sizes); settings.endGroup(); } @@ -548,86 +514,6 @@ void GUI::on_actionSet_global_download_limit_triggered() { new BandwidthAllocationDialog(this, false, BTSession, QStringList()); } -void GUI::on_actionPreview_file_triggered() { - QString hash; - switch(tabs->currentIndex()){ - case 0: - hash = downloadingTorrentTab->getSelectedTorrents(true).first(); - break; - case 1: - hash = finishedTorrentTab->getSelectedTorrents(true).first(); - break; - default: - return; - } - QTorrentHandle h = BTSession->getTorrentHandle(hash); - new previewSelect(this, h); -} - -void GUI::openDestinationFolder() const { - QStringList hashes; - switch(tabs->currentIndex()){ - case 0: - hashes = downloadingTorrentTab->getSelectedTorrents(true); - break; - case 1: - hashes = finishedTorrentTab->getSelectedTorrents(true); - break; - default: - return; - } - QStringList pathsList; - foreach(const QString &hash, hashes) { - QTorrentHandle h = BTSession->getTorrentHandle(hash); - QString savePath = h.save_path(); - if(!pathsList.contains(savePath)) { - pathsList.append(savePath); - QDesktopServices::openUrl(QString("file://")+savePath); - } - } -} - -void GUI::copyMagnetURI() const { - QStringList hashes; - switch(tabs->currentIndex()){ - case 0: - hashes = downloadingTorrentTab->getSelectedTorrents(); - break; - case 1: - hashes = finishedTorrentTab->getSelectedTorrents(); - break; - default: - return; - } - QStringList magnet_uris; - foreach(QString hash, hashes) { - QTorrentHandle h = BTSession->getTorrentHandle(hash); - if(h.is_valid()) { - magnet_uris << misc::toQString(make_magnet_uri(h.get_torrent_info())); - } - } - qApp->clipboard()->setText(magnet_uris.join("\n")); -} - -void GUI::goBuyPage() const { - QStringList hashes; - switch(tabs->currentIndex()){ - case 0: - hashes = downloadingTorrentTab->getSelectedTorrents(true); - break; - case 1: - hashes = finishedTorrentTab->getSelectedTorrents(true); - break; - default: - return; - } - QStringList pathsList; - foreach(const QString &hash, hashes) { - QTorrentHandle h = BTSession->getTorrentHandle(hash); - QDesktopServices::openUrl("http://match.sharemonkey.com/?info_hash="+hash+"&n="+h.name()+"&cid=33"); - } -} - // Necessary if we want to close the window // in one time if "close to systray" is enabled void GUI::on_actionExit_triggered() { @@ -693,7 +579,7 @@ void GUI::on_actionAbout_triggered() { void GUI::showEvent(QShowEvent *e) { qDebug("** Show Event **"); - updateLists(true); + //updateLists(true); e->accept(); } @@ -708,14 +594,14 @@ void GUI::closeEvent(QCloseEvent *e) { e->accept(); return; } - if(settings.value(QString::fromUtf8("Preferences/General/ExitConfirm"), true).toBool() && downloadingTorrentTab->getNbTorrentsInList()) { + if(settings.value(QString::fromUtf8("Preferences/General/ExitConfirm"), true).toBool() && BTSession->hasActiveTorrents()) { show(); if(!isMaximized()) showNormal(); if(e->spontaneous() == true || force_exit == true) { if(QMessageBox::question(this, tr("Are you sure you want to quit?")+QString::fromUtf8(" -- ")+tr("qBittorrent"), - tr("The download list is not empty.\nAre you sure you want to quit qBittorrent?"), + tr("Some files are currently transferring.\nAre you sure you want to quit qBittorrent?"), tr("&Yes"), tr("&No"), QString(), 0, 1)) { e->ignore(); @@ -838,101 +724,6 @@ void GUI::on_actionOpen_triggered() { } } -// delete from download list AND from hard drive -void GUI::on_actionDelete_Permanently_triggered() { - QStringList hashes; - bool inDownloadList = true; - switch(tabs->currentIndex()){ - case 0: - hashes = downloadingTorrentTab->getSelectedTorrents(); - break; - case 1: - hashes = finishedTorrentTab->getSelectedTorrents(); - inDownloadList = false; - break; - default: - return; - } - if(hashes.empty()) return; - int ret; - if(inDownloadList) { - ret = QMessageBox::question( - this, - tr("Are you sure? -- qBittorrent"), - tr("Are you sure you want to delete the selected item(s) from download list and from hard drive?"), - tr("&Yes"), tr("&No"), - QString(), 0, 1); - }else{ - ret = QMessageBox::question( - this, - tr("Are you sure? -- qBittorrent"), - tr("Are you sure you want to delete the selected item(s) from finished list and from hard drive?"), - tr("&Yes"), tr("&No"), - QString(), 0, 1); - } - if(ret) return; - //User clicked YES - foreach(const QString &hash, hashes) { - // Get the file name - QTorrentHandle h = BTSession->getTorrentHandle(hash); - QString fileName = h.name(); - // Remove the torrent - BTSession->deleteTorrent(hash, true); - } -} - -void GUI::deleteTorrent(QString hash) { - // Delete item from list - downloadingTorrentTab->deleteTorrent(hash); - finishedTorrentTab->deleteTorrent(hash); -} - -// delete selected items in the list -void GUI::on_actionDelete_triggered() { - QStringList hashes; - bool inDownloadList = true; - switch(tabs->currentIndex()){ - case 0: // DL - hashes = downloadingTorrentTab->getSelectedTorrents(); - break; - case 1: // SEED - hashes = finishedTorrentTab->getSelectedTorrents(); - inDownloadList = false; - break; - case 3: //RSSImp - rssWidget->deleteSelectedItems(); - return; - default: - return; - } - if(hashes.empty()) return; - int ret; - if(inDownloadList) { - ret = QMessageBox::question( - this, - tr("Are you sure? -- qBittorrent"), - tr("Are you sure you want to delete the selected item(s) in download list?"), - tr("&Yes"), tr("&No"), - QString(), 0, 1); - } else { - ret = QMessageBox::question( - this, - tr("Are you sure? -- qBittorrent"), - tr("Are you sure you want to delete the selected item(s) in finished list?"), - tr("&Yes"), tr("&No"), - QString(), 0, 1); - } - if(ret) return; - //User clicked YES - foreach(const QString &hash, hashes) { - // Get the file name - QTorrentHandle h = BTSession->getTorrentHandle(hash); - QString fileName = h.name(); - // Remove the torrent - BTSession->deleteTorrent(hash, false); - } -} - // As program parameters, we can get paths or urls. // This function parse the parameters and call // the right addTorrent function, considering @@ -993,10 +784,7 @@ void GUI::configureSession(bool deleteOptions) { toolBar->setVisible(false); } unsigned int new_refreshInterval = options->getRefreshInterval(); - if(refreshInterval != new_refreshInterval) { - refreshInterval = new_refreshInterval; - refresher->start(refreshInterval); - } + transferList->setRefreshInterval(new_refreshInterval); // Downloads // * Save path BTSession->setDefaultSavePath(options->getSavePath()); @@ -1069,7 +857,7 @@ void GUI::configureSession(bool deleteOptions) { // Queueing System if(options->isQueueingSystemEnabled()) { if(!BTSession->isQueueingEnabled()) { - downloadingTorrentTab->hidePriorityColumn(false); + transferList->hidePriorityColumn(false); actionDecreasePriority->setVisible(true); actionIncreasePriority->setVisible(true); prioSeparator->setVisible(true); @@ -1090,7 +878,7 @@ void GUI::configureSession(bool deleteOptions) { sessionSettings.active_seeds = -1; sessionSettings.active_limit = -1; BTSession->setQueueingEnabled(false); - downloadingTorrentTab->hidePriorityColumn(true); + transferList->hidePriorityColumn(true); actionDecreasePriority->setVisible(false); actionIncreasePriority->setVisible(false); prioSeparator->setVisible(false); @@ -1247,182 +1035,6 @@ void GUI::configureSession(bool deleteOptions) { qDebug("Session configured"); } -void GUI::updateUnfinishedTorrentNumber(unsigned int nb) { - unsigned int paused = BTSession->getUnfinishedPausedTorrentsNb(); - tabs->setTabText(0, tr("Downloads") +QString::fromUtf8(" (")+misc::toQString(nb-paused)+"/"+misc::toQString(nb)+QString::fromUtf8(")")); -} - -void GUI::updateFinishedTorrentNumber(unsigned int nb) { - unsigned int paused = BTSession->getFinishedPausedTorrentsNb(); - tabs->setTabText(1, tr("Finished") +QString::fromUtf8(" (")+misc::toQString(nb-paused)+"/"+misc::toQString(nb)+QString::fromUtf8(")")); -} - -// Allow to change action on double-click -void GUI::torrentDoubleClicked(QString hash, bool finished) { - int action; - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - QTorrentHandle h = BTSession->getTorrentHandle(hash); - - if(finished) { - action = settings.value(QString::fromUtf8("Preferences/Downloads/DblClOnTorFN"), 0).toInt(); - } else { - action = settings.value(QString::fromUtf8("Preferences/Downloads/DblClOnTorDl"), 0).toInt(); - } - - switch(action) { - case TOGGLE_PAUSE: - this->togglePausedState(hash); - break; - case OPEN_DEST: { - QTorrentHandle h = BTSession->getTorrentHandle(hash); - QString savePath = h.save_path(); - QDesktopServices::openUrl(QUrl(savePath)); - break; - } - case SHOW_PROPERTIES : - if(finished) { - finishedTorrentTab->showPropertiesFromHash(hash); - } else { - downloadingTorrentTab->showPropertiesFromHash(hash); - } - break; - } -} - -// Toggle paused state of selected torrent -void GUI::togglePausedState(QString hash) { - if(tabs->currentIndex() > 1) return; - bool inDownloadList = true; - if(tabs->currentIndex() == 1) - inDownloadList = false; - QTorrentHandle h = BTSession->getTorrentHandle(hash); - if(h.is_paused()) { - h.resume(); - resumedTorrent(h); - if(inDownloadList) { - updateUnfinishedTorrentNumber(downloadingTorrentTab->getNbTorrentsInList()); - }else{ - updateFinishedTorrentNumber(finishedTorrentTab->getNbTorrentsInList()); - } - }else{ - h.pause(); - pausedTorrent(h); - if(inDownloadList) { - updateUnfinishedTorrentNumber(downloadingTorrentTab->getNbTorrentsInList()); - }else{ - updateFinishedTorrentNumber(finishedTorrentTab->getNbTorrentsInList()); - } - } -} - -// Pause All Downloads in DL list -void GUI::on_actionPause_All_triggered() { - bool change = false; - std::vector torrents = BTSession->getTorrents(); - std::vector::iterator torrentIT; - for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { - QTorrentHandle h = QTorrentHandle(*torrentIT); - if(!h.is_valid() || h.is_paused()) continue; - change = true; - h.pause(); - pausedTorrent(h); - } - if(change) { - updateUnfinishedTorrentNumber(downloadingTorrentTab->getNbTorrentsInList()); - updateFinishedTorrentNumber(finishedTorrentTab->getNbTorrentsInList()); - } -} - -void GUI::on_actionIncreasePriority_triggered() { - if(tabs->currentIndex() != 0) - return; - QStringList hashes = downloadingTorrentTab->getSelectedTorrents(); - foreach(const QString &hash, hashes) { - BTSession->increaseDlTorrentPriority(hash); - } - updateLists(); -} - -void GUI::on_actionDecreasePriority_triggered() { - Q_ASSERT(tabs->currentIndex() == 0); - QStringList hashes = downloadingTorrentTab->getSelectedTorrents(); - foreach(const QString &hash, hashes) { - BTSession->decreaseDlTorrentPriority(hash); - } - updateLists(); -} - -// pause selected items in the list -void GUI::on_actionPause_triggered() { - bool inDownloadList = true; - if(tabs->currentIndex() > 1) return; - if(tabs->currentIndex() == 1) - inDownloadList = false; - QStringList hashes; - if(inDownloadList) { - hashes = downloadingTorrentTab->getSelectedTorrents(); - } else { - hashes = finishedTorrentTab->getSelectedTorrents(); - } - qDebug("nb hashes: %d", hashes.size()); - foreach(const QString &hash, hashes) { - QTorrentHandle h = BTSession->getTorrentHandle(hash); - if(!h.is_paused()){ - h.pause(); - pausedTorrent(h); - if(inDownloadList) { - updateUnfinishedTorrentNumber(downloadingTorrentTab->getNbTorrentsInList()); - } else { - updateFinishedTorrentNumber(finishedTorrentTab->getNbTorrentsInList()); - } - } - } -} - -// Resume All Downloads in DL list -void GUI::on_actionStart_All_triggered() { - bool change = false; - std::vector torrents = BTSession->getTorrents(); - std::vector::iterator torrentIT; - for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { - QTorrentHandle h = QTorrentHandle(*torrentIT); - if(!h.is_valid() || !h.is_paused()) continue; - change = true; - h.resume(); - resumedTorrent(h); - } - if(change) { - updateUnfinishedTorrentNumber(downloadingTorrentTab->getNbTorrentsInList()); - updateFinishedTorrentNumber(finishedTorrentTab->getNbTorrentsInList()); - } -} - -// start selected items in the list -void GUI::on_actionStart_triggered() { - bool inDownloadList = true; - if(tabs->currentIndex() > 1) return; - if(tabs->currentIndex() == 1) - inDownloadList = false; - QStringList hashes; - if(inDownloadList) { - hashes = downloadingTorrentTab->getSelectedTorrents(); - } else { - hashes = finishedTorrentTab->getSelectedTorrents(); - } - foreach(const QString &hash, hashes) { - QTorrentHandle h = BTSession->getTorrentHandle(hash); - if(h.is_paused()){ - h.resume(); - resumedTorrent(h); - if(inDownloadList) { - updateUnfinishedTorrentNumber(downloadingTorrentTab->getNbTorrentsInList()); - } else { - updateFinishedTorrentNumber(finishedTorrentTab->getNbTorrentsInList()); - } - } - } -} - void GUI::addUnauthenticatedTracker(QPair tracker) { // Trackers whose authentication was cancelled if(unauthenticated_trackers.indexOf(tracker) < 0) { @@ -1430,19 +1042,7 @@ void GUI::addUnauthenticatedTracker(QPair tracker) { } } -// display properties of selected items -void GUI::on_actionTorrent_Properties_triggered() { - if(tabs->currentIndex() > 1) return; - switch(tabs->currentIndex()){ - case 1: // DL List - finishedTorrentTab->propertiesSelection(); - break; - default: - downloadingTorrentTab->propertiesSelection(); - } -} - -void GUI::updateLists(bool force) { +/*void GUI::updateLists(bool force) { if(isVisible() || force) { // update global informations dlSpeedLbl->setText(tr("DL: %1 KiB/s").arg(QString(QByteArray::number(BTSession->getPayloadDownloadRate()/1024., 'f', 1)))); @@ -1474,7 +1074,7 @@ void GUI::updateLists(bool force) { QString up_rate = QByteArray::number(BTSession->getSessionStatus().payload_upload_rate/1024, 'f', 1); setWindowTitle(tr("qBittorrent %1 (DL: %2KiB/s, UP: %3KiB/s)", "%1 is qBittorrent version").arg(QString::fromUtf8(VERSION)).arg(dl_rate).arg(up_rate)); } -} +}*/ // Called when a tracker requires authentication void GUI::trackerAuthenticationRequired(QTorrentHandle& h) { @@ -1520,6 +1120,13 @@ void GUI::checkConnectionStatus() { } } +void GUI::showNotificationBaloon(QString title, QString msg) const { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + if(systrayIntegration && settings.value(QString::fromUtf8("Preferences/General/NotificationBaloons"), true).toBool()) { + myTrayIcon->showMessage(title, msg, QSystemTrayIcon::Information, TIME_TRAY_BALLOON); + } +} + /***************************************************** * * * Utils * diff --git a/src/GUI.h b/src/GUI.h index 1c789f7fc..6785fbf04 100644 --- a/src/GUI.h +++ b/src/GUI.h @@ -40,8 +40,6 @@ class bittorrent; class createtorrent; class QTimer; -class DownloadingTorrents; -class FinishedTorrents; class downloadFromURL; class SearchEngine; class QLocalServer; @@ -57,6 +55,11 @@ class QLabel; class QModelIndex; class HttpServer; class QFrame; +class TransferListWidget; +class TransferListFiltersWidget; +class QSplitter; +class PropertiesWidget; +class QVBoxLayout; class GUI : public QMainWindow, private Ui::MainWindow{ Q_OBJECT @@ -73,14 +76,17 @@ class GUI : public QMainWindow, private Ui::MainWindow{ QSystemTrayIcon *myTrayIcon; QPointer systrayCreator; QMenu *myTrayIconMenu; - DownloadingTorrents *downloadingTorrentTab; - FinishedTorrents *finishedTorrentTab; + TransferListWidget *transferList; + TransferListFiltersWidget *transferListFilters; + PropertiesWidget *properties; + QVBoxLayout *hSplitter; + QWidget *rightPanel; + QSplitter *vSplitter; QLabel *connecStatusLblIcon; bool systrayIntegration; bool displaySpeedInTitle; bool force_exit; - unsigned int refreshInterval; - QTimer *refresher; + //unsigned int refreshInterval; QLabel *dlSpeedLbl; QLabel *upSpeedLbl; QLabel *ratioLbl; @@ -119,21 +125,15 @@ class GUI : public QMainWindow, private Ui::MainWindow{ void on_actionShow_console_triggered(); void readParamsOnSocket(); void acceptConnection(); - void togglePausedState(QString hash); - void torrentDoubleClicked(QString hash, bool finished); - void on_actionPreview_file_triggered(); void previewFile(QString filePath); void balloonClicked(); void writeSettings(); void readSettings(); void on_actionExit_triggered(); void createTrayIcon(); - void updateUnfinishedTorrentNumber(unsigned int nb); - void updateFinishedTorrentNumber(unsigned int nb); void fullDiskError(QTorrentHandle& h, QString msg) const; void handleDownloadFromUrlFailure(QString, QString) const; void createSystrayDelayed(); - void setPaused(QTorrentHandle &h) const; // Keyboard shortcuts void createKeyboardShortcuts(); void displayDownTab() const; @@ -141,17 +141,10 @@ class GUI : public QMainWindow, private Ui::MainWindow{ void displaySearchTab() const; void displayRSSTab() const; // Torrent actions - void on_actionTorrent_Properties_triggered(); - void on_actionPause_triggered(); - void on_actionPause_All_triggered(); - void on_actionStart_triggered(); - void on_actionStart_All_triggered(); - void on_actionOpen_triggered(); - void on_actionDelete_Permanently_triggered(); - void on_actionDelete_triggered(); void on_actionSet_global_upload_limit_triggered(); void on_actionSet_global_download_limit_triggered(); void on_actionDocumentation_triggered() const; + void on_actionOpen_triggered(); void checkConnectionStatus(); void configureSession(bool deleteOptions); void processParams(const QStringList& params); @@ -159,16 +152,9 @@ class GUI : public QMainWindow, private Ui::MainWindow{ void addUnauthenticatedTracker(QPair tracker); void processDownloadedFiles(QString path, QString url); void downloadFromURLList(const QStringList& urls); - void deleteTorrent(QString hash); void finishedTorrent(QTorrentHandle& h) const; - void addedTorrent(QTorrentHandle& h) const; - void checkedTorrent(QTorrentHandle& h) const; - void pausedTorrent(QTorrentHandle& h) const; - void resumedTorrent(QTorrentHandle& h) const; - void updateLists(bool force=false); + //void updateLists(bool force=false); bool initWebUi(QString username, QString password, int port); - void on_actionIncreasePriority_triggered(); - void on_actionDecreasePriority_triggered(); void scrapeTrackers(); // Options slots void on_actionOptions_triggered(); @@ -180,10 +166,8 @@ class GUI : public QMainWindow, private Ui::MainWindow{ public slots: void trackerAuthenticationRequired(QTorrentHandle& h); void setTabText(int index, QString text) const; - void openDestinationFolder() const; - void goBuyPage() const; - void copyMagnetURI() const; void updateRatio(); + void showNotificationBaloon(QString title, QString msg) const; protected: void closeEvent(QCloseEvent *); diff --git a/src/Icons/oxygen/draw-rectangle.png b/src/Icons/oxygen/draw-rectangle.png new file mode 100644 index 000000000..04e093770 Binary files /dev/null and b/src/Icons/oxygen/draw-rectangle.png differ diff --git a/src/Icons/oxygen/draw-triangle2.png b/src/Icons/oxygen/draw-triangle2.png new file mode 100644 index 000000000..3c29299bb Binary files /dev/null and b/src/Icons/oxygen/draw-triangle2.png differ diff --git a/src/Icons/oxygen/folder-remote.png b/src/Icons/oxygen/folder-remote.png new file mode 100644 index 000000000..6210201b7 Binary files /dev/null and b/src/Icons/oxygen/folder-remote.png differ diff --git a/src/Icons/oxygen/folder-remote16.png b/src/Icons/oxygen/folder-remote16.png new file mode 100644 index 000000000..38465e573 Binary files /dev/null and b/src/Icons/oxygen/folder-remote16.png differ diff --git a/src/Icons/oxygen/help-about.png b/src/Icons/oxygen/help-about.png new file mode 100644 index 000000000..e1eb7972d Binary files /dev/null and b/src/Icons/oxygen/help-about.png differ diff --git a/src/Icons/oxygen/mail-queue.png b/src/Icons/oxygen/mail-queue.png new file mode 100644 index 000000000..0ba505d4f Binary files /dev/null and b/src/Icons/oxygen/mail-queue.png differ diff --git a/src/Icons/oxygen/network-server.png b/src/Icons/oxygen/network-server.png new file mode 100644 index 000000000..d2a954d44 Binary files /dev/null and b/src/Icons/oxygen/network-server.png differ diff --git a/src/Icons/oxygen/peer.png b/src/Icons/oxygen/peer.png new file mode 100644 index 000000000..c974107d2 Binary files /dev/null and b/src/Icons/oxygen/peer.png differ diff --git a/src/Icons/oxygen/run-build.png b/src/Icons/oxygen/run-build.png new file mode 100644 index 000000000..36167d5f0 Binary files /dev/null and b/src/Icons/oxygen/run-build.png differ diff --git a/src/Icons/oxygen/time.png b/src/Icons/oxygen/time.png deleted file mode 100644 index a76a31d2e..000000000 Binary files a/src/Icons/oxygen/time.png and /dev/null differ diff --git a/src/Icons/oxygen/urlseed.png b/src/Icons/oxygen/urlseed.png new file mode 100644 index 000000000..d0746f663 Binary files /dev/null and b/src/Icons/oxygen/urlseed.png differ diff --git a/src/Icons/skin/queued.png b/src/Icons/skin/queued.png deleted file mode 100644 index 125d0e5c4..000000000 Binary files a/src/Icons/skin/queued.png and /dev/null differ diff --git a/src/PropListDelegate.h b/src/PropListDelegate.h index 6bd694c5d..1def6ce28 100644 --- a/src/PropListDelegate.h +++ b/src/PropListDelegate.h @@ -43,55 +43,45 @@ #include "misc.h" // Defines for properties list columns -#define NAME 0 -#define SIZE 1 -#define PROGRESS 2 -#define PRIORITY 3 -#define INDEX 4 - -#define IGNORED 0 -#define NORMAL 1 -#define HIGH 2 -#define MAXIMUM 7 +enum PropColumn {NAME, SIZE, PROGRESS, PRIORITY, INDEX}; +enum PropPriority {IGNORED=0, NORMAL=1, HIGH=2, MAXIMUM=7}; class PropListDelegate: public QItemDelegate { Q_OBJECT - private: - bool* filteredFilesChanged; +signals: + void filteredFilesChanged() const; - public: - PropListDelegate(QObject *parent=0, bool* filteredFilesChanged=0) : QItemDelegate(parent){ - this->filteredFilesChanged = filteredFilesChanged; - } +public: + PropListDelegate(QObject *parent=0) : QItemDelegate(parent){ + } - ~PropListDelegate(){} + ~PropListDelegate(){} - void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const{ - QStyleOptionViewItemV2 opt = QItemDelegate::setOptions(index, option); - QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; - switch(index.column()){ + void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const{ + QStyleOptionViewItemV2 opt = QItemDelegate::setOptions(index, option); + switch(index.column()){ case SIZE: - QItemDelegate::drawBackground(painter, opt, index); - QItemDelegate::drawDisplay(painter, opt, option.rect, misc::friendlyUnit(index.data().toLongLong())); - break; + QItemDelegate::drawBackground(painter, opt, index); + QItemDelegate::drawDisplay(painter, opt, option.rect, misc::friendlyUnit(index.data().toLongLong())); + break; case PROGRESS:{ - QStyleOptionProgressBarV2 newopt; - float progress = index.data().toDouble()*100.; - newopt.rect = opt.rect; - newopt.text = QString(QByteArray::number(progress, 'f', 1))+QString::fromUtf8("%"); - newopt.progress = (int)progress; - newopt.maximum = 100; - newopt.minimum = 0; - newopt.state |= QStyle::State_Enabled; - newopt.textVisible = true; - QApplication::style()->drawControl(QStyle::CE_ProgressBar, &newopt, painter); - break; - } + QStyleOptionProgressBarV2 newopt; + float progress = index.data().toDouble()*100.; + newopt.rect = opt.rect; + newopt.text = QString(QByteArray::number(progress, 'f', 1))+QString::fromUtf8("%"); + newopt.progress = (int)progress; + newopt.maximum = 100; + newopt.minimum = 0; + newopt.state |= QStyle::State_Enabled; + newopt.textVisible = true; + QApplication::style()->drawControl(QStyle::CE_ProgressBar, &newopt, painter); + break; + } case PRIORITY:{ - QStyleOptionComboBox newopt; - newopt.rect = opt.rect; - switch(index.data().toInt()){ + QStyleOptionComboBox newopt; + newopt.rect = opt.rect; + switch(index.data().toInt()){ case IGNORED: newopt.currentText = tr("Ignored"); break; @@ -107,128 +97,129 @@ class PropListDelegate: public QItemDelegate { default: qDebug("Unhandled priority, setting NORMAL"); newopt.currentText = tr("Normal", "Normal (priority)"); + } + //newopt.state |= QStyle::State_Enabled; + //newopt.subControls = QStyle::SC_All; + //painter->translate(QPoint(opt.rect.x()*-1,opt.rect.y()*-1)); + //QApplication::style()->drawComplexControl(QStyle::CC_ComboBox, &newopt, painter); + //painter->translate(QPoint(opt.rect.x(),opt.rect.y())); + //QApplication::style()->drawControl(QStyle::CE_ComboBoxLabel, &newopt, painter); + QItemDelegate::drawBackground(painter, opt, index); + QItemDelegate::drawDisplay(painter, opt, option.rect, newopt.currentText); + break; } - newopt.state |= QStyle::State_Enabled; - QApplication::style()->drawComplexControl(QStyle::CC_ComboBox, &newopt, - painter); - opt.palette.setColor(QPalette::Text, QColor("black")); - painter->setPen(opt.palette.color(cg, QPalette::Text)); - painter->drawText(option.rect, Qt::AlignLeft, QString::fromUtf8(" ")+newopt.currentText); - break; - } default: QItemDelegate::paint(painter, option, index); - } - } - - QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */, const QModelIndex & index) const { - if(index.column() != PRIORITY) return 0; - QComboBox* editor = new QComboBox(parent); - editor->setFocusPolicy(Qt::StrongFocus); - editor->addItem(tr("Ignored")); - editor->addItem(tr("Normal", "Normal (priority)")); - editor->addItem(tr("High", "High (priority)")); - editor->addItem(tr("Maximum", "Maximum (priority)")); - return editor; - } - - void setEditorData(QWidget *editor, const QModelIndex &index) const { - unsigned short val = index.model()->data(index, Qt::DisplayRole).toInt(); - QComboBox *combobox = static_cast(editor); - qDebug("Set Editor data: Prio is %d", val); - switch(val){ + } + } + + QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */, const QModelIndex & index) const { + qDebug("CreateEditor called"); + if(index.column() != PRIORITY) return 0; + QComboBox* editor = new QComboBox(parent); + editor->setFocusPolicy(Qt::StrongFocus); + editor->addItem(tr("Ignored")); + editor->addItem(tr("Normal", "Normal (priority)")); + editor->addItem(tr("High", "High (priority)")); + editor->addItem(tr("Maximum", "Maximum (priority)")); + return editor; + } + + void setEditorData(QWidget *editor, const QModelIndex &index) const { + qDebug("setEditorData called"); + unsigned short val = index.model()->data(index, Qt::DisplayRole).toInt(); + QComboBox *combobox = static_cast(editor); + qDebug("Set Editor data: Prio is %d", val); + switch(val){ case IGNORED: - combobox->setCurrentIndex(0); - break; + combobox->setCurrentIndex(0); + break; case NORMAL: - combobox->setCurrentIndex(1); - break; + combobox->setCurrentIndex(1); + break; case HIGH: - combobox->setCurrentIndex(2); - break; + combobox->setCurrentIndex(2); + break; case MAXIMUM: - combobox->setCurrentIndex(3); - break; + combobox->setCurrentIndex(3); + break; default: - qDebug("Unhandled priority, setting to NORMAL"); - combobox->setCurrentIndex(1); - } - } - - QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const{ - QVariant value = index.data(Qt::FontRole); - QFont fnt = value.isValid() ? qvariant_cast(value) : option.font; - QFontMetrics fontMetrics(fnt); - const QString text = index.data(Qt::DisplayRole).toString(); - QRect textRect = QRect(0, 0, 0, fontMetrics.lineSpacing() * (text.count(QLatin1Char('\n')) + 1)); - return textRect.size(); + qDebug("Unhandled priority, setting to NORMAL"); + combobox->setCurrentIndex(1); } + } + + QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const{ + QVariant value = index.data(Qt::FontRole); + QFont fnt = value.isValid() ? qvariant_cast(value) : option.font; + QFontMetrics fontMetrics(fnt); + const QString text = index.data(Qt::DisplayRole).toString(); + QRect textRect = QRect(0, 0, 0, fontMetrics.lineSpacing() * (text.count(QLatin1Char('\n')) + 1)); + textRect.setHeight(textRect.height()+4); + return textRect.size(); + } public slots: - void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { - QComboBox *combobox = static_cast(editor); - int value = combobox->currentIndex(); - qDebug("Setting combobox value in index: %d", value); - unsigned short old_val = index.model()->data(index, Qt::DisplayRole).toInt(); - switch(value){ + void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { + QComboBox *combobox = static_cast(editor); + int value = combobox->currentIndex(); + qDebug("Setting combobox value in index: %d", value); + unsigned short old_val = index.model()->data(index, Qt::DisplayRole).toInt(); + switch(value){ case 0: - if(old_val != IGNORED){ - model->setData(index, QVariant(IGNORED)); - if(filteredFilesChanged != 0) - *filteredFilesChanged = true; - } else { - // XXX: hack to force the model to send the itemChanged() signal - model->setData(index, QVariant(NORMAL)); - model->setData(index, QVariant(IGNORED)); - } - break; + if(old_val != IGNORED){ + model->setData(index, QVariant(IGNORED)); + emit filteredFilesChanged(); + } else { + // XXX: hack to force the model to send the itemChanged() signal + model->setData(index, QVariant(NORMAL)); + model->setData(index, QVariant(IGNORED)); + } + break; case 1: -// if(old_val != NORMAL){ -// model->setData(index, QVariant(NORMAL)); -// if(filteredFilesChanged != 0) -// *filteredFilesChanged = true; -// } else { - model->setData(index, QVariant(HIGH)); - model->setData(index, QVariant(NORMAL)); - if(filteredFilesChanged != 0) - *filteredFilesChanged = true; -// } - break; + // if(old_val != NORMAL){ + // model->setData(index, QVariant(NORMAL)); + // if(filteredFilesChanged != 0) + // *filteredFilesChanged = true; + // } else { + model->setData(index, QVariant(HIGH)); + model->setData(index, QVariant(NORMAL)); + emit filteredFilesChanged(); + // } + break; case 2: - if(old_val != HIGH){ - model->setData(index, QVariant(HIGH)); - if(filteredFilesChanged != 0) - *filteredFilesChanged = true; - } else { - model->setData(index, QVariant(NORMAL)); - model->setData(index, QVariant(HIGH)); - } - break; + if(old_val != HIGH){ + model->setData(index, QVariant(HIGH)); + emit filteredFilesChanged(); + } else { + model->setData(index, QVariant(NORMAL)); + model->setData(index, QVariant(HIGH)); + } + break; case 3: - if(old_val != MAXIMUM){ - model->setData(index, QVariant(MAXIMUM)); - if(filteredFilesChanged != 0) - *filteredFilesChanged = true; - } else { - model->setData(index, QVariant(HIGH)); - model->setData(index, QVariant(MAXIMUM)); - } - break; + if(old_val != MAXIMUM){ + model->setData(index, QVariant(MAXIMUM)); + emit filteredFilesChanged(); + } else { + model->setData(index, QVariant(HIGH)); + model->setData(index, QVariant(MAXIMUM)); + } + break; default: - if(old_val != NORMAL){ - model->setData(index, QVariant(NORMAL)); - if(filteredFilesChanged != 0) - *filteredFilesChanged = true; - } else { - model->setData(index, QVariant(HIGH)); - model->setData(index, QVariant(NORMAL)); - } + if(old_val != NORMAL){ + model->setData(index, QVariant(NORMAL)); + emit filteredFilesChanged(); + } else { + model->setData(index, QVariant(HIGH)); + model->setData(index, QVariant(NORMAL)); } } + } - void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const { - editor->setGeometry(option.rect); - } + void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const { + qDebug("UpdateEditor Geometry called"); + editor->setGeometry(option.rect); + } }; diff --git a/src/TransferListDelegate.h b/src/TransferListDelegate.h new file mode 100644 index 000000000..8f386a04e --- /dev/null +++ b/src/TransferListDelegate.h @@ -0,0 +1,116 @@ +/* + * Bittorrent Client using Qt4 and libtorrent. + * Copyright (C) 2006 Christophe Dumez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + * + * Contact : chris@qbittorrent.org + */ + +#ifndef TRANSFERLISTDELEGATE_H +#define TRANSFERLISTDELEGATE_H + +#include +#include +#include +#include +#include +#include +#include "misc.h" + +// Defines for download list list columns +enum Column {NAME, SIZE, PROGRESS, DLSPEED, UPSPEED, SEEDSLEECH, RATIO, ETA, PRIORITY, HASH, STATUS}; + +class TransferListDelegate: public QItemDelegate { + Q_OBJECT + +public: + TransferListDelegate(QObject *parent) : QItemDelegate(parent){} + + ~TransferListDelegate(){} + + void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const{ + QStyleOptionViewItemV2 opt = QItemDelegate::setOptions(index, option); + switch(index.column()){ + case SIZE: + QItemDelegate::drawBackground(painter, opt, index); + QItemDelegate::drawDisplay(painter, opt, option.rect, misc::friendlyUnit(index.data().toLongLong())); + break; + case ETA: + QItemDelegate::drawBackground(painter, opt, index); + QItemDelegate::drawDisplay(painter, opt, option.rect, misc::userFriendlyDuration(index.data().toLongLong())); + break; + case UPSPEED: + case DLSPEED:{ + QItemDelegate::drawBackground(painter, opt, index); + double speed = index.data().toDouble(); + QItemDelegate::drawDisplay(painter, opt, opt.rect, QString(QByteArray::number(speed/1024., 'f', 1))+QString::fromUtf8(" ")+tr("KiB/s")); + break; + } + case RATIO:{ + QItemDelegate::drawBackground(painter, opt, index); + double ratio = index.data().toDouble(); + if(ratio > 100.) + QItemDelegate::drawDisplay(painter, opt, opt.rect, QString::fromUtf8("∞")); + else + QItemDelegate::drawDisplay(painter, opt, opt.rect, QString(QByteArray::number(ratio, 'f', 1))); + break; + } + case PRIORITY: { + int priority = index.data().toInt(); + if(priority >= 0) { + QItemDelegate::paint(painter, option, index); + } else { + QItemDelegate::drawBackground(painter, opt, index); + QItemDelegate::drawDisplay(painter, opt, opt.rect, "*"); + } + break; + } + case PROGRESS:{ + QStyleOptionProgressBarV2 newopt; + double progress = index.data().toDouble()*100.; + newopt.rect = opt.rect; + newopt.text = QString(QByteArray::number(progress, 'f', 1))+QString::fromUtf8("%"); + newopt.progress = (int)progress; + newopt.maximum = 100; + newopt.minimum = 0; + newopt.state |= QStyle::State_Enabled; + newopt.textVisible = true; + QApplication::style()->drawControl(QStyle::CE_ProgressBar, &newopt, + painter); + break; + } + default: + QItemDelegate::paint(painter, option, index); + } + } + + QWidget* createEditor(QWidget*, const QStyleOptionViewItem &, const QModelIndex &) const { + // No editor here + return 0; + } + +}; + +#endif // TRANSFERLISTDELEGATE_H diff --git a/src/TransferListFiltersWidget.h b/src/TransferListFiltersWidget.h new file mode 100644 index 000000000..bc807025d --- /dev/null +++ b/src/TransferListFiltersWidget.h @@ -0,0 +1,60 @@ +#ifndef TRANSFERLISTFILTERSWIDGET_H +#define TRANSFERLISTFILTERSWIDGET_H + +#include +#include +#include +#include + +#include "TransferListWidget.h" + +class TransferListFiltersWidget: public QListWidget { + +private: + TransferListWidget *transferList; + +public: + TransferListFiltersWidget(QWidget *parent, TransferListWidget *transferList): QListWidget(parent), transferList(transferList) { + // Add filters + QListWidgetItem *all = new QListWidgetItem(this); + all->setData(Qt::DisplayRole, tr("All")); + all->setData(Qt::DecorationRole, QIcon(":/Icons/oxygen/folder-remote16.png")); + QListWidgetItem *downloading = new QListWidgetItem(this); + downloading->setData(Qt::DisplayRole, tr("Downloading")); + downloading->setData(Qt::DecorationRole, QIcon(":/Icons/skin/downloading.png")); + QListWidgetItem *completed = new QListWidgetItem(this); + completed->setData(Qt::DisplayRole, tr("Completed")); + completed->setData(Qt::DecorationRole, QIcon(":/Icons/skin/seeding.png")); + QListWidgetItem *active = new QListWidgetItem(this); + active->setData(Qt::DisplayRole, tr("Active")); + active->setData(Qt::DecorationRole, QIcon(":/Icons/oxygen/draw-triangle2.png")); + QListWidgetItem *inactive = new QListWidgetItem(this); + inactive->setData(Qt::DisplayRole, tr("Inactive")); + inactive->setData(Qt::DecorationRole, QIcon(":/Icons/oxygen/draw-rectangle.png")); + + // SIGNAL/SLOT + connect(this, SIGNAL(currentRowChanged(int)), transferList, SLOT(applyFilter(int))); + + // Load settings + loadSettings(); + } + + ~TransferListFiltersWidget() { + saveSettings(); + } + + void saveSettings() const { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + settings.beginGroup(QString::fromUtf8("TransferListFilters")); + settings.setValue("selectedFilterIndex", QVariant(currentRow())); + } + + void loadSettings() { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + settings.beginGroup(QString::fromUtf8("TransferListFilters")); + setCurrentRow(settings.value("selectedFilterIndex", 0).toInt()); + } + +}; + +#endif // TRANSFERLISTFILTERSWIDGET_H diff --git a/src/TransferListWidget.cpp b/src/TransferListWidget.cpp new file mode 100644 index 000000000..e5d9d84d1 --- /dev/null +++ b/src/TransferListWidget.cpp @@ -0,0 +1,842 @@ +/* + * Bittorrent Client using Qt4 and libtorrent. + * Copyright (C) 2006 Christophe Dumez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + * + * Contact : chris@qbittorrent.org + */ + +#include "TransferListWidget.h" +#include "TransferListDelegate.h" +#include "bittorrent.h" +#include "torrentPersistentData.h" +#include "previewSelect.h" +#include "allocationDlg.h" +#include "options_imp.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +TransferListWidget::TransferListWidget(QWidget *parent, bittorrent *_BTSession): QTreeView(parent) { + QSettings settings("qBittorrent", "qBittorrent"); + BTSession = _BTSession; + + // Create and apply delegate + listDelegate = new TransferListDelegate(this); + setItemDelegate(listDelegate); + + // Create transfer list model + listModel = new QStandardItemModel(0,11); + listModel->setHeaderData(NAME, Qt::Horizontal, tr("Name", "i.e: file name")); + listModel->setHeaderData(SIZE, Qt::Horizontal, tr("Size", "i.e: file size")); + listModel->setHeaderData(PROGRESS, Qt::Horizontal, tr("Progress", "i.e: % downloaded")); + listModel->setHeaderData(DLSPEED, Qt::Horizontal, tr("DL Speed", "i.e: Download speed")); + listModel->setHeaderData(UPSPEED, Qt::Horizontal, tr("UP Speed", "i.e: Upload speed")); + listModel->setHeaderData(SEEDSLEECH, Qt::Horizontal, tr("Seeds/Leechers", "i.e: full/partial sources")); + listModel->setHeaderData(RATIO, Qt::Horizontal, tr("Ratio")); + listModel->setHeaderData(ETA, Qt::Horizontal, tr("ETA", "i.e: Estimated Time of Arrival / Time left")); + listModel->setHeaderData(PRIORITY, Qt::Horizontal, "#"); + + // Set Sort/Filter proxy + proxyModel = new QSortFilterProxyModel(); + proxyModel->setDynamicSortFilter(true); + proxyModel->setSourceModel(listModel); + proxyModel->setFilterKeyColumn(STATUS); + proxyModel->setFilterRole(Qt::DisplayRole); + setModel(proxyModel); + + // Visual settings + setRootIsDecorated(false); + setAllColumnsShowFocus(true); + setSortingEnabled(true); + setSelectionMode(QAbstractItemView::ExtendedSelection); + setItemsExpandable(false); + setAutoScroll(true); + + hideColumn(PRIORITY); + hideColumn(HASH); + hideColumn(STATUS); + loadHiddenColumns(); + // Load last columns width for transfer list + if(!loadColWidthList()) { + header()->resizeSection(0, 200); + } + loadLastSortedColumn(); + setContextMenuPolicy(Qt::CustomContextMenu); + + // Listen for BTSession events + connect(BTSession, SIGNAL(addedTorrent(QTorrentHandle&)), this, SLOT(addTorrent(QTorrentHandle&))); + connect(BTSession, SIGNAL(finishedTorrent(QTorrentHandle&)), this, SLOT(setFinished(QTorrentHandle&))); + connect(BTSession, SIGNAL(metadataReceived(QTorrentHandle&)), this, SLOT(updateMetadata(QTorrentHandle&))); + + // Listen for list events + connect(this, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(torrentDoubleClicked(QModelIndex))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayListMenu(const QPoint&))); + connect(header(), SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayDLHoSMenu(const QPoint&))); + + // Refresh timer + refreshTimer = new QTimer(); + refreshTimer->start(settings.value("Preferences/General/RefreshInterval", 1500).toInt()); + connect(refreshTimer, SIGNAL(timeout()), this, SLOT(refreshList())); +} + +TransferListWidget::~TransferListWidget() { + // Save settings + saveLastSortedColumn(); + saveColWidthList(); + saveHiddenColumns(); + // Clean up + delete refreshTimer; + delete proxyModel; + delete listModel; + delete listDelegate; +} + +void TransferListWidget::addTorrent(QTorrentHandle& h) { + if(!h.is_valid()) return; + int row = listModel->rowCount(); + try { + // Adding torrent to transfer list + listModel->insertRow(row); + listModel->setData(listModel->index(row, NAME), QVariant(h.name())); + listModel->setData(listModel->index(row, SIZE), QVariant((qlonglong)h.actual_size())); + listModel->setData(listModel->index(row, ETA), QVariant((qlonglong)-1)); + listModel->setData(listModel->index(row, SEEDSLEECH), QVariant(QString::fromUtf8("0/0"))); + if(BTSession->isQueueingEnabled() && !h.is_seed()) + listModel->setData(listModel->index(row, PRIORITY), QVariant((int)BTSession->getDlTorrentPriority(h.hash()))); + listModel->setData(listModel->index(row, HASH), QVariant(h.hash())); + // Pause torrent if it is + if(h.is_paused()) { + listModel->setData(listModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/paused.png"))), Qt::DecorationRole); + listModel->setData(listModel->index(row, STATUS), INACTIVE); + //setRowColor(row, QString::fromUtf8("red")); + }else{ + listModel->setData(listModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/stalled.png"))), Qt::DecorationRole); + listModel->setData(listModel->index(row, STATUS), DOWNLOADING); + //setRowColor(row, QString::fromUtf8("grey")); + } + // Select first torrent to be added + if(listModel->rowCount() == 1) + selectionModel()->setCurrentIndex(proxyModel->index(row, NAME), QItemSelectionModel::SelectCurrent|QItemSelectionModel::Rows); + } catch(invalid_handle e) { + // Remove added torrent + listModel->removeRow(row); + } +} + +/*void TransferListWidget::setRowColor(int row, QColor color) { + unsigned int nbColumns = listModel->columnCount()-2; + for(unsigned int i=0; isetData(listModel->index(row, i), QVariant(color), Qt::ForegroundRole); + } +}*/ + +void TransferListWidget::deleteTorrent(int row) { + listModel->removeRow(row); +} + +void TransferListWidget::pauseTorrent(QString hash) { + pauseTorrent(getRowFromHash(hash)); +} + +void TransferListWidget::pauseTorrent(int row) { + listModel->setData(listModel->index(row, DLSPEED), QVariant((double)0.0)); + listModel->setData(listModel->index(row, UPSPEED), QVariant((double)0.0)); + listModel->setData(listModel->index(row, ETA), QVariant((qlonglong)-1)); + listModel->setData(listModel->index(row, NAME), QIcon(QString::fromUtf8(":/Icons/skin/paused.png")), Qt::DecorationRole); + listModel->setData(listModel->index(row, STATUS), INACTIVE); + listModel->setData(listModel->index(row, SEEDSLEECH), QVariant(QString::fromUtf8("0/0"))); + //setRowColor(row, QString::fromUtf8("red")); +} + +void TransferListWidget::resumeTorrent(int row) { + QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(row)); + if(!h.is_valid()) return; + if(h.is_seed()) { + listModel->setData(listModel->index(row, NAME), QVariant(QIcon(":/Icons/skin/seeding.png")), Qt::DecorationRole); + listModel->setData(listModel->index(row, STATUS), COMPLETED); + } + updateTorrent(row); +} + +void TransferListWidget::updateMetadata(QTorrentHandle &h) { + QString hash = h.hash(); + int row = getRowFromHash(hash); + if(row != -1) { + qDebug("Updating torrent metadata in download list"); + listModel->setData(listModel->index(row, NAME), QVariant(h.name())); + listModel->setData(listModel->index(row, SIZE), QVariant((qlonglong)h.actual_size())); + } +} + +void TransferListWidget::updateTorrent(int row) { + QString hash = getHashFromRow(row); + QTorrentHandle h = BTSession->getTorrentHandle(hash); + if(!h.is_valid()) { + // Delete torrent + deleteTorrent(row); + return; + } + try { + if(!h.is_seed()) { + // Queueing code + if(BTSession->isQueueingEnabled()) { + listModel->setData(listModel->index(row, PRIORITY), QVariant((int)BTSession->getDlTorrentPriority(hash))); + if(h.is_queued()) { + if(h.state() == torrent_status::checking_files || h.state() == torrent_status::queued_for_checking) { + listModel->setData(listModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/oxygen/run-build.png"))), Qt::DecorationRole); + listModel->setData(listModel->index(row, STATUS), INACTIVE); + listModel->setData(listModel->index(row, PROGRESS), QVariant((double)h.progress())); + }else { + listModel->setData(listModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/oxygen/mail-queue.png"))), Qt::DecorationRole); + listModel->setData(listModel->index(row, STATUS), INACTIVE); + listModel->setData(listModel->index(row, ETA), QVariant((qlonglong)-1)); + } + // Reset speeds and seeds/leech + listModel->setData(listModel->index(row, DLSPEED), QVariant((double)0.)); + listModel->setData(listModel->index(row, UPSPEED), QVariant((double)0.)); + listModel->setData(listModel->index(row, SEEDSLEECH), QVariant("0/0")); + //setRowColor(row, QString::fromUtf8("grey")); + return; + } + } + if(h.is_paused()) return; + // Update + listModel->setData(listModel->index(row, PROGRESS), QVariant((double)h.progress())); + listModel->setData(listModel->index(row, DLSPEED), QVariant((double)h.download_payload_rate())); + + // Parse download state + switch(h.state()) { + case torrent_status::checking_files: + case torrent_status::queued_for_checking: + case torrent_status::checking_resume_data: + listModel->setData(listModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/oxygen/run-build.png"))), Qt::DecorationRole); + listModel->setData(listModel->index(row, STATUS), INACTIVE); + //setRowColor(row, QString::fromUtf8("grey")); + break; + case torrent_status::downloading: + case torrent_status::downloading_metadata: + if(h.download_payload_rate() > 0) { + listModel->setData(listModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png"))), Qt::DecorationRole); + listModel->setData(listModel->index(row, ETA), QVariant((qlonglong)BTSession->getETA(hash))); + //setRowColor(row, QString::fromUtf8("green")); + }else{ + listModel->setData(listModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/stalled.png"))), Qt::DecorationRole); + listModel->setData(listModel->index(row, ETA), QVariant((qlonglong)-1)); + //setRowColor(row, QApplication::palette().color(QPalette::WindowText)); + } + listModel->setData(listModel->index(row, STATUS), DOWNLOADING); + listModel->setData(listModel->index(row, UPSPEED), QVariant((double)h.upload_payload_rate())); + break; + default: + listModel->setData(listModel->index(row, ETA), QVariant((qlonglong)-1)); + } + } + + // Common to both downloads and uploads + QString tmp = misc::toQString(h.num_seeds(), true); + if(h.num_complete() >= 0) + tmp.append(QString("(")+misc::toQString(h.num_complete())+QString(")")); + tmp.append(QString("/")+misc::toQString(h.num_peers() - h.num_seeds(), true)); + if(h.num_incomplete() >= 0) + tmp.append(QString("(")+misc::toQString(h.num_incomplete())+QString(")")); + listModel->setData(listModel->index(row, SEEDSLEECH), QVariant(tmp)); + listModel->setData(listModel->index(row, RATIO), QVariant(misc::toQString(BTSession->getRealRatio(hash)))); + listModel->setData(listModel->index(row, UPSPEED), QVariant((double)h.upload_payload_rate())); + // FIXME: Add all_time_upload column + }catch(invalid_handle e) { + deleteTorrent(row); + qDebug("Caught Invalid handle exception, lucky us."); + } +} + +void TransferListWidget::setFinished(QTorrentHandle &h) { + int row = -1; + try { + row = getRowFromHash(h.hash()); + if(row >= 0) { + if(h.is_paused()) { + listModel->setData(listModel->index(row, NAME), QIcon(":/Icons/skin/paused.png"), Qt::DecorationRole); + listModel->setData(listModel->index(row, STATUS), INACTIVE); + //setRowColor(row, "red"); + }else{ + listModel->setData(listModel->index(row, NAME), QVariant(QIcon(":/Icons/skin/seeding.png")), Qt::DecorationRole); + listModel->setData(listModel->index(row, STATUS), COMPLETED); + //setRowColor(row, "orange"); + } + listModel->setData(listModel->index(row, ETA), QVariant((qlonglong)-1)); + listModel->setData(listModel->index(row, DLSPEED), QVariant((double)0.)); + listModel->setData(listModel->index(row, PROGRESS), QVariant((double)1.)); + listModel->setData(listModel->index(row, PRIORITY), QVariant((int)-1)); + } + } catch(invalid_handle e) { + if(row >= 0) deleteTorrent(row); + } +} + +void TransferListWidget::setRefreshInterval(int t) { + refreshTimer->start(t); +} + +void TransferListWidget::refreshList() { + for(int i=0; irowCount(); ++i) { + updateTorrent(i); + } +} + +int TransferListWidget::getRowFromHash(QString hash) const{ + QList items = listModel->findItems(hash, Qt::MatchExactly, HASH); + if(items.empty()) return -1; + Q_ASSERT(items.size() == 1); + return items.first()->row(); +} + +QString TransferListWidget::getHashFromRow(int row) const { + return listModel->data(listModel->index(row, HASH)).toString(); +} + +void TransferListWidget::torrentDoubleClicked(QModelIndex index) { + int row = proxyModel->mapToSource(index).row(); + QString hash = getHashFromRow(row); + QTorrentHandle h = BTSession->getTorrentHandle(hash); + if(!h.is_valid()) return; + int action; + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + if(h.is_seed()) { + action = settings.value(QString::fromUtf8("Preferences/Downloads/DblClOnTorFN"), 0).toInt(); + } else { + action = settings.value(QString::fromUtf8("Preferences/Downloads/DblClOnTorDl"), 0).toInt(); + } + + switch(action) { + case TOGGLE_PAUSE: + if(h.is_paused()) { + h.resume(); + resumeTorrent(row); + } else { + h.pause(); + pauseTorrent(row); + } + break; + case OPEN_DEST: + QDesktopServices::openUrl(QUrl(h.save_path())); + break; + } +} + +void TransferListWidget::startSelectedTorrents() { + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + foreach(const QModelIndex &index, selectedIndexes) { + // Get the file hash + int row = proxyModel->mapToSource(index).row(); + QString hash = getHashFromRow(row); + QTorrentHandle h = BTSession->getTorrentHandle(hash); + if(h.is_valid() && h.is_paused()) { + h.resume(); + resumeTorrent(row); + } + } +} + +void TransferListWidget::startAllTorrents() { + for(int i=0; irowCount(); ++i) { + QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(i)); + if(h.is_valid() && h.is_paused()) { + h.resume(); + resumeTorrent(i); + } + } +} + +void TransferListWidget::pauseSelectedTorrents() { + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + foreach(const QModelIndex &index, selectedIndexes) { + // Get the file hash + int row = proxyModel->mapToSource(index).row(); + QString hash = getHashFromRow(row); + QTorrentHandle h = BTSession->getTorrentHandle(hash); + if(h.is_valid() && !h.is_paused()) { + h.pause(); + pauseTorrent(row); + } + } +} + +void TransferListWidget::pauseAllTorrents() { + for(int i=0; irowCount(); ++i) { + QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(i)); + if(h.is_valid() && !h.is_paused()) { + h.pause(); + pauseTorrent(i); + } + } +} + +void TransferListWidget::deleteSelectedTorrents() { + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + if(!selectedIndexes.empty()) { + int ret = QMessageBox::question( + this, + tr("Deletion confirmation"), + tr("Are you sure you want to delete the selected torrents from transfer list?"), + tr("&Yes"), tr("&No"), + QString(), 0, 1); + if(ret) return; + QStringList hashes; + foreach(const QModelIndex &index, selectedIndexes) { + // Get the file hash + hashes << getHashFromRow(proxyModel->mapToSource(index).row()); + } + foreach(const QString &hash, hashes) { + deleteTorrent(getRowFromHash(hash)); + BTSession->deleteTorrent(hash, false); + } + } +} + +void TransferListWidget::deletePermSelectedTorrents() { + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + if(!selectedIndexes.empty()) { + int ret = QMessageBox::question( + this, + tr("Deletion confirmation"), + tr("Are you sure you want to delete the selected torrents from transfe list and hard disk?"), + tr("&Yes"), tr("&No"), + QString(), 0, 1); + if(ret) return; + QStringList hashes; + foreach(const QModelIndex &index, selectedIndexes) { + // Get the file hash + hashes << getHashFromRow(proxyModel->mapToSource(index).row()); + } + foreach(const QString &hash, hashes) { + deleteTorrent(getRowFromHash(hash)); + BTSession->deleteTorrent(hash, true); + } + } +} + +// FIXME: Should work only if the tab is displayed +void TransferListWidget::increasePrioSelectedTorrents() { + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + foreach(const QModelIndex &index, selectedIndexes) { + QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(proxyModel->mapToSource(index).row())); + if(h.is_valid() && !h.is_seed()) { + BTSession->increaseDlTorrentPriority(h.hash()); + } + } + refreshList(); +} + +// FIXME: Should work only if the tab is displayed +void TransferListWidget::decreasePrioSelectedTorrents() { + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + foreach(const QModelIndex &index, selectedIndexes) { + QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(proxyModel->mapToSource(index).row())); + if(h.is_valid() && !h.is_seed()) { + BTSession->decreaseDlTorrentPriority(h.hash()); + } + } + refreshList(); +} + +void TransferListWidget::buySelectedTorrents() const { + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + foreach(const QModelIndex &index, selectedIndexes) { + QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(proxyModel->mapToSource(index).row())); + if(h.is_valid()) + QDesktopServices::openUrl("http://match.sharemonkey.com/?info_hash="+h.hash()+"&n="+h.name()+"&cid=33"); + } +} + +void TransferListWidget::copySelectedMagnetURIs() const { + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + QStringList magnet_uris; + foreach(const QModelIndex &index, selectedIndexes) { + QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(proxyModel->mapToSource(index).row())); + if(h.is_valid()) + magnet_uris << misc::toQString(make_magnet_uri(h.get_torrent_info())); + } + qApp->clipboard()->setText(magnet_uris.join("\n")); +} + +void TransferListWidget::hidePriorityColumn(bool hide) { + setColumnHidden(PRIORITY, hide); +} + +void TransferListWidget::openSelectedTorrentsFolder() const { + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + QStringList pathsList; + foreach(const QModelIndex &index, selectedIndexes) { + QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(proxyModel->mapToSource(index).row())); + if(h.is_valid()) { + QString savePath = h.save_path(); + if(!pathsList.contains(savePath)) { + pathsList.append(savePath); + QDesktopServices::openUrl(QUrl(QString("file://")+savePath)); + } + } + } +} + +void TransferListWidget::previewSelectedTorrents() { + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + QStringList pathsList; + foreach(const QModelIndex &index, selectedIndexes) { + QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(proxyModel->mapToSource(index).row())); + if(h.is_valid()) { + new previewSelect(this, h); + } + } +} + +void TransferListWidget::setDlLimitSelectedTorrents() { + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + QStringList hashes; + foreach(const QModelIndex &index, selectedIndexes) { + // Get the file hash + QString hash = getHashFromRow(proxyModel->mapToSource(index).row()); + QTorrentHandle h = BTSession->getTorrentHandle(hash); + if(h.is_valid() && !h.is_seed()) + hashes << hash; + } + Q_ASSERT(hashes.size() > 0); + new BandwidthAllocationDialog(this, false, BTSession, hashes); +} + +void TransferListWidget::setUpLimitSelectedTorrents() { + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + QStringList hashes; + foreach(const QModelIndex &index, selectedIndexes) { + // Get the file hash + hashes << getHashFromRow(proxyModel->mapToSource(index).row()); + } + Q_ASSERT(hashes.size() > 0); + new BandwidthAllocationDialog(this, true, BTSession, hashes); +} + +void TransferListWidget::recheckSelectedTorrents() { + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + foreach(const QModelIndex &index, selectedIndexes){ + QString hash = getHashFromRow(proxyModel->mapToSource(index).row()); + QTorrentHandle h = BTSession->getTorrentHandle(hash); + if(h.is_valid() && h.has_metadata()) + h.force_recheck(); + } +} + +// save the hidden columns in settings +void TransferListWidget::saveHiddenColumns() { + QSettings settings("qBittorrent", "qBittorrent"); + QStringList ishidden_list; + short nbColumns = listModel->columnCount()-2; + + for(short i=0; icolumnCount()-2) { + for(unsigned int i=0; iisQueueingEnabled()) { + lastCol = PRIORITY; + } else { + lastCol = ETA; + } + QList actions; + for(int i=0; i <= lastCol; ++i) { + QIcon icon; + if(isColumnHidden(i)) + icon = QIcon(QString::fromUtf8(":/Icons/oxygen/button_cancel.png")); + else + icon = QIcon(QString::fromUtf8(":/Icons/oxygen/button_ok.png")); + actions.append(hideshowColumn.addAction(icon, listModel->headerData(i, Qt::Horizontal).toString())); + } + // Call menu + QAction *act = hideshowColumn.exec(QCursor::pos()); + int col = actions.indexOf(act); + setColumnHidden(col, !isColumnHidden(col)); +} + +void TransferListWidget::displayListMenu(const QPoint&) { + // Create actions + QAction actionStart(QIcon(QString::fromUtf8(":/Icons/skin/play.png")), tr("Start"), 0); + connect(&actionStart, SIGNAL(triggered()), this, SLOT(startSelectedTorrents())); + QAction actionPause(QIcon(QString::fromUtf8(":/Icons/skin/pause.png")), tr("Pause"), 0); + connect(&actionPause, SIGNAL(triggered()), this, SLOT(pauseSelectedTorrents())); + QAction actionDelete(QIcon(QString::fromUtf8(":/Icons/skin/delete.png")), tr("Delete"), 0); + connect(&actionDelete, SIGNAL(triggered()), this, SLOT(deleteSelectedTorrents())); + QAction actionPreview_file(QIcon(QString::fromUtf8(":/Icons/skin/preview.png")), tr("Preview file"), 0); + connect(&actionPreview_file, SIGNAL(triggered()), this, SLOT(previewSelectedTorrents())); + QAction actionSet_upload_limit(QIcon(QString::fromUtf8(":/Icons/skin/seeding.png")), tr("Set upload limit"), 0); + connect(&actionSet_upload_limit, SIGNAL(triggered()), this, SLOT(setUpLimitSelectedTorrents())); + QAction actionSet_download_limit(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png")), tr("Set download limit"), 0); + connect(&actionSet_download_limit, SIGNAL(triggered()), this, SLOT(setDlLimitSelectedTorrents())); + QAction actionDelete_Permanently(QIcon(QString::fromUtf8(":/Icons/skin/delete_perm.png")), tr("Delete Permanently"), 0); + connect(&actionDelete_Permanently, SIGNAL(triggered()), this, SLOT(deletePermSelectedTorrents())); + QAction actionOpen_destination_folder(QIcon(QString::fromUtf8(":/Icons/oxygen/folder.png")), tr("Open destination folder"), 0); + connect(&actionOpen_destination_folder, SIGNAL(triggered()), this, SLOT(openSelectedTorrentsFolder())); + QAction actionBuy_it(QIcon(QString::fromUtf8(":/Icons/oxygen/wallet.png")), tr("Buy it"), 0); + connect(&actionBuy_it, SIGNAL(triggered()), this, SLOT(buySelectedTorrents())); + QAction actionIncreasePriority(QIcon(QString::fromUtf8(":/Icons/skin/increase.png")), tr("Increase priority"), 0); + connect(&actionIncreasePriority, SIGNAL(triggered()), this, SLOT(increasePrioSelectedTorrents())); + QAction actionDecreasePriority(QIcon(QString::fromUtf8(":/Icons/skin/decrease.png")), tr("Decrease priority"), 0); + connect(&actionDecreasePriority, SIGNAL(triggered()), this, SLOT(decreasePrioSelectedTorrents())); + QAction actionForce_recheck(QIcon(QString::fromUtf8(":/Icons/oxygen/gear.png")), tr("Force recheck"), 0); + connect(&actionForce_recheck, SIGNAL(triggered()), this, SLOT(recheckSelectedTorrents())); + QAction actionCopy_magnet_link(QIcon(QString::fromUtf8(":/Icons/magnet.png")), tr("Copy magnet link"), 0); + connect(&actionCopy_magnet_link, SIGNAL(triggered()), this, SLOT(copySelectedMagnetURIs())); + // End of actions + QMenu listMenu(this); + // Enable/disable pause/start action given the DL state + QModelIndexList selectedIndexes = selectionModel()->selectedRows(); + bool has_pause = false, has_start = false, has_preview = false; + bool one_has_metadata = false, one_not_seed = false; + QTorrentHandle h; + qDebug("Displaying menu"); + foreach(const QModelIndex &index, selectedIndexes) { + // Get the file name + QString hash = getHashFromRow(proxyModel->mapToSource(index).row()); + // Get handle and pause the torrent + h = BTSession->getTorrentHandle(hash); + if(!h.is_valid()) continue; + if(h.has_metadata()) + one_has_metadata = true; + if(!h.is_seed()) + one_not_seed = true; + if(h.is_paused()) { + if(!has_start) { + listMenu.addAction(&actionStart); + has_start = true; + } + }else{ + if(!has_pause) { + listMenu.addAction(&actionPause); + has_pause = true; + } + } + if(h.has_metadata() && BTSession->isFilePreviewPossible(hash) && !has_preview) { + listMenu.addAction(&actionPreview_file); + has_preview = true; + } + if(has_pause && has_start && has_preview && one_not_seed) break; + } + listMenu.addSeparator(); + listMenu.addAction(&actionDelete); + listMenu.addAction(&actionDelete_Permanently); + listMenu.addSeparator(); + if(one_not_seed) + listMenu.addAction(&actionSet_download_limit); + listMenu.addAction(&actionSet_upload_limit); + listMenu.addSeparator(); + if(one_has_metadata) { + listMenu.addAction(&actionForce_recheck); + listMenu.addSeparator(); + } + listMenu.addAction(&actionOpen_destination_folder); + if(BTSession->isQueueingEnabled() && one_not_seed) { + listMenu.addSeparator(); + listMenu.addAction(&actionIncreasePriority); + listMenu.addAction(&actionDecreasePriority); + } + listMenu.addSeparator(); + listMenu.addAction(&actionCopy_magnet_link); + listMenu.addAction(&actionBuy_it); + // Call menu + listMenu.exec(QCursor::pos()); +} + +// Save columns width in a file to remember them +void TransferListWidget::saveColWidthList() { + qDebug("Saving columns width in transfer list"); + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + QStringList width_list; + QStringList new_width_list; + short nbColumns = listModel->columnCount()-2; + QString line = settings.value("TransferListColsWidth", QString()).toString(); + if(!line.isEmpty()) { + width_list = line.split(' '); + } + for(short i=0; i=1) { + // load the former width + new_width_list << width_list.at(i); + } else if(columnWidth(i)>=1) { + // usual case, save the current width + new_width_list << misc::toQString(columnWidth(i)); + } else { + // default width + resizeColumnToContents(i); + new_width_list << misc::toQString(columnWidth(i)); + } + } + settings.setValue(QString::fromUtf8("TransferListColsWidth"), new_width_list.join(QString::fromUtf8(" "))); + QVariantList visualIndexes; + for(int i=0; ivisualIndex(i)); + } + settings.setValue(QString::fromUtf8("TransferListVisualIndexes"), visualIndexes); + qDebug("Download list columns width saved"); +} + +// Load columns width in a file that were saved previously +bool TransferListWidget::loadColWidthList() { + qDebug("Loading columns width for download list"); + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + QString line = settings.value(QString::fromUtf8("TransferListColsWidth"), QString()).toString(); + if(line.isEmpty()) + return false; + QStringList width_list = line.split(QString::fromUtf8(" ")); + if(width_list.size() != listModel->columnCount()-2) { + qDebug("Corrupted values for download list columns sizes"); + return false; + } + unsigned int listSize = width_list.size(); + for(unsigned int i=0; iresizeSection(i, width_list.at(i).toInt()); + } + QVariantList visualIndexes = settings.value(QString::fromUtf8("TransferListVisualIndexes"), QVariantList()).toList(); + if(visualIndexes.size() != listModel->columnCount()-2) { + qDebug("Corrupted values for download list columns sizes"); + return false; + } + bool change = false; + do { + change = false; + for(int i=0;ilogicalIndex(i)).toInt(); + if(i != new_visual_index) { + qDebug("Moving column from %d to %d", header()->logicalIndex(i), new_visual_index); + header()->moveSection(i, new_visual_index); + change = true; + } + } + }while(change); + qDebug("Transfer list columns width loaded"); + return true; +} + +void TransferListWidget::saveLastSortedColumn() { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + Qt::SortOrder sortOrder = header()->sortIndicatorOrder(); + QString sortOrderLetter; + if(sortOrder == Qt::AscendingOrder) + sortOrderLetter = QString::fromUtf8("a"); + else + sortOrderLetter = QString::fromUtf8("d"); + int index = header()->sortIndicatorSection(); + settings.setValue(QString::fromUtf8("TransferListSortedCol"), misc::toQString(index)+sortOrderLetter); +} + +void TransferListWidget::loadLastSortedColumn() { + // Loading last sorted column + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + QString sortedCol = settings.value(QString::fromUtf8("TransferListSortedCol"), 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(); + sortByColumn(index, sortOrder); + } +} + +void TransferListWidget::currentChanged(const QModelIndex& current, const QModelIndex&) { + QTorrentHandle h; + if(current.isValid()) { + int row = proxyModel->mapToSource(current).row(); + h = BTSession->getTorrentHandle(getHashFromRow(row)); + } + emit currentTorrentChanged(h); +} + +void TransferListWidget::applyFilter(int f) { + switch(f) { + case DOWNLOADING: + proxyModel->setFilterRegExp(QRegExp(QString::number(DOWNLOADING), Qt::CaseSensitive, QRegExp::FixedString)); + break; + case COMPLETED: + proxyModel->setFilterRegExp(QRegExp(QString::number(COMPLETED), Qt::CaseSensitive, QRegExp::FixedString)); + break; + case ACTIVE: + proxyModel->setFilterRegExp(QRegExp(QString::number(DOWNLOADING)+"|"+QString::number(COMPLETED), Qt::CaseSensitive)); + break; + case INACTIVE: + proxyModel->setFilterRegExp(QRegExp(QString::number(INACTIVE), Qt::CaseSensitive, QRegExp::FixedString)); + break; + default: + proxyModel->setFilterRegExp(QRegExp()); + } + // Select first item if nothing is selected + if(selectionModel()->selectedRows(0).empty() && proxyModel->rowCount() > 0) + selectionModel()->setCurrentIndex(proxyModel->index(0, NAME), QItemSelectionModel::SelectCurrent|QItemSelectionModel::Rows); +} + +void TransferListWidget::updateTorrentSizeAndProgress(QString hash) { + int row = getRowFromHash(hash); + Q_ASSERT(row != -1); + QTorrentHandle h = BTSession->getTorrentHandle(hash); + listModel->setData(listModel->index(row, SIZE), QVariant((qlonglong)h.actual_size())); + listModel->setData(listModel->index(row, PROGRESS), QVariant((double)h.progress())); +} diff --git a/src/TransferListWidget.h b/src/TransferListWidget.h new file mode 100644 index 000000000..b6de5da87 --- /dev/null +++ b/src/TransferListWidget.h @@ -0,0 +1,111 @@ +/* + * Bittorrent Client using Qt4 and libtorrent. + * Copyright (C) 2006 Christophe Dumez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + * + * Contact : chris@qbittorrent.org + */ + +#ifndef TRANSFERLISTWIDGET_H +#define TRANSFERLISTWIDGET_H + +#include +#include "qtorrenthandle.h" + +class TransferListDelegate; +class QStandardItemModel; +class QSortFilterProxyModel; +class bittorrent; +class QTimer; + +enum TorrentFilter {ALL, DOWNLOADING, COMPLETED, ACTIVE, INACTIVE }; + +class TransferListWidget: public QTreeView { + Q_OBJECT + +private: + TransferListDelegate *listDelegate; + QStandardItemModel *listModel; + QSortFilterProxyModel *proxyModel; + bittorrent* BTSession; + QTimer *refreshTimer; + +public: + TransferListWidget(QWidget *parent, bittorrent* BTSession); + ~TransferListWidget(); + +protected: + int getRowFromHash(QString hash) const; + QString getHashFromRow(int row) const; + void saveColWidthList(); + bool loadColWidthList(); + void saveLastSortedColumn(); + void loadLastSortedColumn(); + +protected slots: + void updateTorrent(int row); + void deleteTorrent(int row); + void pauseTorrent(int row); + void resumeTorrent(int row); + void torrentDoubleClicked(QModelIndex index); + bool loadHiddenColumns(); + void saveHiddenColumns(); + void displayListMenu(const QPoint&); + void updateMetadata(QTorrentHandle &h); + void currentChanged(const QModelIndex& current, const QModelIndex&); + //void setRowColor(int row, QColor color); + +public slots: + void refreshList(); + void addTorrent(QTorrentHandle& h); + void setFinished(QTorrentHandle &h); + void setRefreshInterval(int t); + void startSelectedTorrents(); + void startAllTorrents(); + void pauseSelectedTorrents(); + void pauseAllTorrents(); + void pauseTorrent(QString hash); + void deleteSelectedTorrents(); + void deletePermSelectedTorrents(); + void increasePrioSelectedTorrents(); + void decreasePrioSelectedTorrents(); + void buySelectedTorrents() const; + void copySelectedMagnetURIs() const; + void openSelectedTorrentsFolder() const; + void recheckSelectedTorrents(); + void setDlLimitSelectedTorrents(); + void setUpLimitSelectedTorrents(); + void previewSelectedTorrents(); + void hidePriorityColumn(bool hide); + void displayDLHoSMenu(const QPoint&); + void applyFilter(int f); + void updateTorrentSizeAndProgress(QString hash); + +signals: + void currentTorrentChanged(QTorrentHandle &h); + +}; + +#endif // TRANSFERLISTWIDGET_H diff --git a/src/arborescence.h b/src/arborescence.h index 5b6ff0f87..bad1919a9 100644 --- a/src/arborescence.h +++ b/src/arborescence.h @@ -41,7 +41,7 @@ private: torrent_file *parent; bool is_dir; QString rel_path; - QList children; + QList children; size_type size; float progress; int priority; @@ -63,6 +63,19 @@ public: qDeleteAll(children); } + void updateProgress(std::vector fp) { + progress = fp[index]/size; + Q_ASSERT(progress >= 0.); + Q_ASSERT(progress <= 1.); + // Update children + foreach(torrent_file* child, children) { + child->updateProgress(fp); + } + if(parent) { + parent->updateProgress(); + } + } + QString path() const { return rel_path; } @@ -90,7 +103,7 @@ public: void updatePriority(int prio) { Q_ASSERT(is_dir); - foreach(const torrent_file *child, children) { + foreach(torrent_file *child, children) { if(child->getPriority() != prio) return; } priority = prio; @@ -120,13 +133,13 @@ public: return (!children.isEmpty()); } - QList getChildren() const { + QList getChildren() const { return children; } - const torrent_file* getChild(QString fileName) const { + torrent_file* getChild(QString fileName) const { Q_ASSERT(is_dir); - foreach(const torrent_file *f, children) { + foreach(torrent_file *f, children) { if(f->name() == fileName) return f; } return 0; @@ -225,6 +238,10 @@ public: delete root; } + void updateFileProgress(std::vector fp) { + root->updateProgress(fp); + } + torrent_file* getRoot() const { return root; } diff --git a/src/bittorrent.cpp b/src/bittorrent.cpp index 281de1b89..c241b0ebf 100644 --- a/src/bittorrent.cpp +++ b/src/bittorrent.cpp @@ -243,32 +243,15 @@ QTorrentHandle bittorrent::getTorrentHandle(QString hash) const{ return QTorrentHandle(s->find_torrent(misc::fromString((hash.toStdString())))); } -unsigned int bittorrent::getFinishedPausedTorrentsNb() const { - unsigned int nbPaused = 0; +bool bittorrent::hasActiveTorrents() const { std::vector torrents = getTorrents(); std::vector::iterator torrentIT; for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { QTorrentHandle h = QTorrentHandle(*torrentIT); - if(!h.is_valid()) continue; - if(h.is_seed() && h.is_paused()) { - ++nbPaused; - } - } - return nbPaused; -} - -unsigned int bittorrent::getUnfinishedPausedTorrentsNb() const { - unsigned int nbPaused = 0; - std::vector torrents = getTorrents(); - std::vector::iterator torrentIT; - for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { - QTorrentHandle h = QTorrentHandle(*torrentIT); - if(!h.is_valid()) continue; - if(!h.is_seed() && h.is_paused()) { - ++nbPaused; - } + if(h.is_valid() && !h.is_paused() && !h.is_queued()) + return true; } - return nbPaused; + return false; } // Delete a torrent from the session, given its hash diff --git a/src/bittorrent.h b/src/bittorrent.h index 7e753adf7..6aaab3254 100644 --- a/src/bittorrent.h +++ b/src/bittorrent.h @@ -97,8 +97,7 @@ class bittorrent : public QObject { session* getSession() const; QHash getTrackersErrors(QString hash) const; bool has_filtered_files(QString hash) const; - unsigned int getFinishedPausedTorrentsNb() const; - unsigned int getUnfinishedPausedTorrentsNb() const; + bool hasActiveTorrents() const; bool isQueueingEnabled() const; int getDlTorrentPriority(QString hash) const; int getUpTorrentPriority(QString hash) const; diff --git a/src/download.ui b/src/download.ui deleted file mode 100644 index 306afb48f..000000000 --- a/src/download.ui +++ /dev/null @@ -1,193 +0,0 @@ - - - downloading - - - - 0 - 0 - 811 - 453 - - - - Search - - - - - - 6 - - - 0 - - - - - - 0 - 0 - - - - Qt::CustomContextMenu - - - true - - - QAbstractItemView::ExtendedSelection - - - 1 - - - false - - - - - - - - - Start - - - - - Pause - - - - - Delete - - - - - Preview file - - - - - Set upload limit - - - - - Set download limit - - - - - Delete Permanently - - - - - Torrent Properties - - - - - - :/Icons/oxygen/folder.png:/Icons/oxygen/folder.png - - - Open destination folder - - - - - Name - - - - - Size - - - - - Progress - - - - - DLSpeed - - - - - UpSpeed - - - - - Seeds/Leechs - - - - - Ratio - - - - - ETA - - - - - - :/Icons/oxygen/wallet.png:/Icons/oxygen/wallet.png - - - Buy it - - - - - Priority - - - - - - :/Icons/skin/increase.png:/Icons/skin/increase.png - - - Increase priority - - - - - - :/Icons/skin/decrease.png:/Icons/skin/decrease.png - - - Decrease priority - - - - - - :/Icons/oxygen/gear.png:/Icons/oxygen/gear.png - - - Force recheck - - - - - Copy magnet link - - - - - - - - diff --git a/src/downloadingTorrents.cpp b/src/downloadingTorrents.cpp deleted file mode 100644 index 697b2c393..000000000 --- a/src/downloadingTorrents.cpp +++ /dev/null @@ -1,780 +0,0 @@ -/* - * Bittorrent Client using Qt4 and libtorrent. - * Copyright (C) 2006 Christophe Dumez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * In addition, as a special exception, the copyright holders give permission to - * link this program with the OpenSSL project's "OpenSSL" library (or with - * modified versions of it that use the same license as the "OpenSSL" library), - * and distribute the linked executables. You must obey the GNU General Public - * License in all respects for all of the code used other than "OpenSSL". If you - * modify file(s), you may extend this exception to your version of the file(s), - * but you are not obligated to do so. If you do not wish to do so, delete this - * exception statement from your version. - * - * Contact : chris@qbittorrent.org - */ -#include "downloadingTorrents.h" -#include "misc.h" -#include "properties_imp.h" -#include "bittorrent.h" -#include "allocationDlg.h" -#include "DLListDelegate.h" -#include "GUI.h" - -#include -#include -#include -#include -#include -#include -#include - -DownloadingTorrents::DownloadingTorrents(QObject *parent, bittorrent *BTSession) : parent(parent), BTSession(BTSession), nbTorrents(0) { - setupUi(this); - // 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"))); - 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"))); - actionCopy_magnet_link->setIcon(QIcon(QString::fromUtf8(":/Icons/magnet.png"))); - // tabBottom->setTabIcon(0, QIcon(QString::fromUtf8(":/Icons/oxygen/log.png"))); - // tabBottom->setTabIcon(1, QIcon(QString::fromUtf8(":/Icons/oxygen/filter.png"))); - - // Set Download list model - DLListModel = new QStandardItemModel(0,10); - 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/Leechers", "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")); - DLListModel->setHeaderData(PRIORITY, Qt::Horizontal, "#"); - downloadList->setRootIsDecorated(false); - downloadList->setAllColumnsShowFocus(true); - DLDelegate = new DLListDelegate(downloadList); - downloadList->setItemDelegate(DLDelegate); - proxyModel = new QSortFilterProxyModel(); - proxyModel->setDynamicSortFilter(true); - proxyModel->setSourceModel(DLListModel); - downloadList->setModel(proxyModel); - downloadList->setSortingEnabled(true); - // Hide priority column - downloadList->hideColumn(PRIORITY); - // Hide hash column - downloadList->hideColumn(HASH); - loadHiddenColumns(); - - connect(BTSession, SIGNAL(metadataReceived(QTorrentHandle&)), this, SLOT(updateMetadata(QTorrentHandle&))); - - // 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, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayDLListMenu(const QPoint&))); - downloadList->header()->setContextMenuPolicy(Qt::CustomContextMenu); - connect(downloadList->header(), SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayDLHoSMenu(const QPoint&))); - // Actions - connect(actionPause, SIGNAL(triggered()), (GUI*)parent, SLOT(on_actionPause_triggered())); - connect(actionStart, SIGNAL(triggered()), (GUI*)parent, SLOT(on_actionStart_triggered())); - connect(actionDelete, SIGNAL(triggered()), (GUI*)parent, SLOT(on_actionDelete_triggered())); - connect(actionIncreasePriority, SIGNAL(triggered()), (GUI*)parent, SLOT(on_actionIncreasePriority_triggered())); - connect(actionDecreasePriority, SIGNAL(triggered()), (GUI*)parent, SLOT(on_actionDecreasePriority_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(actionOpen_destination_folder, SIGNAL(triggered()), (GUI*)parent, SLOT(openDestinationFolder())); - connect(actionTorrent_Properties, SIGNAL(triggered()), this, SLOT(propertiesSelection())); - connect(actionForce_recheck, SIGNAL(triggered()), this, SLOT(forceRecheck())); - connect(actionBuy_it, SIGNAL(triggered()), (GUI*)parent, SLOT(goBuyPage())); - connect(actionCopy_magnet_link, SIGNAL(triggered()), (GUI*)parent, SLOT(copyMagnetURI())); - - connect(actionHOSColName, SIGNAL(triggered()), this, SLOT(hideOrShowColumnName())); - connect(actionHOSColSize, SIGNAL(triggered()), this, SLOT(hideOrShowColumnSize())); - connect(actionHOSColProgress, SIGNAL(triggered()), this, SLOT(hideOrShowColumnProgress())); - connect(actionHOSColDownSpeed, SIGNAL(triggered()), this, SLOT(hideOrShowColumnDownSpeed())); - connect(actionHOSColUpSpeed, SIGNAL(triggered()), this, SLOT(hideOrShowColumnUpSpeed())); - connect(actionHOSColSeedersLeechers, SIGNAL(triggered()), this, SLOT(hideOrShowColumnSeedersLeechers())); - connect(actionHOSColRatio, SIGNAL(triggered()), this, SLOT(hideOrShowColumnRatio())); - connect(actionHOSColEta, SIGNAL(triggered()), this, SLOT(hideOrShowColumnEta())); - connect(actionHOSColPriority, SIGNAL(triggered()), this, SLOT(hideOrShowColumnPriority())); - - // Load last sorted column - loadLastSortedColumn(); - // Set info Bar infos - BTSession->addConsoleMessage(tr("qBittorrent %1 started.", "e.g: qBittorrent v0.x started.").arg(QString::fromUtf8(""VERSION))); - qDebug("Download tab built"); -} - -DownloadingTorrents::~DownloadingTorrents() { - saveLastSortedColumn(); - saveColWidthDLList(); - saveHiddenColumns(); - delete DLDelegate; - delete proxyModel; - delete DLListModel; -} - -void DownloadingTorrents::enablePriorityColumn(bool enable) { - if(enable) { - downloadList->showColumn(PRIORITY); - } else { - downloadList->hideColumn(PRIORITY); - } -} - -void DownloadingTorrents::notifyTorrentDoubleClicked(const QModelIndex& index) { - unsigned int row = index.row(); - QString hash = getHashFromRow(row); - emit torrentDoubleClicked(hash, false); -} - -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); - if(row == -1) - return; - 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); - //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)proxyModel->rowCount()); - return proxyModel->data(proxyModel->index(row, HASH)).toString(); -} - -// Show torrent properties dialog -void DownloadingTorrents::showProperties(const QModelIndex &index) { - showPropertiesFromHash(getHashFromRow(index.row())); -} - -void DownloadingTorrents::showPropertiesFromHash(QString hash) { - QTorrentHandle h = BTSession->getTorrentHandle(hash); - if(h.is_valid() && h.has_metadata()) { - properties *prop = new properties(this, BTSession, h); - connect(prop, SIGNAL(filteredFilesChanged(QString)), this, SLOT(updateFileSizeAndProgress(QString))); - connect(prop, SIGNAL(trackersChanged(QString)), BTSession, SLOT(saveTrackerFile(QString))); - prop->show(); - } -} - -// Remove a torrent from the download list but NOT from the BT Session -void DownloadingTorrents::deleteTorrent(QString hash) { - int row = getRowFromHash(hash); - if(row == -1){ - qDebug("torrent is not in download list, nothing to delete"); - return; - } - // Select item just under (or above nothing under) the one that was deleted - QModelIndex current_prox_index = proxyModel->mapFromSource(DLListModel->index(row, 0, downloadList->rootIndex())); - bool was_selected = downloadList->selectionModel()->isSelected(current_prox_index); - if(DLListModel->rowCount() > 1 && was_selected) { - QModelIndex under_prox_index; - if(current_prox_index.row() == DLListModel->rowCount()-1) - under_prox_index = proxyModel->index(current_prox_index.row()-1, 0); - else - under_prox_index = proxyModel->index(current_prox_index.row()+1, 0); - //downloadList->selectionModel()->select(under_prox_index, QItemSelectionModel::Current|QItemSelectionModel::Columns|QItemSelectionModel::Select); - downloadList->setCurrentIndex(under_prox_index); - downloadList->update(); - } - // Actually delete the row - DLListModel->removeRow(row); - --nbTorrents; - emit unfinishedTorrentsNumberChanged(nbTorrents); -} - -void DownloadingTorrents::on_actionSet_download_limit_triggered() { - QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes(); - QStringList hashes; - foreach(const QModelIndex &index, selectedIndexes) { - if(index.column() == NAME) { - // Get the file hash - hashes << getHashFromRow(index.row()); - } - } - Q_ASSERT(hashes.size() > 0); - new BandwidthAllocationDialog(this, false, BTSession, hashes); -} - -void DownloadingTorrents::on_actionSet_upload_limit_triggered() { - QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes(); - QStringList hashes; - foreach(const QModelIndex &index, selectedIndexes) { - if(index.column() == NAME) { - // Get the file hash - hashes << getHashFromRow(index.row()); - } - } - Q_ASSERT(hashes.size() > 0); - new BandwidthAllocationDialog(this, true, BTSession, hashes); -} - -// display properties of selected items -void DownloadingTorrents::propertiesSelection(){ - QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes(); - foreach(const QModelIndex &index, selectedIndexes){ - if(index.column() == NAME){ - showProperties(index); - } - } -} - -void DownloadingTorrents::forceRecheck() { - QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes(); - foreach(const QModelIndex &index, selectedIndexes){ - if(index.column() == NAME){ - QString hash = getHashFromRow(index.row()); - QTorrentHandle h = BTSession->getTorrentHandle(hash); - if(h.is_valid() && h.has_metadata()) - h.force_recheck(); - } - } -} - -void DownloadingTorrents::displayDLListMenu(const QPoint&) { - QMenu myDLLlistMenu(this); - // Enable/disable pause/start action given the DL state - QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes(); - bool has_pause = false, has_start = false, has_preview = false; - bool one_has_metadata = false; - QTorrentHandle h; - qDebug("Displaying menu"); - foreach(const QModelIndex &index, selectedIndexes) { - if(index.column() == NAME) { - // Get the file name - QString hash = getHashFromRow(index.row()); - // Get handle and pause the torrent - h = BTSession->getTorrentHandle(hash); - if(!h.is_valid()) continue; - if(h.has_metadata()) { - one_has_metadata = true; - } - if(h.is_paused()) { - if(!has_start) { - myDLLlistMenu.addAction(actionStart); - has_start = true; - } - }else{ - if(!has_pause) { - myDLLlistMenu.addAction(actionPause); - has_pause = true; - } - } - if(h.has_metadata() && 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(); - if(one_has_metadata) { - myDLLlistMenu.addAction(actionForce_recheck); - myDLLlistMenu.addSeparator(); - } - myDLLlistMenu.addAction(actionOpen_destination_folder); - if(one_has_metadata) - myDLLlistMenu.addAction(actionTorrent_Properties); - if(BTSession->isQueueingEnabled()) { - myDLLlistMenu.addSeparator(); - myDLLlistMenu.addAction(actionIncreasePriority); - myDLLlistMenu.addAction(actionDecreasePriority); - } - myDLLlistMenu.addSeparator(); - myDLLlistMenu.addAction(actionCopy_magnet_link); - myDLLlistMenu.addAction(actionBuy_it); - // Call menu - myDLLlistMenu.exec(QCursor::pos()); -} - - -/* - * Hiding Columns functions - */ - -// hide/show columns menu -void DownloadingTorrents::displayDLHoSMenu(const QPoint&){ - QMenu hideshowColumn(this); - hideshowColumn.setTitle(tr("Hide or Show Column")); - int lastCol; - if(BTSession->isQueueingEnabled()) { - lastCol = PRIORITY; - } else { - lastCol = ETA; - } - for(int i=0; i <= lastCol; ++i) { - hideshowColumn.addAction(getActionHoSCol(i)); - } - // Call menu - hideshowColumn.exec(QCursor::pos()); -} - -// toggle hide/show a column -void DownloadingTorrents::hideOrShowColumn(int index) { - unsigned int nbVisibleColumns = 0; - unsigned int nbCols = DLListModel->columnCount(); - // Count visible columns - for(unsigned int i=0; iisColumnHidden(i)) - ++nbVisibleColumns; - } - if(!downloadList->isColumnHidden(index)) { - // User wants to hide the column - // Is there at least one other visible column? - if(nbVisibleColumns <= 1) return; - // User can hide the column, do it. - downloadList->setColumnHidden(index, true); - getActionHoSCol(index)->setIcon(QIcon(QString::fromUtf8(":/Icons/oxygen/button_cancel.png"))); - --nbVisibleColumns; - } else { - // User want to display the column - downloadList->setColumnHidden(index, false); - getActionHoSCol(index)->setIcon(QIcon(QString::fromUtf8(":/Icons/oxygen/button_ok.png"))); - ++nbVisibleColumns; - } - //resize all others non-hidden columns - for(unsigned int i=0; iisColumnHidden(i)) { - downloadList->setColumnWidth(i, (int)ceil(downloadList->columnWidth(i)+(downloadList->columnWidth(index)/nbVisibleColumns))); - } - } -} - -void DownloadingTorrents::hidePriorityColumn(bool hide) { - downloadList->setColumnHidden(PRIORITY, hide); - if(hide) - getActionHoSCol(PRIORITY)->setIcon(QIcon(QString::fromUtf8(":/Icons/oxygen/button_cancel.png"))); - else - getActionHoSCol(PRIORITY)->setIcon(QIcon(QString::fromUtf8(":/Icons/oxygen/button_ok.png"))); -} - -// save the hidden columns in settings -void DownloadingTorrents::saveHiddenColumns() { - QSettings settings("qBittorrent", "qBittorrent"); - QStringList ishidden_list; - short nbColumns = DLListModel->columnCount()-1; - - for(short i=0; iisColumnHidden(i)) { - ishidden_list << QString::fromUtf8(misc::toString(0).c_str()); - } else { - ishidden_list << QString::fromUtf8(misc::toString(1).c_str()); - } - } - settings.setValue("DownloadListColsHoS", ishidden_list.join(" ")); -} - -// load the previous settings, and hide the columns -bool DownloadingTorrents::loadHiddenColumns() { - bool loaded = false; - QSettings settings("qBittorrent", "qBittorrent"); - QString line = settings.value("DownloadListColsHoS", QString()).toString(); - QStringList ishidden_list; - if(!line.isEmpty()) { - ishidden_list = line.split(' '); - if(ishidden_list.size() == DLListModel->columnCount()-1) { - unsigned int listSize = ishidden_list.size(); - for(unsigned int i=0; iheader()->resizeSection(i, ishidden_list.at(i).toInt()); - } - loaded = true; - } - } - for(int i=0; icolumnCount()-1; i++) { - if(loaded && ishidden_list.at(i) == "0") { - downloadList->setColumnHidden(i, true); - getActionHoSCol(i)->setIcon(QIcon(QString::fromUtf8(":/Icons/oxygen/button_cancel.png"))); - } else { - getActionHoSCol(i)->setIcon(QIcon(QString::fromUtf8(":/Icons/oxygen/button_ok.png"))); - } - } - return loaded; -} - -void DownloadingTorrents::hideOrShowColumnName() { - hideOrShowColumn(NAME); -} - -void DownloadingTorrents::hideOrShowColumnSize() { - hideOrShowColumn(SIZE); -} - -void DownloadingTorrents::hideOrShowColumnProgress() { - hideOrShowColumn(PROGRESS); -} - -void DownloadingTorrents::hideOrShowColumnDownSpeed() { - hideOrShowColumn(DLSPEED); -} - -void DownloadingTorrents::hideOrShowColumnUpSpeed() { - hideOrShowColumn(UPSPEED); -} - -void DownloadingTorrents::hideOrShowColumnSeedersLeechers() { - hideOrShowColumn(SEEDSLEECH); -} - -void DownloadingTorrents::hideOrShowColumnRatio() { - hideOrShowColumn(RATIO); -} - -void DownloadingTorrents::hideOrShowColumnEta() { - hideOrShowColumn(ETA); -} - -void DownloadingTorrents::hideOrShowColumnPriority() { - hideOrShowColumn(PRIORITY); -} - -// getter, return the action hide or show whose id is index -QAction* DownloadingTorrents::getActionHoSCol(int index) { - switch(index) { - case NAME : - return actionHOSColName; - break; - case SIZE : - return actionHOSColSize; - break; - case PROGRESS : - return actionHOSColProgress; - break; - case DLSPEED : - return actionHOSColDownSpeed; - break; - case UPSPEED : - return actionHOSColUpSpeed; - break; - case SEEDSLEECH : - return actionHOSColSeedersLeechers; - break; - case RATIO : - return actionHOSColRatio; - break; - case ETA : - return actionHOSColEta; - break; - case PRIORITY : - return actionHOSColPriority; - break; - default : - return NULL; -} -} - -QStringList DownloadingTorrents::getSelectedTorrents(bool only_one) const{ - QStringList res; - QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes(); - foreach(const QModelIndex &index, selectedIndexes) { - if(index.column() == NAME) { - // Get the file hash - QString hash = getHashFromRow(index.row()); - res << hash; - if(only_one) break; - } - } - return res; -} - -void DownloadingTorrents::updateMetadata(QTorrentHandle &h) { - QString hash = h.hash(); - int row = getRowFromHash(hash); - if(row != -1) { - qDebug("Updating torrent metadata in download list"); - DLListModel->setData(DLListModel->index(row, NAME), QVariant(h.name())); - DLListModel->setData(DLListModel->index(row, SIZE), QVariant((qlonglong)h.actual_size())); - } -} - -// get information from torrent handles and -// update download list accordingly -bool DownloadingTorrents::updateTorrent(QTorrentHandle h) { - if(!h.is_valid()) return false; - bool added = false; - 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); - added = true; - } - Q_ASSERT(row != -1); - // Update Priority - if(BTSession->isQueueingEnabled()) { - DLListModel->setData(DLListModel->index(row, PRIORITY), QVariant((int)BTSession->getDlTorrentPriority(hash))); - if(h.is_queued()) { - if(h.state() == torrent_status::checking_files || h.state() == torrent_status::queued_for_checking) { - DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/oxygen/time.png"))), Qt::DecorationRole); - if(!downloadList->isColumnHidden(PROGRESS)) { - DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)h.progress())); - } - }else { - DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/queued.png"))), Qt::DecorationRole); - if(!downloadList->isColumnHidden(ETA)) { - DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1)); - } - } - // Reset speeds and seeds/leech - 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("0/0")); - setRowColor(row, QString::fromUtf8("grey")); - return added; - } - } - if(!downloadList->isColumnHidden(PROGRESS)) - DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)h.progress())); - // No need to update a paused torrent - if(h.is_paused()) return added; - // Parse download state - // Setting download state - switch(h.state()) { - case torrent_status::checking_files: - case torrent_status::queued_for_checking: - case torrent_status::checking_resume_data: - DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/oxygen/time.png"))), Qt::DecorationRole); - setRowColor(row, QString::fromUtf8("grey")); - break; - case torrent_status::downloading: - case torrent_status::downloading_metadata: - if(h.download_payload_rate() > 0) { - DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png"))), Qt::DecorationRole); - if(!downloadList->isColumnHidden(ETA)) { - 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); - if(!downloadList->isColumnHidden(ETA)) { - DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1)); - } - setRowColor(row, QApplication::palette().color(QPalette::WindowText)); - } - if(!downloadList->isColumnHidden(DLSPEED)) { - DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)h.download_payload_rate())); - } - if(!downloadList->isColumnHidden(UPSPEED)) { - DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)h.upload_payload_rate())); - } - break; - default: - if(!downloadList->isColumnHidden(ETA)) { - DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1)); - } - } - if(!downloadList->isColumnHidden(SEEDSLEECH)) { - QString tmp = misc::toQString(h.num_seeds(), true); - if(h.num_complete() >= 0) - tmp.append(QString("(")+misc::toQString(h.num_complete())+QString(")")); - tmp.append(QString("/")+misc::toQString(h.num_peers() - h.num_seeds(), true)); - if(h.num_incomplete() >= 0) - tmp.append(QString("(")+misc::toQString(h.num_incomplete())+QString(")")); - DLListModel->setData(DLListModel->index(row, SEEDSLEECH), QVariant(tmp)); - } - if(!downloadList->isColumnHidden(RATIO)) { - DLListModel->setData(DLListModel->index(row, RATIO), QVariant(misc::toQString(BTSession->getRealRatio(hash)))); - } - }catch(invalid_handle e) {} - return added; -} - -void DownloadingTorrents::addTorrent(QString hash) { - QTorrentHandle h = BTSession->getTorrentHandle(hash); - int row = getRowFromHash(hash); - qDebug("DL: addTorrent(): %s, row: %d", (const char*)hash.toLocal8Bit(), row); - 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, PROGRESS), QVariant((double)h.progress())); - DLListModel->setData(DLListModel->index(row, RATIO), QVariant((double)0.)); - DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1)); - if(BTSession->isQueueingEnabled()) - DLListModel->setData(DLListModel->index(row, PRIORITY), QVariant((int)BTSession->getDlTorrentPriority(hash))); - DLListModel->setData(DLListModel->index(row, HASH), QVariant(hash)); - // Pause torrent if it is - if(h.is_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/stalled.png"))), Qt::DecorationRole); - setRowColor(row, QString::fromUtf8("grey")); - } - ++nbTorrents; - emit unfinishedTorrentsNumberChanged(nbTorrents); -} - -// 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; - QStringList new_width_list; - short nbColumns = DLListModel->columnCount()-1; - QString line = settings.value("DownloadListColsWidth", QString()).toString(); - if(!line.isEmpty()) { - width_list = line.split(' '); - } - for(short i=0; icolumnWidth(i)<1 && width_list.size() == nbColumns && width_list.at(i).toInt()>=1) { - // load the former width - new_width_list << width_list.at(i); - } else if(downloadList->columnWidth(i)>=1) { - // usual case, save the current width - new_width_list << QString::fromUtf8(misc::toString(downloadList->columnWidth(i)).c_str()); - } else { - // default width - downloadList->resizeColumnToContents(i); - new_width_list << QString::fromUtf8(misc::toString(downloadList->columnWidth(i)).c_str()); - } - } - settings.setValue(QString::fromUtf8("DownloadListColsWidth"), new_width_list.join(QString::fromUtf8(" "))); - QVariantList visualIndexes; - for(int i=0; iheader()->visualIndex(i)); - } - settings.setValue(QString::fromUtf8("DownloadListVisualIndexes"), visualIndexes); - 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()); - } - QVariantList visualIndexes = settings.value(QString::fromUtf8("DownloadListVisualIndexes"), QVariantList()).toList(); - if(visualIndexes.size() != DLListModel->columnCount()-1) { - qDebug("Corrupted values for download list columns sizes"); - return false; - } - bool change = false; - do { - change = false; - for(int i=0;iheader()->logicalIndex(i)).toInt(); - if(i != new_visual_index) { - qDebug("Moving column from %d to %d", downloadList->header()->logicalIndex(i), new_visual_index); - downloadList->header()->moveSection(i, new_visual_index); - change = true; - } - } - }while(change); - qDebug("Download list columns width loaded"); - return true; -} - -void DownloadingTorrents::saveLastSortedColumn() { - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - Qt::SortOrder sortOrder = downloadList->header()->sortIndicatorOrder(); - QString sortOrderLetter; - if(sortOrder == Qt::AscendingOrder) - sortOrderLetter = QString::fromUtf8("a"); - else - sortOrderLetter = QString::fromUtf8("d"); - int index = downloadList->header()->sortIndicatorSection(); - settings.setValue(QString::fromUtf8("DownloadListSortedCol"), misc::toQString(index)+sortOrderLetter); -} - -void DownloadingTorrents::loadLastSortedColumn() { - // Loading last sorted column - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - 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(); - downloadList->sortByColumn(index, sortOrder); - } -} - -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())); - //DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)h.progress())); -} - -// Set the color of a row in data model -void DownloadingTorrents::setRowColor(int row, QColor color) { - unsigned int nbColumns = DLListModel->columnCount()-1; - for(unsigned int i=0; isetData(DLListModel->index(row, i), QVariant(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; -} diff --git a/src/downloadingTorrents.h b/src/downloadingTorrents.h deleted file mode 100644 index 0004ee408..000000000 --- a/src/downloadingTorrents.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Bittorrent Client using Qt4 and libtorrent. - * Copyright (C) 2006 Christophe Dumez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * In addition, as a special exception, the copyright holders give permission to - * link this program with the OpenSSL project's "OpenSSL" library (or with - * modified versions of it that use the same license as the "OpenSSL" library), - * and distribute the linked executables. You must obey the GNU General Public - * License in all respects for all of the code used other than "OpenSSL". If you - * modify file(s), you may extend this exception to your version of the file(s), - * but you are not obligated to do so. If you do not wish to do so, delete this - * exception statement from your version. - * - * Contact : chris@qbittorrent.org - */ - -#ifndef DOWNLOADINGTORRENTS_H -#define DOWNLOADINGTORRENTS_H - -#include "ui_download.h" -#include "qtorrenthandle.h" - -class QStandardItemModel; -class bittorrent; -class DLListDelegate; -class QSortFilterProxyModel; - -using namespace libtorrent; - -class DownloadingTorrents : public QWidget, public Ui::downloading{ - Q_OBJECT - private: - QObject *parent; - bittorrent *BTSession; - DLListDelegate *DLDelegate; - QStandardItemModel *DLListModel; - QSortFilterProxyModel *proxyModel; - unsigned int nbTorrents; - void hideOrShowColumn(int index); - bool loadHiddenColumns(); - void saveHiddenColumns(); - QAction* getActionHoSCol(int index); - - 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; - void enablePriorityColumn(bool enable); - - signals: - void unfinishedTorrentsNumberChanged(unsigned int); - void torrentDoubleClicked(QString hash, bool finished); - - protected slots: - void on_actionSet_download_limit_triggered(); - void notifyTorrentDoubleClicked(const QModelIndex& index); - void on_actionSet_upload_limit_triggered(); - void displayDLListMenu(const QPoint& pos); - void displayDLHoSMenu(const QPoint&); - void saveColWidthDLList() const; - void setRowColor(int row, QColor color); - void showProperties(const QModelIndex &index); - void hideOrShowColumnName(); - void hideOrShowColumnSize(); - void hideOrShowColumnProgress(); - void hideOrShowColumnDownSpeed(); - void hideOrShowColumnUpSpeed(); - void hideOrShowColumnSeedersLeechers(); - void hideOrShowColumnRatio(); - void hideOrShowColumnEta(); - void hideOrShowColumnPriority(); - void forceRecheck(); - - public slots: - bool updateTorrent(QTorrentHandle h); - void pauseTorrent(QString hash); - void deleteTorrent(QString hash); - void propertiesSelection(); - void updateFileSizeAndProgress(QString hash); - void showPropertiesFromHash(QString hash); - void hidePriorityColumn(bool hide); - void saveLastSortedColumn(); - void loadLastSortedColumn(); - void addTorrent(QString hash); - void updateMetadata(QTorrentHandle &h); - -}; - -#endif diff --git a/src/icons.qrc b/src/icons.qrc index 4f9f4278c..e70126d52 100644 --- a/src/icons.qrc +++ b/src/icons.qrc @@ -35,7 +35,6 @@ Icons/skin/info.png Icons/skin/tabs.gif Icons/skin/delete_perm.png - Icons/skin/queued.png Icons/skin/settings.png Icons/skin/exit.png Icons/skin/delete_all.png @@ -68,13 +67,16 @@ Icons/flags/italy.png Icons/flags/south_korea.png Icons/flags/japan.png + Icons/oxygen/mail-queue.png Icons/oxygen/view-refresh.png Icons/oxygen/file.png + Icons/oxygen/folder-remote16.png Icons/oxygen/mail-folder-inbox.png - Icons/oxygen/time.png Icons/oxygen/edit-find.png Icons/oxygen/folder-new.png + Icons/oxygen/folder-remote.png Icons/oxygen/edit-paste.png + Icons/oxygen/run-build.png Icons/oxygen/proxy.png Icons/oxygen/log.png Icons/oxygen/unavailable.png @@ -87,7 +89,9 @@ Icons/oxygen/download.png Icons/oxygen/application-x-kgetlist-no.png Icons/oxygen/gear.png + Icons/oxygen/draw-triangle2.png Icons/oxygen/remove.png + Icons/oxygen/peer.png Icons/oxygen/browse.png Icons/oxygen/unsubscribe16.png Icons/oxygen/subscribe.png @@ -101,11 +105,15 @@ Icons/oxygen/list-remove.png Icons/oxygen/connection.png Icons/oxygen/bug.png + Icons/oxygen/help-about.png Icons/oxygen/list-add.png + Icons/oxygen/network-server.png Icons/oxygen/application-x-kgetlist.png Icons/oxygen/folder.png + Icons/oxygen/urlseed.png Icons/oxygen/edit-cut.png Icons/oxygen/unsubscribe.png + Icons/oxygen/draw-rectangle.png Icons/oxygen/subscribe16.png \ No newline at end of file diff --git a/src/properties.ui b/src/properties.ui deleted file mode 100644 index 2f83b0d11..000000000 --- a/src/properties.ui +++ /dev/null @@ -1,1080 +0,0 @@ - - - properties - - - - 0 - 0 - 594 - 621 - - - - Torrent Properties - - - - 6 - - - 9 - - - - - 0 - - - - Main info - - - - - - - 16777215 - 20 - - - - - Sans Serif - 9 - 75 - false - true - false - false - - - - - - - Qt::AlignCenter - - - - - - - Qt::Horizontal - - - - - - - - 75 - true - - - - Torrent information - - - - - - - - 6 - - - 0 - - - - - - 0 - 29 - - - - - 75 - true - - - - Save path: - - - - - - - - 0 - 28 - - - - - 75 - true - - - - Creator: - - - - - - - - 0 - 29 - - - - - 75 - true - - - - Torrent hash: - - - - - - - - 0 - 128 - - - - - 16777215 - 120 - - - - - 75 - true - - - - Comment: - - - - - - - - - - - - - - 0 - 29 - - - - - - - - - - - - 21 - 0 - - - - - 21 - 16777215 - - - - ... - - - - - - - - - - 0 - 28 - - - - - - - - - - - - 0 - 29 - - - - - - - - - - - - 16777215 - 120 - - - - false - - - true - - - false - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - 0 - 50 - - - - - 75 - true - - - - Downloaded pieces - - - - - - - - 0 - 0 - - - - - 0 - 115 - - - - - Sans Serif - 9 - 75 - false - true - false - false - - - - Current session - - - - 6 - - - 9 - - - - - 6 - - - 0 - - - - - 6 - - - 0 - - - - - - Sans Serif - 9 - 50 - false - false - false - false - - - - Total uploaded: - - - - - - - - Sans Serif - 9 - 50 - false - false - false - false - - - - Total downloaded: - - - - - - - - Sans Serif - 9 - 50 - false - false - false - false - - - - Share ratio: - - - - - - - - Sans Serif - 9 - 50 - false - false - false - false - - - - Total failed: - - - - - - - - - 6 - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Qt::Horizontal - - - - 181 - 20 - - - - - - - - - - - - - - Sans Serif - 9 - 50 - false - false - false - false - - - - Download in correct order (slower but good for previewing) - - - - - - - - Trackers - - - - - - 6 - - - 0 - - - - - - Sans Serif - 9 - 50 - false - false - false - false - - - - Trackers: - - - - - - - 6 - - - 0 - - - - - - 0 - 0 - - - - QAbstractItemView::ExtendedSelection - - - - - - - 6 - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 24 - 24 - - - - - 24 - 24 - - - - - - - - - - - - 24 - 24 - - - - - 24 - 24 - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - 6 - - - 0 - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - 24 - 24 - - - - - 24 - 24 - - - - - - - - - - - - 24 - 24 - - - - - 24 - 24 - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - 6 - - - 0 - - - - - - 16777215 - 16 - - - - - Sans Serif - 9 - 50 - false - false - false - false - - - - Current tracker: - - - - - - - - 16777215 - 16 - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Minimum - - - - 20 - 40 - - - - - - - - - Url seeds - - - - 6 - - - 9 - - - - - - 75 - true - - - - The following url seeds are available for this torrent: - - - - - - - - - - 6 - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 24 - 24 - - - - - - - - - - - - 24 - 24 - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - Torrent content - - - - - - - Sans Serif - 9 - 75 - false - true - false - false - - - - Files contained in current torrent: - - - - - - - - 0 - 301 - - - - Qt::CustomContextMenu - - - QAbstractItemView::AllEditTriggers - - - QAbstractItemView::ExtendedSelection - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Collapse all - - - - - - - Expand all - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - Sans Serif - 8 - 50 - false - false - false - false - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - true - - - - - - - - - - - 6 - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - OK - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Ignored - - - - - Normal - - - - - Maximum - - - - - High - - - - - - - okButton - clicked() - properties - accept() - - - 306 - 556 - - - 96 - 254 - - - - - diff --git a/src/propertiesWidget.ui b/src/propertiesWidget.ui new file mode 100644 index 000000000..77f293cae --- /dev/null +++ b/src/propertiesWidget.ui @@ -0,0 +1,1046 @@ + + + PropertiesWidget + + + + 0 + 0 + 756 + 291 + + + + + 0 + 0 + + + + + 16777215 + 303 + + + + Form + + + + + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 16777215 + 260 + + + + 0 + + + + + + + 0 + + + + + + 8 + 75 + true + + + + Torrent information + + + + 0 + + + + + + + + + + 16777215 + 22 + + + + + 8 + 50 + false + + + + Save path: + + + + + + + + 8 + 50 + false + + + + Creator: + + + + + + + + 8 + 50 + false + + + + Torrent hash: + + + + + + + + 8 + 50 + false + + + + Comment: + + + + + + + + + + + + + + 16777215 + 22 + + + + + 50 + false + + + + + + + + + + + + 22 + 22 + + + + + 50 + false + + + + ... + + + + + + + + + + 50 + false + + + + + + + + + + + + 50 + false + + + + + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + 50 + false + + + + + + + + + + + + + + + Qt::Horizontal + + + + 190 + 20 + + + + + + + + + + + + 0 + 0 + + + + + 0 + 115 + + + + + 8 + 75 + false + true + false + false + + + + Current session + + + + 9 + + + 9 + + + 9 + + + 0 + + + + + 6 + + + 0 + + + + + 6 + + + 0 + + + + + + 50 + false + false + false + false + + + + Total uploaded: + + + + + + + + 50 + false + false + false + false + + + + Total downloaded: + + + + + + + + 50 + false + + + + Share ratio: + + + + + + + + 50 + false + false + false + false + + + + Total failed: + + + + + + + + + 6 + + + 0 + + + + + + 50 + false + + + + + + + + + + + + 50 + false + + + + + + + + + + + + 50 + false + + + + + + + + + + + + 50 + false + + + + + + + + + + + + + Qt::Horizontal + + + + 181 + 20 + + + + + + + + + + + + + + + + 0 + 50 + + + + + 8 + 75 + true + + + + Downloaded pieces + + + + + + + + 8 + 50 + false + false + false + false + + + + Download in correct order (slower but good for previewing) + + + + + + + + + + + 6 + + + 0 + + + + + 6 + + + 0 + + + + + + 0 + 0 + + + + QAbstractItemView::ExtendedSelection + + + + + + + 6 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + + + + + :/Icons/oxygen/list-remove.png:/Icons/oxygen/list-remove.png + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + + + + + :/Icons/oxygen/list-add.png:/Icons/oxygen/list-add.png + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + 6 + + + 0 + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + + + + + :/Icons/uparrow.png:/Icons/uparrow.png + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + + + + + :/Icons/downarrow.png:/Icons/downarrow.png + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + 6 + + + 0 + + + + + + 16777215 + 16 + + + + + 8 + 50 + false + false + false + false + + + + Current tracker: + + + + + + + + 16777215 + 16 + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + + 6 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 24 + 24 + + + + + + + + :/Icons/oxygen/list-remove.png:/Icons/oxygen/list-remove.png + + + + + + + + 24 + 24 + + + + + + + + :/Icons/oxygen/list-add.png:/Icons/oxygen/list-add.png + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + Qt::CustomContextMenu + + + QAbstractItemView::AllEditTriggers + + + QAbstractItemView::ExtendedSelection + + + false + + + true + + + false + + + true + + + false + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Collapse all + + + + + + + Expand all + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + Qt::Horizontal + + + + + + + 5 + + + 4 + + + 5 + + + + + QPushButton { +border: 1px solid rgb(85, 81, 91); +border-radius: 3px; +padding: 2px; +margin-left: 3px; margin-right: 3px; +} + + + General + + + + :/Icons/oxygen/help-about.png:/Icons/oxygen/help-about.png + + + + 16 + 16 + + + + + + + + QPushButton { +border: 1px solid rgb(85, 81, 91); +border-radius: 3px; +padding: 2px; +margin-left: 3px; margin-right: 3px; +} + + + Trackers + + + + :/Icons/oxygen/network-server.png:/Icons/oxygen/network-server.png + + + + 16 + 16 + + + + + + + + QPushButton { +border: 1px solid rgb(85, 81, 91); +border-radius: 3px; +padding: 2px; +margin-left: 3px; margin-right: 3px; +} + + + URL seeds + + + + :/Icons/oxygen/urlseed.png:/Icons/oxygen/urlseed.png + + + + 16 + 16 + + + + + + + + QPushButton { +border: 1px solid rgb(85, 81, 91); +border-radius: 3px; +padding: 2px; +margin-left: 3px; margin-right: 3px; +} + + + Files + + + + :/Icons/oxygen/folder.png:/Icons/oxygen/folder.png + + + + 16 + 16 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + diff --git a/src/properties_imp.h b/src/properties_imp.h deleted file mode 100644 index 53121d4f0..000000000 --- a/src/properties_imp.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Bittorrent Client using Qt4 and libtorrent. - * Copyright (C) 2006 Christophe Dumez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * In addition, as a special exception, the copyright holders give permission to - * link this program with the OpenSSL project's "OpenSSL" library (or with - * modified versions of it that use the same license as the "OpenSSL" library), - * and distribute the linked executables. You must obey the GNU General Public - * License in all respects for all of the code used other than "OpenSSL". If you - * modify file(s), you may extend this exception to your version of the file(s), - * but you are not obligated to do so. If you do not wish to do so, delete this - * exception statement from your version. - * - * Contact : chris@qbittorrent.org - */ - -#ifndef PROPERTIES_H -#define PROPERTIES_H - -#include "ui_properties.h" -#include "qtorrenthandle.h" - -class PropListDelegate; -class QTimer; -class bittorrent; -class QStandardItemModel; -class torrent_file; -class QStandardItem; -class RealProgressBar; -class RealProgressBarThread; - -using namespace libtorrent; - -class properties : public QDialog, private Ui::properties{ - Q_OBJECT - private: - QTorrentHandle h; - bittorrent *BTSession; - bool changedFilteredfiles; - QString hash; - PropListDelegate *PropDelegate; - QStandardItemModel *PropListModel; - QTimer *updateInfosTimer; - QStringList urlSeeds; - RealProgressBar *progressBar; - RealProgressBarThread *progressBarUpdater; - QVBoxLayout *progressBarVbox; - - protected slots: - void on_okButton_clicked(); - void on_incrementalDownload_stateChanged(int); - void setItemColor(QModelIndex index, QString color); - void updateInfos(); - void askForTracker(); - void loadTrackers(); - void deleteSelectedTrackers(); - void lowerSelectedTracker(); - void riseSelectedTracker(); - void displayFilesListMenu(const QPoint& pos); - void ignoreSelection(); - void normalSelection(); - void highSelection(); - void maximumSelection(); - void loadWebSeeds(); - void askWebSeed(); - void loadWebSeedsFromFile(); - void deleteSelectedUrlSeeds(); - void addFilesToTree(const torrent_file *root, QStandardItem *parent); - void updateChildrenPriority(QStandardItem *item, int priority); - void updateParentsPriority(QStandardItem *item, int priority); - void updatePriorities(QStandardItem *item); - void getPriorities(QStandardItem *parent, int *priorities); - void addTrackerList(QStringList myTrackers); - void writeSettings(); - void loadSettings(); - void on_changeSavePathButton_clicked(); - - signals: - void filteredFilesChanged(QString hash); - void fileSizeChanged(QString hash); - void trackersChanged(QString hash); - - public: - // Constructor - properties(QWidget *parent, bittorrent *BTSession, QTorrentHandle &h); - ~properties(); - bool allFiltered() const; - bool savePiecesPriorities(); - std::vector loadFilesPriorities(); - - protected: - QPoint screenCenter() const; -}; - -#endif diff --git a/src/properties_imp.cpp b/src/propertieswidget.cpp similarity index 65% rename from src/properties_imp.cpp rename to src/propertieswidget.cpp index efe99c0ae..7e4849f01 100644 --- a/src/properties_imp.cpp +++ b/src/propertieswidget.cpp @@ -28,38 +28,42 @@ * Contact : chris@qbittorrent.org */ -#include "properties_imp.h" -#include "misc.h" -#include "PropListDelegate.h" -#include "bittorrent.h" -#include "arborescence.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "propertieswidget.h" +#include "TransferListWidget.h" +#include "torrentPersistentData.h" #include "realprogressbar.h" #include "realprogressbarthread.h" +#include "arborescence.h" +#include "bittorrent.h" +#include "PropListDelegate.h" #include "TrackersAdditionDlg.h" -#include "torrentPersistentData.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include +#define DEFAULT_BUTTON_CSS "QPushButton {border: 1px solid rgb(85, 81, 91);border-radius: 3px;padding: 2px; margin-left: 3px; margin-right: 3px;}" +#define SELECTED_BUTTON_CSS "QPushButton {border: 1px solid rgb(85, 81, 91);border-radius: 3px;padding: 2px;background-color: rgb(255, 208, 105);margin-left: 3px; margin-right: 3px;}" -// Constructor -properties::properties(QWidget *parent, bittorrent *BTSession, QTorrentHandle &h): QDialog(parent), h(h), BTSession(BTSession), changedFilteredfiles(false), hash(h.hash()) { +PropertiesWidget::PropertiesWidget(QWidget *parent, TransferListWidget *transferList, bittorrent* BTSession): QWidget(parent), transferList(transferList), BTSession(BTSession) { setupUi(this); - lbl_priorities->setText(tr("Priorities:")+"
  • "+tr("Ignored: file is not downloaded at all")+"
  • "+tr("Normal: normal priority. Download order is dependent on availability")+"
  • "+tr("High: higher than normal priority. Pieces are preferred over pieces with the same availability, but not over pieces with lower availability")+"
  • "+tr("Maximum: maximum priority, availability is disregarded, the piece is preferred over any other piece with lower priority")+"
"); - // set icons - addTracker_button->setIcon(QIcon(QString::fromUtf8(":/Icons/oxygen/list-add.png"))); - removeTracker_button->setIcon(QIcon(QString::fromUtf8(":/Icons/oxygen/list-remove.png"))); - lowerTracker_button->setIcon(QIcon(QString::fromUtf8(":/Icons/downarrow.png"))); - riseTracker_button->setIcon(QIcon(QString::fromUtf8(":/Icons/uparrow.png"))); - addWS_button->setIcon(QIcon(QString::fromUtf8(":/Icons/oxygen/list-add.png"))); - deleteWS_button->setIcon(QIcon(QString::fromUtf8(":/Icons/oxygen/list-remove.png"))); - setAttribute(Qt::WA_DeleteOnClose); + state = VISIBLE; + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + if(!settings.value("TorrentProperties/Visible", false).toBool()) { + reduce(); + } else { + main_infos_button->setStyleSheet(SELECTED_BUTTON_CSS); + setEnabled(false); + } + // Set Properties list model PropListModel = new QStandardItemModel(0,5); PropListModel->setHeaderData(NAME, Qt::Horizontal, tr("File name")); @@ -68,8 +72,16 @@ properties::properties(QWidget *parent, bittorrent *BTSession, QTorrentHandle &h PropListModel->setHeaderData(PRIORITY, Qt::Horizontal, tr("Priority")); filesList->setModel(PropListModel); filesList->hideColumn(INDEX); - PropDelegate = new PropListDelegate(0, &changedFilteredfiles); + PropDelegate = new PropListDelegate(0); filesList->setItemDelegate(PropDelegate); + + // QActions + actionIgnored = new QAction(this); + actionNormal = new QAction(this); + actionMaximum = new QAction(this); + actionHigh = new QAction(this); + + // SIGNAL/SLOTS connect(filesList, SIGNAL(clicked(const QModelIndex&)), filesList, SLOT(edit(const QModelIndex&))); connect(collapseAllButton, SIGNAL(clicked()), filesList, SLOT(collapseAll())); connect(expandAllButton, SIGNAL(clicked()), filesList, SLOT(expandAll())); @@ -84,127 +96,132 @@ properties::properties(QWidget *parent, bittorrent *BTSession, QTorrentHandle &h connect(actionMaximum, SIGNAL(triggered()), this, SLOT(maximumSelection())); connect(addWS_button, SIGNAL(clicked()), this, SLOT(askWebSeed())); connect(deleteWS_button, SIGNAL(clicked()), this, SLOT(deleteSelectedUrlSeeds())); - // get Infos from torrent handle - fileName->setText(h.name()); - // Torrent Infos - save_path->setText(TorrentPersistentData::getSavePath(hash)); - QString author = h.creator().trimmed(); - if(author.isEmpty()) - author = tr("Unknown"); - creator->setText(author); - hash_lbl->setText(hash); - comment_txt->setText(h.comment()); - //Trackers - loadTrackers(); - // Session infos - failed->setText(misc::friendlyUnit(h.total_failed_bytes())); - upTotal->setText(misc::friendlyUnit(h.total_payload_upload())); - dlTotal->setText(misc::friendlyUnit(h.total_payload_download())); - // Update ratio info - float ratio; - if(h.total_payload_download() == 0){ - if(h.total_payload_upload() == 0) - ratio = 1.; - else - ratio = 10.; // Max ratio - }else{ - ratio = (double)h.total_payload_upload()/(double)h.total_payload_download(); - if(ratio > 10.){ - ratio = 10.; - } - } - shareRatio->setText(QString(QByteArray::number(ratio, 'f', 1))); - std::vector fp; - h.file_progress(fp); - std::vector files_priority = loadFilesPriorities(); - // List files in torrent - h.get_torrent_info(); - arborescence *arb = new arborescence(h.get_torrent_info(), fp, files_priority); - addFilesToTree(arb->getRoot(), PropListModel->invisibleRootItem()); - delete arb; + connect(transferList, SIGNAL(currentTorrentChanged(QTorrentHandle&)), this, SLOT(loadTorrentInfos(QTorrentHandle &))); + connect(incrementalDownload, SIGNAL(stateChanged(int)), this, SLOT(setIncrementalDownload(int))); connect(PropListModel, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(updatePriorities(QStandardItem*))); - filesList->expandAll(); - // List web seeds - loadWebSeedsFromFile(); - loadWebSeeds(); - // Incremental download - incrementalDownload->setChecked(TorrentPersistentData::isSequentialDownload(hash)); - updateInfosTimer = new QTimer(this); - connect(updateInfosTimer, SIGNAL(timeout()), this, SLOT(updateInfos())); - updateInfosTimer->start(3000); + connect(PropDelegate, SIGNAL(filteredFilesChanged()), this, SLOT(filteredFilesChanged())); + + // Downloaded pieces progress bar progressBar = new RealProgressBar(this); progressBar->setForegroundColor(Qt::blue); progressBarVbox = new QVBoxLayout(RealProgressBox); progressBarVbox->addWidget(progressBar); - progressBarUpdater = new RealProgressBarThread(progressBar, h); - progressBarUpdater->start(); - // progressBarUpdater->refresh(); - connect(updateInfosTimer, SIGNAL(timeout()), progressBarUpdater, SLOT(refresh())); - loadSettings(); -} - -properties::~properties(){ - writeSettings(); - qDebug("Properties destroyed"); - delete updateInfosTimer; - delete PropDelegate; - delete PropListModel; - delete progressBarUpdater; + // Pointers init + progressBarUpdater = 0; + arb = 0; + // Dynamic data refresher + refreshTimer = new QTimer(this); + connect(refreshTimer, SIGNAL(timeout()), this, SLOT(loadDynamicData())); + refreshTimer->start(10000); // 10sec +} + +PropertiesWidget::~PropertiesWidget() { + saveSettings(); + delete refreshTimer; + if(progressBarUpdater) + delete progressBarUpdater; delete progressBar; delete progressBarVbox; + delete PropListModel; + if(arb) + delete arb; + // Delete QActions + delete actionIgnored; + delete actionNormal; + delete actionMaximum; + delete actionHigh; } -void properties::addFilesToTree(const torrent_file *root, QStandardItem *parent) { - QList child; - // Name - QStandardItem *first; - if(root->isDir()) { - first = new QStandardItem(QIcon(":/Icons/oxygen/folder.png"), root->name()); - } else { - first = new QStandardItem(QIcon(":/Icons/oxygen/file.png"), root->name()); - } - child << first; - // Size - child << new QStandardItem(misc::toQString(root->getSize())); - // Progress - child << new QStandardItem(misc::toQString(root->getProgress())); - // Prio - child << new QStandardItem(misc::toQString(root->getPriority())); - // INDEX - child << new QStandardItem(misc::toQString(root->getIndex())); - // Add the child to the tree - parent->appendRow(child); - // Set row color - if(root->getPriority() == IGNORED) - setItemColor(first->index(), "red"); - else - setItemColor(first->index(), "green"); - // Add childs - foreach(const torrent_file *childFile, root->getChildren()) { - addFilesToTree(childFile, first); +void PropertiesWidget::reduce() { + if(state == VISIBLE) { + stackedProperties->setFixedHeight(0); + state = REDUCED; } } -void properties::writeSettings() { - QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - settings.beginGroup(QString::fromUtf8("PropWindow")); - settings.setValue(QString::fromUtf8("size"), size()); - settings.setValue(QString::fromUtf8("pos"), pos()); - QVariantList contentColsWidths; - for(int i=0; icolumnCount()-1; ++i) { - contentColsWidths.append(filesList->columnWidth(i)); +void PropertiesWidget::slide() { + if(state == REDUCED) { + stackedProperties->setFixedHeight(260); + state = VISIBLE; } - settings.setValue(QString::fromUtf8("contentColsWidths"), contentColsWidths); - settings.endGroup(); } -void properties::loadSettings() { +void PropertiesWidget::clear() { + save_path->clear(); + creator->clear(); + hash_lbl->clear(); + comment_lbl->clear(); + incrementalDownload->setChecked(false); + trackersURLS->clear(); + trackerURL->clear(); + progressBar->setProgress(QRealArray()); + failed->clear(); + upTotal->clear(); + dlTotal->clear(); + shareRatio->clear(); + listWebSeeds->clear(); + PropListModel->removeRows(0, PropListModel->rowCount()); + setEnabled(false); +} + +void PropertiesWidget::loadTorrentInfos(QTorrentHandle &_h) { + h = _h; + if(!h.is_valid()) { + clear(); + return; + } + setEnabled(true); + if(progressBarUpdater) { + delete progressBarUpdater; + progressBarUpdater = 0; + } + if(arb != 0) { + delete arb; + arb = 0; + } + try { + // Save path + save_path->setText(TorrentPersistentData::getSavePath(h.hash())); + // Author + QString author = h.creator().trimmed(); + if(author.isEmpty()) + author = tr("Unknown"); + creator->setText(author); + // Hash + hash_lbl->setText(h.hash()); + // Comment + comment_lbl->setText(h.comment()); + // Sequential download + incrementalDownload->setChecked(TorrentPersistentData::isSequentialDownload(h.hash())); + // Trackers + loadTrackers(); + // URL seeds + loadUrlSeeds(); + // downloaded pieces updater + progressBarUpdater = new RealProgressBarThread(progressBar, h); + progressBarUpdater->start(); + // Create arborescence (Tree representation of files in the torrent) + std::vector fp; + h.file_progress(fp); + std::vector files_priority = loadFilesPriorities(); + // List files in torrent + arborescence *arb = new arborescence(h.get_torrent_info(), fp, files_priority); + PropListModel->removeRows(0, PropListModel->rowCount()); + addFilesToTree(arb->getRoot(), PropListModel->invisibleRootItem()); + // Increase first column width + //filesList->resizeColumnToContents(0); // does not work + } catch(invalid_handle e) { + + } + // Load dynamic data + loadDynamicData(); +} + +void PropertiesWidget::readSettings() { QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - resize(settings.value(QString::fromUtf8("PropWindow/size"), size()).toSize()); - move(settings.value(QString::fromUtf8("PropWindow/pos"), screenCenter()).toPoint()); - QVariantList contentColsWidths = settings.value(QString::fromUtf8("PropWindow/contentColsWidths"), QVariantList()).toList(); + QVariantList contentColsWidths = settings.value(QString::fromUtf8("TorrentProperties/filesColsWidth"), QVariantList()).toList(); if(contentColsWidths.empty()) { - filesList->header()->resizeSection(NAME, 200); + filesList->header()->resizeSection(0, filesList->width()/2.); } else { for(int i=0; isetColumnWidth(i, contentColsWidths.at(i).toInt()); @@ -212,24 +229,165 @@ void properties::loadSettings() { } } -// Center window -QPoint properties::screenCenter() const{ - int scrn = 0; - QWidget *w = this->topLevelWidget(); +void PropertiesWidget::saveSettings() { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + settings.setValue("TorrentProperties/Visible", state==VISIBLE); + QVariantList contentColsWidths; + for(int i=0; icolumnCount()-1; ++i) { + contentColsWidths.append(filesList->columnWidth(i)); + } + settings.setValue(QString::fromUtf8("TorrentProperties/filesColsWidth"), contentColsWidths); +} - if(w) - scrn = QApplication::desktop()->screenNumber(w); - else if(QApplication::desktop()->isVirtualDesktop()) - scrn = QApplication::desktop()->screenNumber(QCursor::pos()); - else - scrn = QApplication::desktop()->screenNumber(this); +void PropertiesWidget::loadDynamicData() { + if(!h.is_valid()) return; + try { + // Session infos + failed->setText(misc::friendlyUnit(h.total_failed_bytes())); + upTotal->setText(misc::friendlyUnit(h.total_payload_upload())); + dlTotal->setText(misc::friendlyUnit(h.total_payload_download())); + // Update ratio info + float ratio; + if(h.total_payload_download() == 0){ + if(h.total_payload_upload() == 0) + ratio = 1.; + else + ratio = 10.; // Max ratio + }else{ + ratio = (double)h.total_payload_upload()/(double)h.total_payload_download(); + if(ratio > 10.){ + ratio = 10.; + } + } + shareRatio->setText(QString(QByteArray::number(ratio, 'f', 1))); + // Downloaded pieces + if(progressBarUpdater) + progressBarUpdater->refresh(); + } catch(invalid_handle e) {} +} - QRect desk(QApplication::desktop()->availableGeometry(scrn)); - return QPoint((desk.width() - this->frameGeometry().width()) / 2, (desk.height() - this->frameGeometry().height()) / 2); +void PropertiesWidget::setIncrementalDownload(int checkboxState) { + if(!h.is_valid()) return; + h.set_sequential_download(checkboxState == Qt::Checked); + TorrentPersistentData::saveSequentialStatus(h); +} + +void PropertiesWidget::loadTrackers() { + if(!h.is_valid()) return; + //Trackers + std::vector trackers = h.trackers(); + trackersURLS->clear(); + QHash errors = BTSession->getTrackersErrors(h.hash()); + unsigned int nbTrackers = trackers.size(); + for(unsigned int i=0; isetForeground(QBrush(QColor("red"))); + // Set tooltip + QString msg=""; + unsigned int i=0; + foreach(QString word, errors[current_tracker].split(" ")) { + if(i > 0 && i%5!=1) msg += " "; + msg += word; + if(i> 0 && i%5==0) msg += "\n"; + ++i; + } + item->setToolTip(msg); + } else { + item->setForeground(QBrush(QColor("green"))); + } + } + QString tracker = h.current_tracker().trimmed(); + if(!tracker.isEmpty()){ + trackerURL->setText(tracker); + }else{ + trackerURL->setText(tr("None - Unreachable?")); + } +} + +void PropertiesWidget::loadUrlSeeds(){ + QStringList already_added; + listWebSeeds->clear(); + QVariantList url_seeds = TorrentPersistentData::getUrlSeeds(h.hash()); + foreach(const QVariant &var_url_seed, url_seeds){ + QString url_seed = var_url_seed.toString(); + if(!url_seed.isEmpty()) { + new QListWidgetItem(url_seed, listWebSeeds); + already_added << url_seed; + } + } + // Load the hard-coded url seeds + QStringList hc_seeds = h.url_seeds(); + // Add hard coded url seeds + foreach(const QString &hc_seed, hc_seeds){ + if(!already_added.contains(hc_seed)){ + new QListWidgetItem(hc_seed, listWebSeeds); + } + } +} + +/* Tab buttons */ +QPushButton* PropertiesWidget::getButtonFromIndex(int index) { + switch(index) { + case TRACKERS_TAB: + return trackers_button; + case URLSEEDS_TAB: + return url_seeds_button; + case FILES_TAB: + return files_button; + default: + return main_infos_button; + } +} + +void PropertiesWidget::on_main_infos_button_clicked() { + if(state == VISIBLE && stackedProperties->currentIndex() == MAIN_TAB) { + reduce(); + } else { + slide(); + getButtonFromIndex(stackedProperties->currentIndex())->setStyleSheet(DEFAULT_BUTTON_CSS); + stackedProperties->setCurrentIndex(MAIN_TAB); + main_infos_button->setStyleSheet(SELECTED_BUTTON_CSS); + } +} + +void PropertiesWidget::on_trackers_button_clicked() { + if(state == VISIBLE && stackedProperties->currentIndex() == TRACKERS_TAB) { + reduce(); + } else { + slide(); + getButtonFromIndex(stackedProperties->currentIndex())->setStyleSheet(DEFAULT_BUTTON_CSS); + stackedProperties->setCurrentIndex(TRACKERS_TAB); + trackers_button->setStyleSheet(SELECTED_BUTTON_CSS); + } +} + +void PropertiesWidget::on_url_seeds_button_clicked() { + if(state == VISIBLE && stackedProperties->currentIndex() == URLSEEDS_TAB) { + reduce(); + } else { + slide(); + getButtonFromIndex(stackedProperties->currentIndex())->setStyleSheet(DEFAULT_BUTTON_CSS); + stackedProperties->setCurrentIndex(URLSEEDS_TAB); + url_seeds_button->setStyleSheet(SELECTED_BUTTON_CSS); + } +} + +void PropertiesWidget::on_files_button_clicked() { + if(state == VISIBLE && stackedProperties->currentIndex() == FILES_TAB) { + reduce(); + } else { + slide(); + getButtonFromIndex(stackedProperties->currentIndex())->setStyleSheet(DEFAULT_BUTTON_CSS); + stackedProperties->setCurrentIndex(FILES_TAB); + files_button->setStyleSheet(SELECTED_BUTTON_CSS); + } } // priority is the new priority of given item -void properties::updateParentsPriority(QStandardItem *item, int priority) { +void PropertiesWidget::updateParentsPriority(QStandardItem *item, int priority) { QStandardItem *parent = item->parent(); if(!parent) return; // Check if children have different priorities @@ -269,7 +427,7 @@ void properties::updateParentsPriority(QStandardItem *item, int priority) { } } -void properties::updateChildrenPriority(QStandardItem *item, int priority) { +void PropertiesWidget::updateChildrenPriority(QStandardItem *item, int priority) { QStandardItem *parent = item->parent(); if(!parent) { parent = PropListModel->invisibleRootItem(); @@ -290,7 +448,7 @@ void properties::updateChildrenPriority(QStandardItem *item, int priority) { } } -void properties::updatePriorities(QStandardItem *item) { +void PropertiesWidget::updatePriorities(QStandardItem *item) { qDebug("Priority changed"); // First we disable the signal/slot on item edition // temporarily so that it doesn't mess with our manual updates @@ -318,19 +476,9 @@ void properties::updatePriorities(QStandardItem *item) { connect(PropListModel, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(updatePriorities(QStandardItem*))); } -void properties::loadWebSeeds(){ - // Clear url seeds list - listWebSeeds->clear(); - // Add manually added url seeds - foreach(const QString &url_seed, urlSeeds){ - listWebSeeds->addItem(url_seed); - qDebug("Added custom url seed to list: %s", url_seed.toLocal8Bit().data()); - } -} - -std::vector properties::loadFilesPriorities(){ +std::vector PropertiesWidget::loadFilesPriorities(){ std::vector fp; - QVariantList files_priority = TorrentPersistentData::getFilesPriority(hash); + QVariantList files_priority = TorrentPersistentData::getFilesPriority(h.hash()); if(files_priority.empty()) { for(int i=0; i properties::loadFilesPriorities(){ return fp; } -bool properties::allFiltered() const { +bool PropertiesWidget::allFiltered() const { unsigned int nbRows = PropListModel->rowCount(); for(unsigned int i=0; idata(PropListModel->index(i, PRIORITY)).toInt() != IGNORED) @@ -358,7 +506,7 @@ bool properties::allFiltered() const { } -void properties::getPriorities(QStandardItem *parent, int *priorities) { +void PropertiesWidget::getPriorities(QStandardItem *parent, int *priorities) { qDebug("In getPriorities"); unsigned int nbRows = parent->rowCount(); for(unsigned int i=0; iselectionModel()->selectedIndexes(); foreach(const QModelIndex &index, selectedIndexes){ if(index.column() == PRIORITY){ if(PropListModel->data(index) != QVariant(IGNORED)){ PropListModel->setData(index, QVariant(IGNORED)); - changedFilteredfiles = true; + filteredFilesChanged(); setItemColor(index, "red"); } } } } -void properties::normalSelection(){ +void PropertiesWidget::normalSelection(){ QModelIndexList selectedIndexes = filesList->selectionModel()->selectedIndexes(); foreach(const QModelIndex &index, selectedIndexes){ if(index.column() == PRIORITY){ if(PropListModel->data(index) != QVariant(NORMAL)){ PropListModel->setData(index, QVariant(NORMAL)); - changedFilteredfiles = true; + filteredFilesChanged(); setItemColor(index, "green"); } } } } -void properties::highSelection(){ +void PropertiesWidget::highSelection(){ QModelIndexList selectedIndexes = filesList->selectionModel()->selectedIndexes(); foreach(const QModelIndex &index, selectedIndexes){ if(index.column() == PRIORITY){ if(PropListModel->data(index) != QVariant(HIGH)){ PropListModel->setData(index, QVariant(HIGH)); - changedFilteredfiles = true; + filteredFilesChanged(); setItemColor(index, "green"); } } } } -void properties::maximumSelection(){ +void PropertiesWidget::maximumSelection(){ QModelIndexList selectedIndexes = filesList->selectionModel()->selectedIndexes(); foreach(const QModelIndex &index, selectedIndexes){ if(index.column() == PRIORITY){ if(PropListModel->data(index) != QVariant(MAXIMUM)){ PropListModel->setData(index, QVariant(MAXIMUM)); - changedFilteredfiles = true; + filteredFilesChanged(); setItemColor(index, "green"); } } } } -void properties::loadTrackers(){ - //Trackers - std::vector trackers = h.trackers(); - trackersURLS->clear(); - QHash errors = BTSession->getTrackersErrors(h.hash()); - unsigned int nbTrackers = trackers.size(); - for(unsigned int i=0; isetForeground(QBrush(QColor("red"))); - // Set tooltip - QString msg=""; - unsigned int i=0; - foreach(QString word, errors[current_tracker].split(" ")) { - if(i > 0 && i%5!=1) msg += " "; - msg += word; - if(i> 0 && i%5==0) msg += "\n"; - ++i; - } - item->setToolTip(msg); - } else { - item->setForeground(QBrush(QColor("green"))); - } - } - QString tracker = h.current_tracker().trimmed(); - if(!tracker.isEmpty()){ - trackerURL->setText(tracker); - }else{ - trackerURL->setText(tr("None - Unreachable?")); - } -} - -void properties::askWebSeed(){ +void PropertiesWidget::askWebSeed(){ bool ok; // Ask user for a new url seed QString url_seed = QInputDialog::getText(this, tr("New url seed", "New HTTP source"), @@ -483,28 +597,27 @@ void properties::askWebSeed(){ QString::fromUtf8("http://www."), &ok); if(!ok) return; qDebug("Adding %s web seed", url_seed.toLocal8Bit().data()); - if(urlSeeds.indexOf(url_seed) != -1) { + if(!listWebSeeds->findItems(url_seed, Qt::MatchFixedString).empty()) { QMessageBox::warning(this, tr("qBittorrent"), tr("This url seed is already in the list."), QMessageBox::Ok); return; } - urlSeeds << url_seed; h.add_url_seed(url_seed); TorrentPersistentData::saveUrlSeeds(h); // Refresh the seeds list - loadWebSeeds(); + loadUrlSeeds(); } // Ask the user for a new tracker // and add it to the download list // if it is not already in it -void properties::askForTracker(){ +void PropertiesWidget::askForTracker(){ TrackersAddDlg *dlg = new TrackersAddDlg(this); connect(dlg, SIGNAL(TrackersToAdd(QStringList)), this, SLOT(addTrackerList(QStringList))); } -void properties::addTrackerList(QStringList myTrackers) { +void PropertiesWidget::addTrackerList(QStringList myTrackers) { // Add the trackers to the list std::vector trackers = h.trackers(); foreach(const QString& tracker, myTrackers) { @@ -517,17 +630,14 @@ void properties::addTrackerList(QStringList myTrackers) { h.force_reannounce(); // Reload Trackers loadTrackers(); - emit trackersChanged(h.hash()); + BTSession->saveTrackerFile(h.hash()); } -void properties::deleteSelectedUrlSeeds(){ +void PropertiesWidget::deleteSelectedUrlSeeds(){ QList selectedItems = listWebSeeds->selectedItems(); bool change = false; foreach(QListWidgetItem *item, selectedItems){ QString url_seed = item->text(); - int index = urlSeeds.indexOf(url_seed); - Q_ASSERT(index != -1); - urlSeeds.removeAt(index); h.remove_url_seed(url_seed); change = true; } @@ -535,11 +645,11 @@ void properties::deleteSelectedUrlSeeds(){ // Save them to disk TorrentPersistentData::saveUrlSeeds(h); // Refresh list - loadWebSeeds(); + loadUrlSeeds(); } } -void properties::deleteSelectedTrackers(){ +void PropertiesWidget::deleteSelectedTrackers(){ QList selectedItems = trackersURLS->selectedItems(); if(!selectedItems.size()) return; std::vector trackers = h.trackers(); @@ -563,10 +673,10 @@ void properties::deleteSelectedTrackers(){ h.force_reannounce(); // Reload Trackers loadTrackers(); - emit trackersChanged(h.hash()); + BTSession->saveTrackerFile(h.hash()); } -void properties::riseSelectedTracker(){ +void PropertiesWidget::riseSelectedTracker(){ unsigned int i = 0; std::vector trackers = h.trackers(); QList selectedItems = trackersURLS->selectedItems(); @@ -595,11 +705,11 @@ void properties::riseSelectedTracker(){ // Reload Trackers loadTrackers(); trackersURLS->item(i-1)->setSelected(true); - emit trackersChanged(h.hash()); + BTSession->saveTrackerFile(h.hash()); } } -void properties::lowerSelectedTracker(){ +void PropertiesWidget::lowerSelectedTracker(){ unsigned int i = 0; std::vector trackers = h.trackers(); QList selectedItems = trackersURLS->selectedItems(); @@ -628,47 +738,37 @@ void properties::lowerSelectedTracker(){ // Reload Trackers loadTrackers(); trackersURLS->item(i+1)->setSelected(true); - emit trackersChanged(h.hash()); + BTSession->saveTrackerFile(h.hash()); } } -void properties::updateInfos(){ - // Update current tracker - try { - QString tracker = h.current_tracker().trimmed(); - if(!tracker.isEmpty()){ - trackerURL->setText(tracker); - }else{ - trackerURL->setText(tr("None - Unreachable?")); - } - // XXX: This causes selection problems - //loadTrackers(); - }catch(invalid_handle e){ - // torrent was removed, closing properties - close(); - } -} - -void properties::setItemColor(QModelIndex index, QString color){ +void PropertiesWidget::setItemColor(QModelIndex index, QString color){ for(int i=0; icolumnCount(); ++i){ PropListModel->setData(index.sibling(index.row(), i), QVariant(QColor(color)), Qt::ForegroundRole); } } -void properties::on_incrementalDownload_stateChanged(int state){ - qDebug("Incremental download toggled"); - if(state == Qt::Checked){ - if(!TorrentPersistentData::isSequentialDownload(hash)) { - h.set_sequential_download(true); - TorrentPersistentData::saveSequentialStatus(h); - } - }else{ - h.set_sequential_download(false); - TorrentPersistentData::saveSequentialStatus(h); +bool PropertiesWidget::savePiecesPriorities() { + /*if(!changedFilteredfiles) return true; + if(allFiltered()) { + QMessageBox::warning(0, tr("Priorities error"), tr("Error, you can't filter all the files in a torrent.")); + return false; + }*/ + qDebug("Saving pieces priorities"); + int *priorities = new int[h.get_torrent_info().num_files()]; + getPriorities(PropListModel->invisibleRootItem(), priorities); + unsigned int nbFiles = h.get_torrent_info().num_files(); + for(unsigned int i=0; iuseTemporaryFolder() || h.is_seed()) h.move_storage(savePath.path()); @@ -695,45 +795,40 @@ void properties::on_changeSavePathButton_clicked() { } } -void properties::on_okButton_clicked(){ - if(savePiecesPriorities()) - close(); -} - -void properties::loadWebSeedsFromFile(){ - urlSeeds.clear(); - QVariantList url_seeds = TorrentPersistentData::getUrlSeeds(hash); - foreach(const QVariant &var_url_seed, url_seeds){ - QString url_seed = var_url_seed.toString(); - if(!url_seed.isEmpty()) - urlSeeds << url_seed; - } - // Load the hard-coded url seeds - QStringList hc_seeds = h.url_seeds(); - // Add hard coded url seeds - foreach(const QString &hc_seed, hc_seeds){ - if(urlSeeds.indexOf(hc_seed) == -1){ - urlSeeds << hc_seed; - } +void PropertiesWidget::filteredFilesChanged() { + if(h.is_valid()) { + savePiecesPriorities(); + transferList->updateTorrentSizeAndProgress(h.hash()); } } -bool properties::savePiecesPriorities() { - if(!changedFilteredfiles) return true; - if(allFiltered()) { - QMessageBox::warning(0, tr("Priorities error"), tr("Error, you can't filter all the files in a torrent.")); - return false; +void PropertiesWidget::addFilesToTree(torrent_file *root, QStandardItem *parent) { + QList child; + // Name + QStandardItem *first; + if(root->isDir()) { + first = new QStandardItem(QIcon(":/Icons/oxygen/folder.png"), root->name()); + } else { + first = new QStandardItem(QIcon(":/Icons/oxygen/file.png"), root->name()); } - qDebug("Saving pieces priorities"); - int *priorities = new int[h.get_torrent_info().num_files()]; - getPriorities(PropListModel->invisibleRootItem(), priorities); - unsigned int nbFiles = h.get_torrent_info().num_files(); - for(unsigned int i=0; igetSize())); + // Progress + child << new QStandardItem(misc::toQString(root->getProgress())); + // Prio + child << new QStandardItem(misc::toQString(root->getPriority())); + // INDEX + child << new QStandardItem(misc::toQString(root->getIndex())); + // Add the child to the tree + parent->appendRow(child); + // Set row color + if(root->getPriority() == IGNORED) + setItemColor(first->index(), "red"); + else + setItemColor(first->index(), "green"); + // Add childs + foreach(torrent_file *childFile, root->getChildren()) { + addFilesToTree(childFile, first); } - delete[] priorities; - TorrentPersistentData::saveFilesPriority(h); - // Emit a signal so that the GUI updates the size - emit filteredFilesChanged(hash); - return true; } diff --git a/src/propertieswidget.h b/src/propertieswidget.h new file mode 100644 index 000000000..adb44dde1 --- /dev/null +++ b/src/propertieswidget.h @@ -0,0 +1,123 @@ +/* + * Bittorrent Client using Qt4 and libtorrent. + * Copyright (C) 2006 Christophe Dumez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + * + * Contact : chris@qbittorrent.org + */ + +#ifndef PROPERTIESWIDGET_H +#define PROPERTIESWIDGET_H + +#include +#include "ui_propertiesWidget.h" +#include "qtorrenthandle.h" + +class TransferListWidget; +class QTimer; +class RealProgressBar; +class QVBoxLayout; +class RealProgressBarThread; +class bittorrent; +class arborescence; +class QStandardItemModel; +class PropListDelegate; +class QStandardItem; +class QAction; +class torrent_file; + +enum Tab {MAIN_TAB, TRACKERS_TAB, URLSEEDS_TAB, FILES_TAB}; +enum SlideState {REDUCED, VISIBLE}; + +class PropertiesWidget : public QWidget, private Ui::PropertiesWidget { + Q_OBJECT + +private: + TransferListWidget *transferList; + QTorrentHandle h; + QTimer *refreshTimer; + RealProgressBar *progressBar; + RealProgressBarThread *progressBarUpdater; + QVBoxLayout *progressBarVbox; + bittorrent* BTSession; + SlideState state; + arborescence *arb; + QStandardItemModel *PropListModel; + PropListDelegate *PropDelegate; + QAction *actionIgnored; + QAction *actionNormal; + QAction *actionMaximum; + QAction *actionHigh; + +protected: + QPushButton* getButtonFromIndex(int index); + std::vector loadFilesPriorities(); + bool allFiltered() const; + bool savePiecesPriorities(); + +protected slots: + void loadTorrentInfos(QTorrentHandle &h); + void loadDynamicData(); + void setIncrementalDownload(int checkboxState); + void loadTrackers(); + void loadUrlSeeds(); + void on_main_infos_button_clicked(); + void on_trackers_button_clicked(); + void on_url_seeds_button_clicked(); + void on_files_button_clicked(); + void updateChildrenPriority(QStandardItem *item, int priority); + void updateParentsPriority(QStandardItem *item, int priority); + void updatePriorities(QStandardItem *item); + void ignoreSelection(); + void normalSelection(); + void highSelection(); + void maximumSelection(); + void askWebSeed(); + void deleteSelectedUrlSeeds(); + void askForTracker(); + void deleteSelectedTrackers(); + void lowerSelectedTracker(); + void riseSelectedTracker(); + void displayFilesListMenu(const QPoint& pos); + void setItemColor(QModelIndex index, QString color); + void on_changeSavePathButton_clicked(); + void addFilesToTree(torrent_file *root, QStandardItem *parent); + void getPriorities(QStandardItem *parent, int *priorities); + void addTrackerList(QStringList myTrackers); + void filteredFilesChanged(); + +public slots: + void reduce(); + void slide(); + void clear(); + void readSettings(); + void saveSettings(); + +public: + PropertiesWidget(QWidget *parent, TransferListWidget *transferList, bittorrent* BTSession); + ~PropertiesWidget(); +}; + +#endif // PROPERTIESWIDGET_H diff --git a/src/realprogressbar.cpp b/src/realprogressbar.cpp index 667f3c89b..8ae80c0ec 100644 --- a/src/realprogressbar.cpp +++ b/src/realprogressbar.cpp @@ -38,6 +38,7 @@ RealProgressBar::RealProgressBar(QWidget *parent) { background = Qt::white; foreground = Qt::black; + setFixedHeight(20); active = false; array[0] = 0.; drawPixmap(); diff --git a/src/rss.cpp b/src/rss.cpp index 56e90f284..c13e0bf63 100644 --- a/src/rss.cpp +++ b/src/rss.cpp @@ -591,6 +591,7 @@ short RssStream::readDoc(const QDomDocument& doc) { } } } + } else { delete item; } diff --git a/src/seeding.ui b/src/seeding.ui deleted file mode 100644 index 6cf5f042b..000000000 --- a/src/seeding.ui +++ /dev/null @@ -1,159 +0,0 @@ - - - seeding - - - - 0 - 0 - 811 - 453 - - - - Search - - - - 6 - - - 9 - - - - - Qt::CustomContextMenu - - - QAbstractItemView::ExtendedSelection - - - - - - - - true - - - - <u>Note:</u> It is important that you keep sharing your torrents after they are finished for the well being of the network. - - - - - - - Start - - - - - Pause - - - - - Delete - - - - - Delete Permanently - - - - - Torrent Properties - - - - - Preview file - - - - - Set upload limit - - - - - - :/Icons/oxygen/folder.png:/Icons/oxygen/folder.png - - - Open destination folder - - - - - Name - - - - - Size - - - - - Upload Speed - - - - - Connected peers - - - Connected peers - - - - - Ratio - - - - - - :/Icons/oxygen/wallet.png:/Icons/oxygen/wallet.png - - - Buy it - - - - - - :/Icons/oxygen/gear.png:/Icons/oxygen/gear.png - - - Force recheck - - - - - Total uploaded - - - - - Seeds / Leechers - - - Seeds / Leechers - - - - - Copy magnet link - - - - - - - - diff --git a/src/src.pro b/src/src.pro index 115cc1b1b..c393feda9 100644 --- a/src/src.pro +++ b/src/src.pro @@ -143,9 +143,7 @@ HEADERS += GUI.h \ misc.h \ options_imp.h \ about_imp.h \ - properties_imp.h \ createtorrent_imp.h \ - DLListDelegate.h \ SearchListDelegate.h \ PropListDelegate.h \ previewSelect.h \ @@ -158,11 +156,8 @@ HEADERS += GUI.h \ searchEngine.h \ rss.h \ rss_imp.h \ - FinishedTorrents.h \ allocationDlg.h \ - FinishedListDelegate.h \ qtorrenthandle.h \ - downloadingTorrents.h \ engineSelectDlg.h \ pluginSource.h \ arborescence.h \ @@ -185,11 +180,14 @@ HEADERS += GUI.h \ torrentPersistentData.h \ FeedDownloader.h \ feedList.h \ - supportedEngines.h + supportedEngines.h \ + TransferListWidget.h \ + TransferListDelegate.h \ + TransferListFiltersWidget.h \ + propertieswidget.h FORMS += MainWindow.ui \ options.ui \ about.ui \ - properties.ui \ createtorrent.ui \ preview.ui \ login.ui \ @@ -197,25 +195,21 @@ FORMS += MainWindow.ui \ addTorrentDialog.ui \ search.ui \ rss.ui \ - seeding.ui \ bandwidth_limit.ui \ - download.ui \ engineSelect.ui \ pluginSource.ui \ trackersAdd.ui \ console.ui \ - FeedDownloader.ui + FeedDownloader.ui \ + propertiesWidget.ui SOURCES += GUI.cpp \ main.cpp \ options_imp.cpp \ - properties_imp.cpp \ createtorrent_imp.cpp \ bittorrent.cpp \ searchEngine.cpp \ rss_imp.cpp \ - FinishedTorrents.cpp \ qtorrenthandle.cpp \ - downloadingTorrents.cpp \ engineSelectDlg.cpp \ downloadThread.cpp \ realprogressbar.cpp \ @@ -228,5 +222,7 @@ SOURCES += GUI.cpp \ eventmanager.cpp \ SearchTab.cpp \ ico.cpp \ - rss.cpp + rss.cpp \ + TransferListWidget.cpp \ + propertieswidget.cpp DESTDIR = . diff --git a/src/torrentAddition.h b/src/torrentAddition.h index 83f5f1bbf..00bde2d13 100644 --- a/src/torrentAddition.h +++ b/src/torrentAddition.h @@ -179,8 +179,8 @@ public: // set row Color setItemColor(first->index(), "green"); // Add children - QList children = root->getChildren(); - foreach(const torrent_file *child, children) { + QList children = root->getChildren(); + foreach(torrent_file *child, children) { addFilesToTree(child, first); } } diff --git a/src/webui/scripts/client.js b/src/webui/scripts/client.js index 5b07e2b14..dd119fb94 100644 --- a/src/webui/scripts/client.js +++ b/src/webui/scripts/client.js @@ -49,13 +49,13 @@ window.addEvent('domready', function(){ case 'seeding': return ''; case 'checking': - return ''; + return ''; case 'downloading': return ''; case 'stalled': return ''; case 'queued': - return ''; + return ''; default: return ''; }