- Merged major-gui-lift branch
|
@ -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 <QItemDelegate>
|
||||
#include <QModelIndex>
|
||||
#include <QPainter>
|
||||
#include <QStyleOptionProgressBarV2>
|
||||
#include <QStyleOptionViewItemV2>
|
||||
#include <QProgressBar>
|
||||
#include <QApplication>
|
||||
#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
|
|
@ -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 <QItemDelegate>
|
||||
#include <QModelIndex>
|
||||
#include <QPainter>
|
||||
#include <QStyleOptionProgressBarV2>
|
||||
#include <QStyleOptionViewItemV2>
|
||||
#include <QProgressBar>
|
||||
#include <QApplication>
|
||||
#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
|
|
@ -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 <QFile>
|
||||
#include <QSettings>
|
||||
#include <QStandardItemModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QHeaderView>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
|
||||
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; i<nbColumns; ++i){
|
||||
finishedListModel->setData(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; i<listSize; ++i){
|
||||
finishedList->header()->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;i<visualIndexes.size(); ++i) {
|
||||
int new_visual_index = visualIndexes.at(finishedList->header()->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; i<nbColumns; ++i){
|
||||
if(finishedList->columnWidth(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; i<nbColumns; ++i) {
|
||||
visualIndexes.append(finishedList->header()->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; i<nbRows; ++i){
|
||||
if(finishedListModel->data(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; i<nbCols; ++i) {
|
||||
if(!finishedList->isColumnHidden(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; i<nbCols; ++i) {
|
||||
if(!finishedList->isColumnHidden(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; i<listSize; ++i){
|
||||
finishedList->header()->resizeSection(i, ishidden_list.at(i).toInt());
|
||||
}
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
for(int i=0; i<finishedListModel->columnCount()-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; i<nbColumns; ++i){
|
||||
if(finishedList->isColumnHidden(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;
|
||||
}
|
||||
}
|
|
@ -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
|
579
src/GUI.cpp
|
@ -31,6 +31,7 @@
|
|||
#include <QMessageBox>
|
||||
#include <QDesktopWidget>
|
||||
#include <QTimer>
|
||||
#include <QVBoxLayout>
|
||||
#include <QDesktopServices>
|
||||
#include <QStatusBar>
|
||||
#include <QFrame>
|
||||
|
@ -46,24 +47,24 @@
|
|||
#include <QModelIndex>
|
||||
|
||||
#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 <stdlib.h>
|
||||
#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<int> 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<torrent_handle> torrents = BTSession->getTorrents();
|
||||
std::vector<torrent_handle>::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<torrent_handle> torrents = BTSession->getTorrents();
|
||||
std::vector<torrent_handle>::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<QTorrentHandle,QString> tracker) {
|
||||
// Trackers whose authentication was cancelled
|
||||
if(unauthenticated_trackers.indexOf(tracker) < 0) {
|
||||
|
@ -1430,19 +1042,7 @@ void GUI::addUnauthenticatedTracker(QPair<QTorrentHandle,QString> 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 *
|
||||
|
|
46
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<QTimer> 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<QTorrentHandle,QString> 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 *);
|
||||
|
|
BIN
src/Icons/oxygen/draw-rectangle.png
Normal file
After Width: | Height: | Size: 389 B |
BIN
src/Icons/oxygen/draw-triangle2.png
Normal file
After Width: | Height: | Size: 670 B |
BIN
src/Icons/oxygen/folder-remote.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
src/Icons/oxygen/folder-remote16.png
Normal file
After Width: | Height: | Size: 675 B |
BIN
src/Icons/oxygen/help-about.png
Normal file
After Width: | Height: | Size: 734 B |
BIN
src/Icons/oxygen/mail-queue.png
Normal file
After Width: | Height: | Size: 860 B |
BIN
src/Icons/oxygen/network-server.png
Normal file
After Width: | Height: | Size: 491 B |
BIN
src/Icons/oxygen/peer.png
Normal file
After Width: | Height: | Size: 409 B |
BIN
src/Icons/oxygen/run-build.png
Normal file
After Width: | Height: | Size: 942 B |
Before Width: | Height: | Size: 856 B |
BIN
src/Icons/oxygen/urlseed.png
Normal file
After Width: | Height: | Size: 901 B |
Before Width: | Height: | Size: 493 B |
|
@ -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;
|
||||
}
|
||||
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 {
|
||||
unsigned short val = index.model()->data(index, Qt::DisplayRole).toInt();
|
||||
QComboBox *combobox = static_cast<QComboBox*>(editor);
|
||||
qDebug("Set Editor data: Prio is %d", val);
|
||||
switch(val){
|
||||
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<QComboBox*>(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);
|
||||
}
|
||||
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<QFont>(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();
|
||||
}
|
||||
QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const{
|
||||
QVariant value = index.data(Qt::FontRole);
|
||||
QFont fnt = value.isValid() ? qvariant_cast<QFont>(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<QComboBox*>(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<QComboBox*>(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);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
|
116
src/TransferListDelegate.h
Normal file
|
@ -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 <QItemDelegate>
|
||||
#include <QModelIndex>
|
||||
#include <QByteArray>
|
||||
#include <QStyleOptionViewItem>
|
||||
#include <QStyleOptionViewItemV2>
|
||||
#include <QApplication>
|
||||
#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
|
60
src/TransferListFiltersWidget.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
#ifndef TRANSFERLISTFILTERSWIDGET_H
|
||||
#define TRANSFERLISTFILTERSWIDGET_H
|
||||
|
||||
#include <QListWidget>
|
||||
#include <QListWidgetItem>
|
||||
#include <QIcon>
|
||||
#include <QSettings>
|
||||
|
||||
#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
|
842
src/TransferListWidget.cpp
Normal file
|
@ -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 <QStandardItemModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QDesktopServices>
|
||||
#include <QTimer>
|
||||
#include <QSettings>
|
||||
#include <QClipboard>
|
||||
#include <QColor>
|
||||
#include <QUrl>
|
||||
#include <QMenu>
|
||||
#include <QRegExp>
|
||||
#include <vector>
|
||||
|
||||
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; i<nbColumns; ++i) {
|
||||
listModel->setData(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; i<listModel->rowCount(); ++i) {
|
||||
updateTorrent(i);
|
||||
}
|
||||
}
|
||||
|
||||
int TransferListWidget::getRowFromHash(QString hash) const{
|
||||
QList<QStandardItem *> 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; i<listModel->rowCount(); ++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; i<listModel->rowCount(); ++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; i<nbColumns; ++i){
|
||||
if(isColumnHidden(i)) {
|
||||
ishidden_list << "0";
|
||||
} else {
|
||||
ishidden_list << "1";
|
||||
}
|
||||
}
|
||||
settings.setValue("TransferListColsHoS", ishidden_list.join(" "));
|
||||
}
|
||||
|
||||
// load the previous settings, and hide the columns
|
||||
bool TransferListWidget::loadHiddenColumns() {
|
||||
QSettings settings("qBittorrent", "qBittorrent");
|
||||
QString line = settings.value("TransferListColsHoS", QString()).toString();
|
||||
if(line.isEmpty()) return false;
|
||||
bool loaded = false;
|
||||
QStringList ishidden_list;
|
||||
ishidden_list = line.split(' ');
|
||||
unsigned int nbCol = ishidden_list.size();
|
||||
if(nbCol == (unsigned int)listModel->columnCount()-2) {
|
||||
for(unsigned int i=0; i<nbCol; ++i){
|
||||
if(ishidden_list.at(i) == "0") {
|
||||
setColumnHidden(i, true);
|
||||
}
|
||||
}
|
||||
loaded = true;
|
||||
}
|
||||
return loaded;
|
||||
}
|
||||
|
||||
// hide/show columns menu
|
||||
void TransferListWidget::displayDLHoSMenu(const QPoint&){
|
||||
QMenu hideshowColumn(this);
|
||||
hideshowColumn.setTitle(tr("Column visibility"));
|
||||
int lastCol;
|
||||
if(BTSession->isQueueingEnabled()) {
|
||||
lastCol = PRIORITY;
|
||||
} else {
|
||||
lastCol = ETA;
|
||||
}
|
||||
QList<QAction*> 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<nbColumns; ++i){
|
||||
if(columnWidth(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(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; i<nbColumns; ++i) {
|
||||
visualIndexes.append(header()->visualIndex(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; i<listSize; ++i) {
|
||||
header()->resizeSection(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;i<visualIndexes.size(); ++i) {
|
||||
int new_visual_index = visualIndexes.at(header()->logicalIndex(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()));
|
||||
}
|
111
src/TransferListWidget.h
Normal file
|
@ -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<QTreeView>
|
||||
#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
|
|
@ -41,7 +41,7 @@ private:
|
|||
torrent_file *parent;
|
||||
bool is_dir;
|
||||
QString rel_path;
|
||||
QList<const torrent_file*> children;
|
||||
QList<torrent_file*> children;
|
||||
size_type size;
|
||||
float progress;
|
||||
int priority;
|
||||
|
@ -63,6 +63,19 @@ public:
|
|||
qDeleteAll(children);
|
||||
}
|
||||
|
||||
void updateProgress(std::vector<size_type> 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<const torrent_file*> getChildren() const {
|
||||
QList<torrent_file*> 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<size_type> fp) {
|
||||
root->updateProgress(fp);
|
||||
}
|
||||
|
||||
torrent_file* getRoot() const {
|
||||
return root;
|
||||
}
|
||||
|
|
|
@ -243,32 +243,15 @@ QTorrentHandle bittorrent::getTorrentHandle(QString hash) const{
|
|||
return QTorrentHandle(s->find_torrent(misc::fromString<sha1_hash>((hash.toStdString()))));
|
||||
}
|
||||
|
||||
unsigned int bittorrent::getFinishedPausedTorrentsNb() const {
|
||||
unsigned int nbPaused = 0;
|
||||
bool bittorrent::hasActiveTorrents() const {
|
||||
std::vector<torrent_handle> torrents = getTorrents();
|
||||
std::vector<torrent_handle>::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;
|
||||
}
|
||||
|
||||
unsigned int bittorrent::getUnfinishedPausedTorrentsNb() const {
|
||||
unsigned int nbPaused = 0;
|
||||
std::vector<torrent_handle> torrents = getTorrents();
|
||||
std::vector<torrent_handle>::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;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Delete a torrent from the session, given its hash
|
||||
|
|
|
@ -97,8 +97,7 @@ class bittorrent : public QObject {
|
|||
session* getSession() const;
|
||||
QHash<QString, QString> 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;
|
||||
|
|
193
src/download.ui
|
@ -1,193 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>downloading</class>
|
||||
<widget class="QWidget" name="downloading">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>811</width>
|
||||
<height>453</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Search</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTreeView" name="downloadList">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="autoScroll">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<property name="indentation">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="itemsExpandable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
<action name="actionStart">
|
||||
<property name="text">
|
||||
<string>Start</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionPause">
|
||||
<property name="text">
|
||||
<string>Pause</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDelete">
|
||||
<property name="text">
|
||||
<string>Delete</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionPreview_file">
|
||||
<property name="text">
|
||||
<string>Preview file</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSet_upload_limit">
|
||||
<property name="text">
|
||||
<string>Set upload limit</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSet_download_limit">
|
||||
<property name="text">
|
||||
<string>Set download limit</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDelete_Permanently">
|
||||
<property name="text">
|
||||
<string>Delete Permanently</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionTorrent_Properties">
|
||||
<property name="text">
|
||||
<string>Torrent Properties</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionOpen_destination_folder">
|
||||
<property name="icon">
|
||||
<iconset resource="icons.qrc">
|
||||
<normaloff>:/Icons/oxygen/folder.png</normaloff>:/Icons/oxygen/folder.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Open destination folder</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionHOSColName">
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionHOSColSize">
|
||||
<property name="text">
|
||||
<string>Size</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionHOSColProgress">
|
||||
<property name="text">
|
||||
<string>Progress</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionHOSColDownSpeed">
|
||||
<property name="text">
|
||||
<string>DLSpeed</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionHOSColUpSpeed">
|
||||
<property name="text">
|
||||
<string>UpSpeed</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionHOSColSeedersLeechers">
|
||||
<property name="text">
|
||||
<string>Seeds/Leechs</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionHOSColRatio">
|
||||
<property name="text">
|
||||
<string>Ratio</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionHOSColEta">
|
||||
<property name="text">
|
||||
<string>ETA</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionBuy_it">
|
||||
<property name="icon">
|
||||
<iconset resource="icons.qrc">
|
||||
<normaloff>:/Icons/oxygen/wallet.png</normaloff>:/Icons/oxygen/wallet.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Buy it</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionHOSColPriority">
|
||||
<property name="text">
|
||||
<string>Priority</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionIncreasePriority">
|
||||
<property name="icon">
|
||||
<iconset resource="icons.qrc">
|
||||
<normaloff>:/Icons/skin/increase.png</normaloff>:/Icons/skin/increase.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Increase priority</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDecreasePriority">
|
||||
<property name="icon">
|
||||
<iconset resource="icons.qrc">
|
||||
<normaloff>:/Icons/skin/decrease.png</normaloff>:/Icons/skin/decrease.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Decrease priority</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionForce_recheck">
|
||||
<property name="icon">
|
||||
<iconset resource="icons.qrc">
|
||||
<normaloff>:/Icons/oxygen/gear.png</normaloff>:/Icons/oxygen/gear.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Force recheck</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCopy_magnet_link">
|
||||
<property name="text">
|
||||
<string>Copy magnet link</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="icons.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -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 <QFile>
|
||||
#include <QSettings>
|
||||
#include <QStandardItemModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QHeaderView>
|
||||
#include <QTime>
|
||||
#include <QMenu>
|
||||
|
||||
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; i<nbCols; ++i) {
|
||||
if(!downloadList->isColumnHidden(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; i<nbCols; ++i) {
|
||||
if(!downloadList->isColumnHidden(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; i<nbColumns; ++i){
|
||||
if(downloadList->isColumnHidden(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; i<listSize; ++i){
|
||||
downloadList->header()->resizeSection(i, ishidden_list.at(i).toInt());
|
||||
}
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
for(int i=0; i<DLListModel->columnCount()-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; i<nbColumns; ++i){
|
||||
if(downloadList->columnWidth(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; i<nbColumns; ++i) {
|
||||
visualIndexes.append(downloadList->header()->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; i<listSize; ++i) {
|
||||
downloadList->header()->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;i<visualIndexes.size(); ++i) {
|
||||
int new_visual_index = visualIndexes.at(downloadList->header()->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; i<nbColumns; ++i) {
|
||||
DLListModel->setData(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; i<nbRows; ++i) {
|
||||
if(DLListModel->data(DLListModel->index(i, HASH)) == hash) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
|
@ -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
|
|
@ -35,7 +35,6 @@
|
|||
<file>Icons/skin/info.png</file>
|
||||
<file>Icons/skin/tabs.gif</file>
|
||||
<file>Icons/skin/delete_perm.png</file>
|
||||
<file>Icons/skin/queued.png</file>
|
||||
<file>Icons/skin/settings.png</file>
|
||||
<file>Icons/skin/exit.png</file>
|
||||
<file>Icons/skin/delete_all.png</file>
|
||||
|
@ -68,13 +67,16 @@
|
|||
<file>Icons/flags/italy.png</file>
|
||||
<file>Icons/flags/south_korea.png</file>
|
||||
<file>Icons/flags/japan.png</file>
|
||||
<file>Icons/oxygen/mail-queue.png</file>
|
||||
<file>Icons/oxygen/view-refresh.png</file>
|
||||
<file>Icons/oxygen/file.png</file>
|
||||
<file>Icons/oxygen/folder-remote16.png</file>
|
||||
<file>Icons/oxygen/mail-folder-inbox.png</file>
|
||||
<file>Icons/oxygen/time.png</file>
|
||||
<file>Icons/oxygen/edit-find.png</file>
|
||||
<file>Icons/oxygen/folder-new.png</file>
|
||||
<file>Icons/oxygen/folder-remote.png</file>
|
||||
<file>Icons/oxygen/edit-paste.png</file>
|
||||
<file>Icons/oxygen/run-build.png</file>
|
||||
<file>Icons/oxygen/proxy.png</file>
|
||||
<file>Icons/oxygen/log.png</file>
|
||||
<file>Icons/oxygen/unavailable.png</file>
|
||||
|
@ -87,7 +89,9 @@
|
|||
<file>Icons/oxygen/download.png</file>
|
||||
<file>Icons/oxygen/application-x-kgetlist-no.png</file>
|
||||
<file>Icons/oxygen/gear.png</file>
|
||||
<file>Icons/oxygen/draw-triangle2.png</file>
|
||||
<file>Icons/oxygen/remove.png</file>
|
||||
<file>Icons/oxygen/peer.png</file>
|
||||
<file>Icons/oxygen/browse.png</file>
|
||||
<file>Icons/oxygen/unsubscribe16.png</file>
|
||||
<file>Icons/oxygen/subscribe.png</file>
|
||||
|
@ -101,11 +105,15 @@
|
|||
<file>Icons/oxygen/list-remove.png</file>
|
||||
<file>Icons/oxygen/connection.png</file>
|
||||
<file>Icons/oxygen/bug.png</file>
|
||||
<file>Icons/oxygen/help-about.png</file>
|
||||
<file>Icons/oxygen/list-add.png</file>
|
||||
<file>Icons/oxygen/network-server.png</file>
|
||||
<file>Icons/oxygen/application-x-kgetlist.png</file>
|
||||
<file>Icons/oxygen/folder.png</file>
|
||||
<file>Icons/oxygen/urlseed.png</file>
|
||||
<file>Icons/oxygen/edit-cut.png</file>
|
||||
<file>Icons/oxygen/unsubscribe.png</file>
|
||||
<file>Icons/oxygen/draw-rectangle.png</file>
|
||||
<file>Icons/oxygen/subscribe16.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
1080
src/properties.ui
1046
src/propertiesWidget.ui
Normal file
|
@ -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<int> loadFilesPriorities();
|
||||
|
||||
protected:
|
||||
QPoint screenCenter() const;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -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 "realprogressbar.h"
|
||||
#include "realprogressbarthread.h"
|
||||
#include "TrackersAdditionDlg.h"
|
||||
#include "torrentPersistentData.h"
|
||||
|
||||
#include <QInputDialog>
|
||||
#include <QTimer>
|
||||
#include <QListWidgetItem>
|
||||
#include <QStandardItemModel>
|
||||
#include <QStandardItem>
|
||||
#include <QVBoxLayout>
|
||||
#include <QStackedWidget>
|
||||
#include <QSplitter>
|
||||
#include <QAction>
|
||||
#include <QMessageBox>
|
||||
#include <QMenu>
|
||||
#include <QTimer>
|
||||
#include <QStandardItemModel>
|
||||
#include <QSettings>
|
||||
#include <QDesktopWidget>
|
||||
#include <QFileDialog>
|
||||
#include <QHeaderView>
|
||||
#include <QInputDialog>
|
||||
#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"
|
||||
|
||||
// Constructor
|
||||
properties::properties(QWidget *parent, bittorrent *BTSession, QTorrentHandle &h): QDialog(parent), h(h), BTSession(BTSession), changedFilteredfiles(false), hash(h.hash()) {
|
||||
#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;}"
|
||||
|
||||
PropertiesWidget::PropertiesWidget(QWidget *parent, TransferListWidget *transferList, bittorrent* BTSession): QWidget(parent), transferList(transferList), BTSession(BTSession) {
|
||||
setupUi(this);
|
||||
lbl_priorities->setText(tr("Priorities:")+"<ul><li>"+tr("Ignored: file is not downloaded at all")+"</li><li>"+tr("Normal: normal priority. Download order is dependent on availability")+"</li><li>"+tr("High: higher than normal priority. Pieces are preferred over pieces with the same availability, but not over pieces with lower availability")+"</li><li>"+tr("Maximum: maximum priority, availability is disregarded, the piece is preferred over any other piece with lower priority")+"</li></ul>");
|
||||
// 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<size_type> fp;
|
||||
h.file_progress(fp);
|
||||
std::vector<int> 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();
|
||||
// Pointers init
|
||||
progressBarUpdater = 0;
|
||||
arb = 0;
|
||||
// Dynamic data refresher
|
||||
refreshTimer = new QTimer(this);
|
||||
connect(refreshTimer, SIGNAL(timeout()), this, SLOT(loadDynamicData()));
|
||||
refreshTimer->start(10000); // 10sec
|
||||
}
|
||||
|
||||
properties::~properties(){
|
||||
writeSettings();
|
||||
qDebug("Properties destroyed");
|
||||
delete updateInfosTimer;
|
||||
delete PropDelegate;
|
||||
delete PropListModel;
|
||||
delete progressBarUpdater;
|
||||
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<QStandardItem*> 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() {
|
||||
void PropertiesWidget::slide() {
|
||||
if(state == REDUCED) {
|
||||
stackedProperties->setFixedHeight(260);
|
||||
state = VISIBLE;
|
||||
}
|
||||
}
|
||||
|
||||
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<size_type> fp;
|
||||
h.file_progress(fp);
|
||||
std::vector<int> 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"));
|
||||
settings.beginGroup(QString::fromUtf8("PropWindow"));
|
||||
settings.setValue(QString::fromUtf8("size"), size());
|
||||
settings.setValue(QString::fromUtf8("pos"), pos());
|
||||
QVariantList contentColsWidths;
|
||||
for(int i=0; i<PropListModel->columnCount()-1; ++i) {
|
||||
contentColsWidths.append(filesList->columnWidth(i));
|
||||
}
|
||||
settings.setValue(QString::fromUtf8("contentColsWidths"), contentColsWidths);
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
void properties::loadSettings() {
|
||||
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; i<contentColsWidths.size(); ++i) {
|
||||
filesList->setColumnWidth(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; i<PropListModel->columnCount()-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<announce_entry> trackers = h.trackers();
|
||||
trackersURLS->clear();
|
||||
QHash<QString, QString> errors = BTSession->getTrackersErrors(h.hash());
|
||||
unsigned int nbTrackers = trackers.size();
|
||||
for(unsigned int i=0; i<nbTrackers; ++i){
|
||||
QString current_tracker = misc::toQString(trackers[i].url);
|
||||
QListWidgetItem *item = new QListWidgetItem(current_tracker, trackersURLS);
|
||||
// IsThere any errors ?
|
||||
if(errors.contains(current_tracker)) {
|
||||
item->setForeground(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<int> properties::loadFilesPriorities(){
|
||||
std::vector<int> PropertiesWidget::loadFilesPriorities(){
|
||||
std::vector<int> fp;
|
||||
QVariantList files_priority = TorrentPersistentData::getFilesPriority(hash);
|
||||
QVariantList files_priority = TorrentPersistentData::getFilesPriority(h.hash());
|
||||
if(files_priority.empty()) {
|
||||
for(int i=0; i<h.num_files(); ++i) {
|
||||
fp.push_back(1);
|
||||
|
@ -348,7 +496,7 @@ std::vector<int> properties::loadFilesPriorities(){
|
|||
return fp;
|
||||
}
|
||||
|
||||
bool properties::allFiltered() const {
|
||||
bool PropertiesWidget::allFiltered() const {
|
||||
unsigned int nbRows = PropListModel->rowCount();
|
||||
for(unsigned int i=0; i<nbRows; ++i){
|
||||
if(PropListModel->data(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; i<nbRows; ++i){
|
||||
|
@ -374,7 +522,7 @@ void properties::getPriorities(QStandardItem *parent, int *priorities) {
|
|||
}
|
||||
}
|
||||
|
||||
void properties::displayFilesListMenu(const QPoint&){
|
||||
void PropertiesWidget::displayFilesListMenu(const QPoint&){
|
||||
if(h.get_torrent_info().num_files() == 1) return;
|
||||
QMenu myFilesLlistMenu(this);
|
||||
QModelIndex index;
|
||||
|
@ -389,93 +537,59 @@ void properties::displayFilesListMenu(const QPoint&){
|
|||
myFilesLlistMenu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
void properties::ignoreSelection(){
|
||||
void PropertiesWidget::ignoreSelection(){
|
||||
QModelIndexList selectedIndexes = filesList->selectionModel()->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<announce_entry> trackers = h.trackers();
|
||||
trackersURLS->clear();
|
||||
QHash<QString, QString> errors = BTSession->getTrackersErrors(h.hash());
|
||||
unsigned int nbTrackers = trackers.size();
|
||||
for(unsigned int i=0; i<nbTrackers; ++i){
|
||||
QString current_tracker = misc::toQString(trackers[i].url);
|
||||
QListWidgetItem *item = new QListWidgetItem(current_tracker, trackersURLS);
|
||||
// IsThere any errors ?
|
||||
if(errors.contains(current_tracker)) {
|
||||
item->setForeground(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<announce_entry> 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<QListWidgetItem *> 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<QListWidgetItem *> selectedItems = trackersURLS->selectedItems();
|
||||
if(!selectedItems.size()) return;
|
||||
std::vector<announce_entry> 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<announce_entry> trackers = h.trackers();
|
||||
QList<QListWidgetItem *> 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<announce_entry> trackers = h.trackers();
|
||||
QList<QListWidgetItem *> 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; i<PropListModel->columnCount(); ++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; i<nbFiles; ++i) {
|
||||
h.file_priority(i, priorities[i]);
|
||||
}
|
||||
delete[] priorities;
|
||||
TorrentPersistentData::saveFilesPriority(h);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void properties::on_changeSavePathButton_clicked() {
|
||||
|
||||
void PropertiesWidget::on_changeSavePathButton_clicked() {
|
||||
QString dir;
|
||||
QDir saveDir(h.save_path());
|
||||
if(saveDir.exists()){
|
||||
|
@ -686,7 +786,7 @@ void properties::on_changeSavePathButton_clicked() {
|
|||
}
|
||||
}
|
||||
// Save savepath
|
||||
TorrentPersistentData::saveSavePath(hash, savePath.path());
|
||||
TorrentPersistentData::saveSavePath(h.hash(), savePath.path());
|
||||
// Actually move storage
|
||||
if(!BTSession->useTemporaryFolder() || 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<QStandardItem*> 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; i<nbFiles; ++i) {
|
||||
h.file_priority(i, priorities[i]);
|
||||
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(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;
|
||||
}
|
123
src/propertieswidget.h
Normal file
|
@ -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 <QWidget>
|
||||
#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<int> 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
|
|
@ -38,6 +38,7 @@ RealProgressBar::RealProgressBar(QWidget *parent)
|
|||
{
|
||||
background = Qt::white;
|
||||
foreground = Qt::black;
|
||||
setFixedHeight(20);
|
||||
active = false;
|
||||
array[0] = 0.;
|
||||
drawPixmap();
|
||||
|
|
|
@ -591,6 +591,7 @@ short RssStream::readDoc(const QDomDocument& doc) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
delete item;
|
||||
}
|
||||
|
|
159
src/seeding.ui
|
@ -1,159 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>seeding</class>
|
||||
<widget class="QWidget" name="seeding">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>811</width>
|
||||
<height>453</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Search</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTreeView" name="finishedList">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lbl_note">
|
||||
<property name="font">
|
||||
<font>
|
||||
<italic>true</italic>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><u>Note:</u> It is important that you keep sharing your torrents after they are finished for the well being of the network.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<action name="actionStart">
|
||||
<property name="text">
|
||||
<string>Start</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionPause">
|
||||
<property name="text">
|
||||
<string>Pause</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDelete">
|
||||
<property name="text">
|
||||
<string>Delete</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDelete_Permanently">
|
||||
<property name="text">
|
||||
<string>Delete Permanently</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionTorrent_Properties">
|
||||
<property name="text">
|
||||
<string>Torrent Properties</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionPreview_file">
|
||||
<property name="text">
|
||||
<string>Preview file</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSet_upload_limit">
|
||||
<property name="text">
|
||||
<string>Set upload limit</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionOpen_destination_folder">
|
||||
<property name="icon">
|
||||
<iconset resource="icons.qrc">
|
||||
<normaloff>:/Icons/oxygen/folder.png</normaloff>:/Icons/oxygen/folder.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Open destination folder</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionHOSColName">
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionHOSColSize">
|
||||
<property name="text">
|
||||
<string>Size</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionHOSColUpSpeed">
|
||||
<property name="text">
|
||||
<string>Upload Speed</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionHOSColPeers">
|
||||
<property name="text">
|
||||
<string>Connected peers</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Connected peers</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionHOSColRatio">
|
||||
<property name="text">
|
||||
<string>Ratio</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionBuy_it">
|
||||
<property name="icon">
|
||||
<iconset resource="icons.qrc">
|
||||
<normaloff>:/Icons/oxygen/wallet.png</normaloff>:/Icons/oxygen/wallet.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Buy it</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionForce_recheck">
|
||||
<property name="icon">
|
||||
<iconset resource="icons.qrc">
|
||||
<normaloff>:/Icons/oxygen/gear.png</normaloff>:/Icons/oxygen/gear.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Force recheck</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionHOSColUpload">
|
||||
<property name="text">
|
||||
<string>Total uploaded</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionHOSColSwarm">
|
||||
<property name="text">
|
||||
<string>Seeds / Leechers</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Seeds / Leechers</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCopy_magnet_link">
|
||||
<property name="text">
|
||||
<string>Copy magnet link</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="icons.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
24
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 = .
|
||||
|
|
|
@ -179,8 +179,8 @@ public:
|
|||
// set row Color
|
||||
setItemColor(first->index(), "green");
|
||||
// Add children
|
||||
QList<const torrent_file*> children = root->getChildren();
|
||||
foreach(const torrent_file *child, children) {
|
||||
QList<torrent_file*> children = root->getChildren();
|
||||
foreach(torrent_file *child, children) {
|
||||
addFilesToTree(child, first);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,13 +49,13 @@ window.addEvent('domready', function(){
|
|||
case 'seeding':
|
||||
return '<img src="images/skin/seeding.png"/>';
|
||||
case 'checking':
|
||||
return '<img src="images/oxygen/time.png"/>';
|
||||
return '<img src="images/oxygen/run-build.png"/>';
|
||||
case 'downloading':
|
||||
return '<img src="images/skin/downloading.png"/>';
|
||||
case 'stalled':
|
||||
return '<img src="images/skin/stalled.png"/>';
|
||||
case 'queued':
|
||||
return '<img src="images/skin/queued.png"/>';
|
||||
return '<img src="images/oxygen/mail-queue.png"/>';
|
||||
default:
|
||||
return '<img src="images/skin/stalled.png"/>';
|
||||
}
|
||||
|
|