mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2026-01-06 15:42:32 -06:00
Fix compilation warnings in smtp.h (cgreco)
This commit is contained in:
131
src/properties/downloadedpiecesbar.h
Normal file
131
src/properties/downloadedpiecesbar.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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 DOWNLOADEDPIECESBAR_H
|
||||
#define DOWNLOADEDPIECESBAR_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QPainter>
|
||||
#include <QList>
|
||||
#include <QPixmap>
|
||||
#include <libtorrent/bitfield.hpp>
|
||||
#include <math.h>
|
||||
|
||||
#define BAR_HEIGHT 18
|
||||
|
||||
class DownloadedPiecesBar: public QWidget {
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(DownloadedPiecesBar)
|
||||
|
||||
private:
|
||||
QPixmap pixmap;
|
||||
|
||||
|
||||
public:
|
||||
DownloadedPiecesBar(QWidget *parent): QWidget(parent) {
|
||||
setFixedHeight(BAR_HEIGHT);
|
||||
}
|
||||
|
||||
void setProgress(const libtorrent::bitfield &pieces, const libtorrent::bitfield &downloading_pieces) {
|
||||
if(pieces.empty()) {
|
||||
// Empty bar
|
||||
QPixmap pix = QPixmap(1, 1);
|
||||
pix.fill();
|
||||
pixmap = pix;
|
||||
} else {
|
||||
const qulonglong nb_pieces = pieces.size();
|
||||
// Reduce the number of pieces before creating the pixmap
|
||||
// otherwise it can crash when there are too many pieces
|
||||
const uint w = width();
|
||||
if(nb_pieces > w) {
|
||||
const uint ratio = floor(nb_pieces/(double)w);
|
||||
libtorrent::bitfield scaled_pieces(ceil(nb_pieces/(double)ratio), false);
|
||||
libtorrent::bitfield scaled_downloading(ceil(nb_pieces/(double)ratio), false);
|
||||
uint scaled_index = 0;
|
||||
for(qulonglong i=0; i<nb_pieces; i+= ratio) {
|
||||
bool have = true;
|
||||
for(qulonglong j=i; j<qMin(i+ratio, nb_pieces); ++j) {
|
||||
if(!pieces[i]) { have = false; break; }
|
||||
}
|
||||
if(have) {
|
||||
scaled_pieces.set_bit(scaled_index);
|
||||
} else {
|
||||
bool downloading = false;
|
||||
for(qulonglong j=i; j<qMin(i+ratio, nb_pieces); ++j) {
|
||||
if(downloading_pieces[i]) { downloading = true; break; }
|
||||
}
|
||||
if(downloading)
|
||||
scaled_downloading.set_bit(scaled_index);
|
||||
}
|
||||
++scaled_index;
|
||||
}
|
||||
updatePixmap(scaled_pieces, scaled_downloading);
|
||||
} else {
|
||||
updatePixmap(pieces, downloading_pieces);
|
||||
}
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
pixmap = QPixmap();
|
||||
update();
|
||||
}
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *) {
|
||||
if(pixmap.isNull()) return;
|
||||
QPainter painter(this);
|
||||
painter.drawPixmap(rect(), pixmap);
|
||||
}
|
||||
|
||||
private:
|
||||
void updatePixmap(const libtorrent::bitfield &pieces, const libtorrent::bitfield &downloading_pieces) {
|
||||
QPixmap pix = QPixmap(pieces.size(), 1);
|
||||
//pix.fill();
|
||||
QPainter painter(&pix);
|
||||
for(uint i=0; i<pieces.size(); ++i) {
|
||||
if(pieces[i]) {
|
||||
painter.setPen(Qt::blue);
|
||||
} else {
|
||||
if(downloading_pieces[i]) {
|
||||
painter.setPen(Qt::green);
|
||||
} else {
|
||||
painter.setPen(Qt::white);
|
||||
}
|
||||
}
|
||||
painter.drawPoint(i,0);
|
||||
}
|
||||
pixmap = pix;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // DOWNLOADEDPIECESBAR_H
|
||||
109
src/properties/peer.ui
Normal file
109
src/properties/peer.ui
Normal file
@@ -0,0 +1,109 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>addPeerDialog</class>
|
||||
<widget class="QDialog" name="addPeerDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>112</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Peer addition</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>IP</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineIP"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Port</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinPort">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65535</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>6881</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
103
src/properties/peeraddition.h
Normal file
103
src/properties/peeraddition.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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 PEERADDITION_H
|
||||
#define PEERADDITION_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QRegExp>
|
||||
#include <QMessageBox>
|
||||
#include <QHostAddress>
|
||||
#include "ui_peer.h"
|
||||
#include <libtorrent/session.hpp>
|
||||
|
||||
#include <boost/version.hpp>
|
||||
#if BOOST_VERSION < 103500
|
||||
#include <libtorrent/asio/ip/tcp.hpp>
|
||||
#else
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#endif
|
||||
|
||||
class PeerAdditionDlg: public QDialog, private Ui::addPeerDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PeerAdditionDlg(QWidget *parent=0): QDialog(parent) {
|
||||
setupUi(this);
|
||||
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
||||
connect(buttonBox, SIGNAL(accepted()), this, SLOT(validateInput()));
|
||||
}
|
||||
|
||||
~PeerAdditionDlg(){}
|
||||
|
||||
QString getIP() const {
|
||||
QHostAddress ip(lineIP->text());
|
||||
if(!ip.isNull()) {
|
||||
// QHostAddress::toString() cleans up the IP for libtorrent
|
||||
return ip.toString();
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
unsigned short getPort() const {
|
||||
return spinPort->value();
|
||||
}
|
||||
|
||||
static libtorrent::asio::ip::tcp::endpoint askForPeerEndpoint() {
|
||||
libtorrent::asio::ip::tcp::endpoint ep;
|
||||
PeerAdditionDlg dlg;
|
||||
if(dlg.exec() == QDialog::Accepted) {
|
||||
QString ip = dlg.getIP();
|
||||
boost::system::error_code ec;
|
||||
libtorrent::address addr = libtorrent::address::from_string(qPrintable(ip), ec);
|
||||
if(ec) {
|
||||
qDebug("Unable to parse the provided IP: %s", qPrintable(ip));
|
||||
return ep;
|
||||
}
|
||||
qDebug("Provided IP is correct");
|
||||
ep = libtorrent::asio::ip::tcp::endpoint(addr, dlg.getPort());
|
||||
}
|
||||
return ep;
|
||||
}
|
||||
|
||||
|
||||
protected slots:
|
||||
void validateInput() {
|
||||
if(getIP().isEmpty()) {
|
||||
QMessageBox::warning(this, tr("Invalid IP"),
|
||||
tr("The IP you provided is invalid."),
|
||||
QMessageBox::Ok);
|
||||
} else {
|
||||
accept();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // PEERADDITION_H
|
||||
86
src/properties/peerlistdelegate.h
Normal file
86
src/properties/peerlistdelegate.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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 PEERLISTDELEGATE_H
|
||||
#define PEERLISTDELEGATE_H
|
||||
|
||||
#include <QItemDelegate>
|
||||
#include <QPainter>
|
||||
#include "misc.h"
|
||||
|
||||
class PeerListDelegate: public QItemDelegate {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum PeerListColumns {IP, CONNECTION, CLIENT, PROGRESS, DOWN_SPEED, UP_SPEED,
|
||||
TOT_DOWN, TOT_UP, IP_HIDDEN, COL_COUNT};
|
||||
|
||||
public:
|
||||
PeerListDelegate(QObject *parent) : QItemDelegate(parent){}
|
||||
|
||||
~PeerListDelegate(){}
|
||||
|
||||
void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const{
|
||||
painter->save();
|
||||
QStyleOptionViewItemV2 opt = QItemDelegate::setOptions(index, option);
|
||||
switch(index.column()){
|
||||
case TOT_DOWN:
|
||||
case TOT_UP:
|
||||
QItemDelegate::drawBackground(painter, opt, index);
|
||||
QItemDelegate::drawDisplay(painter, opt, option.rect, misc::friendlyUnit(index.data().toLongLong()));
|
||||
break;
|
||||
case DOWN_SPEED:
|
||||
case UP_SPEED:{
|
||||
QItemDelegate::drawBackground(painter, opt, index);
|
||||
qreal speed = index.data().toDouble();
|
||||
if (speed > 0.0)
|
||||
QItemDelegate::drawDisplay(painter, opt, opt.rect, misc::friendlyUnit(speed)+tr("/s", "/second (i.e. per second)"));
|
||||
break;
|
||||
}
|
||||
case PROGRESS:{
|
||||
QItemDelegate::drawBackground(painter, opt, index);
|
||||
qreal progress = index.data().toDouble();
|
||||
QItemDelegate::drawDisplay(painter, opt, opt.rect, QString::number(progress*100., 'f', 1)+"%");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
QItemDelegate::paint(painter, option, index);
|
||||
}
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
QWidget* createEditor(QWidget*, const QStyleOptionViewItem &, const QModelIndex &) const {
|
||||
// No editor here
|
||||
return 0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // PEERLISTDELEGATE_H
|
||||
426
src/properties/peerlistwidget.cpp
Normal file
426
src/properties/peerlistwidget.cpp
Normal file
@@ -0,0 +1,426 @@
|
||||
/*
|
||||
* 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 "peerlistwidget.h"
|
||||
#include "peerlistdelegate.h"
|
||||
#include "reverseresolution.h"
|
||||
#include "preferences.h"
|
||||
#include "propertieswidget.h"
|
||||
#include "geoipmanager.h"
|
||||
#include "peeraddition.h"
|
||||
#include "speedlimitdlg.h"
|
||||
#include "iconprovider.h"
|
||||
#include <QStandardItemModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QSet>
|
||||
#include <QHeaderView>
|
||||
#include <QMenu>
|
||||
#include <QClipboard>
|
||||
#include <vector>
|
||||
#include "qinisettings.h"
|
||||
|
||||
using namespace libtorrent;
|
||||
|
||||
PeerListWidget::PeerListWidget(PropertiesWidget *parent): QTreeView(parent), properties(parent), display_flags(false) {
|
||||
// Load settings
|
||||
loadSettings();
|
||||
// Visual settings
|
||||
setRootIsDecorated(false);
|
||||
setItemsExpandable(false);
|
||||
setAllColumnsShowFocus(true);
|
||||
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
// List Model
|
||||
listModel = new QStandardItemModel(0, PeerListDelegate::COL_COUNT);
|
||||
listModel->setHeaderData(PeerListDelegate::IP, Qt::Horizontal, tr("IP"));
|
||||
listModel->setHeaderData(PeerListDelegate::CONNECTION, Qt::Horizontal, tr("Connection"));
|
||||
listModel->setHeaderData(PeerListDelegate::CLIENT, Qt::Horizontal, tr("Client", "i.e.: Client application"));
|
||||
listModel->setHeaderData(PeerListDelegate::PROGRESS, Qt::Horizontal, tr("Progress", "i.e: % downloaded"));
|
||||
listModel->setHeaderData(PeerListDelegate::DOWN_SPEED, Qt::Horizontal, tr("Down Speed", "i.e: Download speed"));
|
||||
listModel->setHeaderData(PeerListDelegate::UP_SPEED, Qt::Horizontal, tr("Up Speed", "i.e: Upload speed"));
|
||||
listModel->setHeaderData(PeerListDelegate::TOT_DOWN, Qt::Horizontal, tr("Downloaded", "i.e: total data downloaded"));
|
||||
listModel->setHeaderData(PeerListDelegate::TOT_UP, Qt::Horizontal, tr("Uploaded", "i.e: total data uploaded"));
|
||||
// Proxy model to support sorting without actually altering the underlying model
|
||||
proxyModel = new QSortFilterProxyModel();
|
||||
proxyModel->setDynamicSortFilter(true);
|
||||
proxyModel->setSourceModel(listModel);
|
||||
setModel(proxyModel);
|
||||
hideColumn(PeerListDelegate::IP_HIDDEN);
|
||||
// Context menu
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showPeerListMenu(QPoint)));
|
||||
// List delegate
|
||||
listDelegate = new PeerListDelegate(this);
|
||||
setItemDelegate(listDelegate);
|
||||
// Enable sorting
|
||||
setSortingEnabled(true);
|
||||
// IP to Hostname resolver
|
||||
updatePeerHostNameResolutionState();
|
||||
// SIGNAL/SLOT
|
||||
connect(header(), SIGNAL(sectionClicked(int)), SLOT(handleSortColumnChanged(int)));
|
||||
handleSortColumnChanged(header()->sortIndicatorSection());
|
||||
}
|
||||
|
||||
PeerListWidget::~PeerListWidget() {
|
||||
saveSettings();
|
||||
delete proxyModel;
|
||||
delete listModel;
|
||||
delete listDelegate;
|
||||
if(resolver)
|
||||
delete resolver;
|
||||
}
|
||||
|
||||
void PeerListWidget::updatePeerHostNameResolutionState() {
|
||||
if(Preferences().resolvePeerHostNames()) {
|
||||
if(!resolver) {
|
||||
resolver = new ReverseResolution(this);
|
||||
connect(resolver, SIGNAL(ip_resolved(QString,QString)), this, SLOT(handleResolved(QString,QString)));
|
||||
loadPeers(properties->getCurrentTorrent(), true);
|
||||
}
|
||||
} else {
|
||||
if(resolver) {
|
||||
delete resolver;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListWidget::updatePeerCountryResolutionState() {
|
||||
if(Preferences().resolvePeerCountries() != display_flags) {
|
||||
display_flags = !display_flags;
|
||||
if(display_flags) {
|
||||
const QTorrentHandle h = properties->getCurrentTorrent();
|
||||
if(!h.is_valid()) return;
|
||||
loadPeers(h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListWidget::showPeerListMenu(QPoint) {
|
||||
QMenu menu;
|
||||
bool empty_menu = true;
|
||||
QTorrentHandle h = properties->getCurrentTorrent();
|
||||
if(!h.is_valid()) return;
|
||||
QModelIndexList selectedIndexes = selectionModel()->selectedRows();
|
||||
QStringList selectedPeerIPs;
|
||||
foreach(const QModelIndex &index, selectedIndexes) {
|
||||
int row = proxyModel->mapToSource(index).row();
|
||||
QString myip = listModel->data(listModel->index(row, PeerListDelegate::IP_HIDDEN)).toString();
|
||||
selectedPeerIPs << myip;
|
||||
}
|
||||
// Add Peer Action
|
||||
QAction *addPeerAct = 0;
|
||||
if(!h.is_queued() && !h.is_checking()) {
|
||||
addPeerAct = menu.addAction(IconProvider::instance()->getIcon("user-group-new"), tr("Add a new peer..."));
|
||||
empty_menu = false;
|
||||
}
|
||||
// Per Peer Speed limiting actions
|
||||
QAction *upLimitAct = 0;
|
||||
QAction *dlLimitAct = 0;
|
||||
QAction *banAct = 0;
|
||||
QAction *copyIPAct = 0;
|
||||
if(!selectedPeerIPs.isEmpty()) {
|
||||
copyIPAct = menu.addAction(IconProvider::instance()->getIcon("edit-copy"), tr("Copy IP"));
|
||||
menu.addSeparator();
|
||||
dlLimitAct = menu.addAction(QIcon(":/Icons/skin/download.png"), tr("Limit download rate..."));
|
||||
upLimitAct = menu.addAction(QIcon(":/Icons/skin/seeding.png"), tr("Limit upload rate..."));
|
||||
menu.addSeparator();
|
||||
banAct = menu.addAction(IconProvider::instance()->getIcon("user-group-delete"), tr("Ban peer permanently"));
|
||||
empty_menu = false;
|
||||
}
|
||||
if(empty_menu) return;
|
||||
QAction *act = menu.exec(QCursor::pos());
|
||||
if(act == 0) return;
|
||||
if(act == addPeerAct) {
|
||||
libtorrent::asio::ip::tcp::endpoint ep = PeerAdditionDlg::askForPeerEndpoint();
|
||||
if(ep != libtorrent::asio::ip::tcp::endpoint()) {
|
||||
try {
|
||||
h.connect_peer(ep);
|
||||
QMessageBox::information(0, tr("Peer addition"), tr("The peer was added to this torrent."));
|
||||
} catch(std::exception) {
|
||||
QMessageBox::critical(0, tr("Peer addition"), tr("The peer could not be added to this torrent."));
|
||||
}
|
||||
} else {
|
||||
qDebug("No peer was added");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(act == upLimitAct) {
|
||||
limitUpRateSelectedPeers(selectedPeerIPs);
|
||||
return;
|
||||
}
|
||||
if(act == dlLimitAct) {
|
||||
limitDlRateSelectedPeers(selectedPeerIPs);
|
||||
return;
|
||||
}
|
||||
if(act == banAct) {
|
||||
banSelectedPeers(selectedPeerIPs);
|
||||
return;
|
||||
}
|
||||
if(act == copyIPAct) {
|
||||
#if defined(Q_WS_WIN) || defined(Q_OS_OS2)
|
||||
QApplication::clipboard()->setText(selectedPeerIPs.join("\r\n"));
|
||||
#else
|
||||
QApplication::clipboard()->setText(selectedPeerIPs.join("\n"));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListWidget::banSelectedPeers(QStringList peer_ips) {
|
||||
// Confirm first
|
||||
int ret = QMessageBox::question(this, tr("Are you sure? -- qBittorrent"), tr("Are you sure you want to ban permanently the selected peers?"),
|
||||
tr("&Yes"), tr("&No"),
|
||||
QString(), 0, 1);
|
||||
if(ret) return;
|
||||
foreach(const QString &ip, peer_ips) {
|
||||
qDebug("Banning peer %s...", ip.toLocal8Bit().data());
|
||||
QBtSession::instance()->addConsoleMessage(tr("Manually banning peer %1...").arg(ip));
|
||||
QBtSession::instance()->banIP(ip);
|
||||
}
|
||||
// Refresh list
|
||||
loadPeers(properties->getCurrentTorrent());
|
||||
}
|
||||
|
||||
void PeerListWidget::limitUpRateSelectedPeers(QStringList peer_ips) {
|
||||
if(peer_ips.empty()) return;
|
||||
QTorrentHandle h = properties->getCurrentTorrent();
|
||||
if(!h.is_valid()) return;
|
||||
bool ok=false;
|
||||
int cur_limit = -1;
|
||||
#if LIBTORRENT_VERSION_MINOR > 15
|
||||
libtorrent::asio::ip::tcp::endpoint first_ep = peerEndpoints.value(peer_ips.first(),
|
||||
libtorrent::asio::ip::tcp::endpoint());
|
||||
if(first_ep != libtorrent::asio::ip::tcp::endpoint())
|
||||
cur_limit = h.get_peer_upload_limit(first_ep);
|
||||
#endif
|
||||
long limit = SpeedLimitDialog::askSpeedLimit(&ok, tr("Upload rate limiting"), cur_limit, Preferences().getGlobalUploadLimit()*1024.);
|
||||
if(!ok) return;
|
||||
foreach(const QString &ip, peer_ips) {
|
||||
libtorrent::asio::ip::tcp::endpoint ep = peerEndpoints.value(ip, libtorrent::asio::ip::tcp::endpoint());
|
||||
if(ep != libtorrent::asio::ip::tcp::endpoint()) {
|
||||
qDebug("Settings Upload limit of %.1f Kb/s to peer %s", limit/1024., ip.toLocal8Bit().data());
|
||||
try {
|
||||
h.set_peer_upload_limit(ep, limit);
|
||||
}catch(std::exception) {
|
||||
std::cerr << "Impossible to apply upload limit to peer" << std::endl;
|
||||
}
|
||||
} else {
|
||||
qDebug("The selected peer no longer exists...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListWidget::limitDlRateSelectedPeers(QStringList peer_ips) {
|
||||
QTorrentHandle h = properties->getCurrentTorrent();
|
||||
if(!h.is_valid()) return;
|
||||
bool ok=false;
|
||||
int cur_limit = -1;
|
||||
#if LIBTORRENT_VERSION_MINOR > 15
|
||||
libtorrent::asio::ip::tcp::endpoint first_ep = peerEndpoints.value(peer_ips.first(),
|
||||
libtorrent::asio::ip::tcp::endpoint());
|
||||
if(first_ep != libtorrent::asio::ip::tcp::endpoint())
|
||||
cur_limit = h.get_peer_download_limit(first_ep);
|
||||
#endif
|
||||
long limit = SpeedLimitDialog::askSpeedLimit(&ok, tr("Download rate limiting"), cur_limit, Preferences().getGlobalDownloadLimit()*1024.);
|
||||
if(!ok) return;
|
||||
foreach(const QString &ip, peer_ips) {
|
||||
libtorrent::asio::ip::tcp::endpoint ep = peerEndpoints.value(ip, libtorrent::asio::ip::tcp::endpoint());
|
||||
if(ep != libtorrent::asio::ip::tcp::endpoint()) {
|
||||
qDebug("Settings Download limit of %.1f Kb/s to peer %s", limit/1024., ip.toLocal8Bit().data());
|
||||
try {
|
||||
h.set_peer_download_limit(ep, limit);
|
||||
}catch(std::exception) {
|
||||
std::cerr << "Impossible to apply download limit to peer" << std::endl;
|
||||
}
|
||||
} else {
|
||||
qDebug("The selected peer no longer exists...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PeerListWidget::clear() {
|
||||
qDebug("clearing peer list");
|
||||
peerItems.clear();
|
||||
peerEndpoints.clear();
|
||||
missingFlags.clear();
|
||||
int nbrows = listModel->rowCount();
|
||||
if(nbrows > 0) {
|
||||
qDebug("Cleared %d peers", nbrows);
|
||||
listModel->removeRows(0, nbrows);
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListWidget::loadSettings() {
|
||||
QIniSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
|
||||
header()->restoreState(settings.value("TorrentProperties/Peers/PeerListState").toByteArray());
|
||||
}
|
||||
|
||||
void PeerListWidget::saveSettings() const {
|
||||
QIniSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
|
||||
settings.setValue("TorrentProperties/Peers/PeerListState", header()->saveState());
|
||||
}
|
||||
|
||||
void PeerListWidget::loadPeers(const QTorrentHandle &h, bool force_hostname_resolution) {
|
||||
if(!h.is_valid()) return;
|
||||
boost::system::error_code ec;
|
||||
std::vector<peer_info> peers;
|
||||
h.get_peer_info(peers);
|
||||
std::vector<peer_info>::iterator itr;
|
||||
QSet<QString> old_peers_set = peerItems.keys().toSet();
|
||||
for(itr = peers.begin(); itr != peers.end(); itr++) {
|
||||
peer_info peer = *itr;
|
||||
QString peer_ip = misc::toQString(peer.ip.address().to_string(ec));
|
||||
if(ec) continue;
|
||||
if(peerItems.contains(peer_ip)) {
|
||||
// Update existing peer
|
||||
updatePeer(peer_ip, peer);
|
||||
old_peers_set.remove(peer_ip);
|
||||
if(force_hostname_resolution) {
|
||||
if(resolver) {
|
||||
const QString host = resolver->getHostFromCache(peer.ip);
|
||||
if(host.isNull()) {
|
||||
resolver->resolve(peer.ip);
|
||||
} else {
|
||||
qDebug("Got peer IP from cache");
|
||||
handleResolved(peer_ip, host);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Add new peer
|
||||
peerItems[peer_ip] = addPeer(peer_ip, peer);
|
||||
peerEndpoints[peer_ip] = peer.ip;
|
||||
}
|
||||
}
|
||||
// Delete peers that are gone
|
||||
QSetIterator<QString> it(old_peers_set);
|
||||
while(it.hasNext()) {
|
||||
QString ip = it.next();
|
||||
missingFlags.remove(ip);
|
||||
peerEndpoints.remove(ip);
|
||||
QStandardItem *item = peerItems.take(ip);
|
||||
listModel->removeRow(item->row());
|
||||
}
|
||||
}
|
||||
|
||||
QStandardItem* PeerListWidget::addPeer(QString ip, peer_info peer) {
|
||||
int row = listModel->rowCount();
|
||||
// Adding Peer to peer list
|
||||
listModel->insertRow(row);
|
||||
QString host;
|
||||
if(resolver) {
|
||||
host = resolver->getHostFromCache(peer.ip);
|
||||
}
|
||||
if(host.isNull())
|
||||
listModel->setData(listModel->index(row, PeerListDelegate::IP), ip);
|
||||
else
|
||||
listModel->setData(listModel->index(row, PeerListDelegate::IP), host);
|
||||
listModel->setData(listModel->index(row, PeerListDelegate::IP_HIDDEN), ip);
|
||||
// Resolve peer host name is asked
|
||||
if(resolver && host.isNull())
|
||||
resolver->resolve(peer.ip);
|
||||
if(display_flags) {
|
||||
const QIcon ico = GeoIPManager::CountryISOCodeToIcon(peer.country);
|
||||
if(!ico.isNull()) {
|
||||
listModel->setData(listModel->index(row, PeerListDelegate::IP), ico, Qt::DecorationRole);
|
||||
const QString country_name = GeoIPManager::CountryISOCodeToName(peer.country);
|
||||
listModel->setData(listModel->index(row, PeerListDelegate::IP), country_name, Qt::ToolTipRole);
|
||||
} else {
|
||||
missingFlags.insert(ip);
|
||||
}
|
||||
}
|
||||
listModel->setData(listModel->index(row, PeerListDelegate::CONNECTION), getConnectionString(peer.connection_type));
|
||||
listModel->setData(listModel->index(row, PeerListDelegate::CLIENT), misc::toQStringU(peer.client));
|
||||
listModel->setData(listModel->index(row, PeerListDelegate::PROGRESS), peer.progress);
|
||||
listModel->setData(listModel->index(row, PeerListDelegate::DOWN_SPEED), peer.payload_down_speed);
|
||||
listModel->setData(listModel->index(row, PeerListDelegate::UP_SPEED), peer.payload_up_speed);
|
||||
listModel->setData(listModel->index(row, PeerListDelegate::TOT_DOWN), (qulonglong)peer.total_download);
|
||||
listModel->setData(listModel->index(row, PeerListDelegate::TOT_UP), (qulonglong)peer.total_upload);
|
||||
return listModel->item(row, PeerListDelegate::IP);
|
||||
}
|
||||
|
||||
void PeerListWidget::updatePeer(QString ip, peer_info peer) {
|
||||
QStandardItem *item = peerItems.value(ip);
|
||||
int row = item->row();
|
||||
if(display_flags) {
|
||||
const QIcon ico = GeoIPManager::CountryISOCodeToIcon(peer.country);
|
||||
if(!ico.isNull()) {
|
||||
listModel->setData(listModel->index(row, PeerListDelegate::IP), ico, Qt::DecorationRole);
|
||||
const QString country_name = GeoIPManager::CountryISOCodeToName(peer.country);
|
||||
listModel->setData(listModel->index(row, PeerListDelegate::IP), country_name, Qt::ToolTipRole);
|
||||
missingFlags.remove(ip);
|
||||
}
|
||||
}
|
||||
listModel->setData(listModel->index(row, PeerListDelegate::CONNECTION), getConnectionString(peer.connection_type));
|
||||
listModel->setData(listModel->index(row, PeerListDelegate::CLIENT), misc::toQStringU(peer.client));
|
||||
listModel->setData(listModel->index(row, PeerListDelegate::PROGRESS), peer.progress);
|
||||
listModel->setData(listModel->index(row, PeerListDelegate::DOWN_SPEED), peer.payload_down_speed);
|
||||
listModel->setData(listModel->index(row, PeerListDelegate::UP_SPEED), peer.payload_up_speed);
|
||||
listModel->setData(listModel->index(row, PeerListDelegate::TOT_DOWN), (qulonglong)peer.total_download);
|
||||
listModel->setData(listModel->index(row, PeerListDelegate::TOT_UP), (qulonglong)peer.total_upload);
|
||||
}
|
||||
|
||||
void PeerListWidget::handleResolved(const QString &ip, const QString &hostname) {
|
||||
QStandardItem *item = peerItems.value(ip, 0);
|
||||
if(item) {
|
||||
qDebug("Resolved %s -> %s", qPrintable(ip), qPrintable(hostname));
|
||||
item->setData(hostname, Qt::DisplayRole);
|
||||
//listModel->setData(listModel->index(item->row(), IP), hostname, Qt::DisplayRole);
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListWidget::handleSortColumnChanged(int col)
|
||||
{
|
||||
if(col == 0) {
|
||||
qDebug("Sorting by decoration");
|
||||
proxyModel->setSortRole(Qt::ToolTipRole);
|
||||
} else {
|
||||
proxyModel->setSortRole(Qt::DisplayRole);
|
||||
}
|
||||
}
|
||||
|
||||
QString PeerListWidget::getConnectionString(int connection_type)
|
||||
{
|
||||
QString connection;
|
||||
switch(connection_type) {
|
||||
#if LIBTORRENT_VERSION_MINOR > 15
|
||||
case peer_info::bittorrent_utp:
|
||||
connection = "uTP";
|
||||
break;
|
||||
case peer_info::http_seed:
|
||||
#endif
|
||||
case peer_info::web_seed:
|
||||
connection = "Web";
|
||||
break;
|
||||
default:
|
||||
connection = "BT";
|
||||
break;
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
100
src/properties/peerlistwidget.h
Normal file
100
src/properties/peerlistwidget.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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 PEERLISTWIDGET_H
|
||||
#define PEERLISTWIDGET_H
|
||||
|
||||
#include <QTreeView>
|
||||
#include <QHash>
|
||||
#include <QPointer>
|
||||
#include <QSet>
|
||||
#include <libtorrent/peer_info.hpp>
|
||||
#include "qtorrenthandle.h"
|
||||
#include "misc.h"
|
||||
|
||||
class PeerListDelegate;
|
||||
class ReverseResolution;
|
||||
class PropertiesWidget;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QSortFilterProxyModel;
|
||||
class QStandardItem;
|
||||
class QStandardItemModel;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#include <boost/version.hpp>
|
||||
#if BOOST_VERSION < 103500
|
||||
#include <libtorrent/asio/ip/tcp.hpp>
|
||||
#else
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#endif
|
||||
|
||||
class PeerListWidget : public QTreeView {
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(PeerListWidget)
|
||||
|
||||
public:
|
||||
PeerListWidget(PropertiesWidget *parent);
|
||||
~PeerListWidget();
|
||||
|
||||
public slots:
|
||||
void loadPeers(const QTorrentHandle &h, bool force_hostname_resolution=false);
|
||||
QStandardItem* addPeer(QString ip, libtorrent::peer_info peer);
|
||||
void updatePeer(QString ip, libtorrent::peer_info peer);
|
||||
void handleResolved(const QString &ip, const QString &hostname);
|
||||
void updatePeerHostNameResolutionState();
|
||||
void updatePeerCountryResolutionState();
|
||||
void clear();
|
||||
|
||||
protected slots:
|
||||
void loadSettings();
|
||||
void saveSettings() const;
|
||||
void showPeerListMenu(QPoint);
|
||||
void limitUpRateSelectedPeers(QStringList peer_ips);
|
||||
void limitDlRateSelectedPeers(QStringList peer_ips);
|
||||
void banSelectedPeers(QStringList peer_ips);
|
||||
void handleSortColumnChanged(int col);
|
||||
|
||||
private:
|
||||
static QString getConnectionString(int connection_type);
|
||||
|
||||
private:
|
||||
QStandardItemModel *listModel;
|
||||
PeerListDelegate *listDelegate;
|
||||
QSortFilterProxyModel * proxyModel;
|
||||
QHash<QString, QStandardItem*> peerItems;
|
||||
QHash<QString, libtorrent::asio::ip::tcp::endpoint> peerEndpoints;
|
||||
QSet<QString> missingFlags;
|
||||
QPointer<ReverseResolution> resolver;
|
||||
PropertiesWidget* properties;
|
||||
bool display_flags;
|
||||
};
|
||||
|
||||
#endif // PEERLISTWIDGET_H
|
||||
117
src/properties/pieceavailabilitybar.h
Normal file
117
src/properties/pieceavailabilitybar.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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 PIECEAVAILABILITYBAR_H
|
||||
#define PIECEAVAILABILITYBAR_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QPainter>
|
||||
#include <QPixmap>
|
||||
#include <QColor>
|
||||
#include <numeric>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
#define BAR_HEIGHT 18
|
||||
|
||||
class PieceAvailabilityBar: public QWidget {
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(PieceAvailabilityBar)
|
||||
|
||||
private:
|
||||
QPixmap pixmap;
|
||||
|
||||
public:
|
||||
PieceAvailabilityBar(QWidget *parent): QWidget(parent) {
|
||||
setFixedHeight(BAR_HEIGHT);
|
||||
}
|
||||
|
||||
void setAvailability(const std::vector<int>& avail) {
|
||||
if(avail.empty()) {
|
||||
// Empty bar
|
||||
QPixmap pix = QPixmap(1, 1);
|
||||
pix.fill();
|
||||
pixmap = pix;
|
||||
} else {
|
||||
// Reduce the number of pieces before creating the pixmap
|
||||
// otherwise it can crash when there are too many pieces
|
||||
const qulonglong nb_pieces = avail.size();
|
||||
const uint w = width();
|
||||
if(nb_pieces > w) {
|
||||
const qulonglong ratio = floor(nb_pieces/(double)w);
|
||||
std::vector<int> scaled_avail;
|
||||
scaled_avail.reserve(ceil(nb_pieces/(double)ratio));
|
||||
for(qulonglong i=0; i<nb_pieces; i+= ratio) {
|
||||
// XXX: Do not compute the average to save cpu
|
||||
scaled_avail.push_back(avail[i]);
|
||||
}
|
||||
updatePixmap(scaled_avail);
|
||||
} else {
|
||||
updatePixmap(avail);
|
||||
}
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
pixmap = QPixmap();
|
||||
update();
|
||||
}
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *) {
|
||||
if(pixmap.isNull()) return;
|
||||
QPainter painter(this);
|
||||
painter.drawPixmap(rect(), pixmap);
|
||||
}
|
||||
|
||||
private:
|
||||
void updatePixmap(const std::vector<int> avail) {
|
||||
const int max = *std::max_element(avail.begin(), avail.end());
|
||||
if(max == 0) {
|
||||
QPixmap pix = QPixmap(1, 1);
|
||||
pix.fill();
|
||||
pixmap = pix;
|
||||
return;
|
||||
}
|
||||
QPixmap pix = QPixmap(avail.size(), 1);
|
||||
//pix.fill();
|
||||
QPainter painter(&pix);
|
||||
for(uint i=0; i < avail.size(); ++i) {
|
||||
const uint rg = 0xff - (0xff * avail[i]/max);
|
||||
painter.setPen(QColor(rg, rg, 0xff));
|
||||
painter.drawPoint(i,0);
|
||||
}
|
||||
pixmap = pix;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // PIECEAVAILABILITYBAR_H
|
||||
22
src/properties/properties.pri
Normal file
22
src/properties/properties.pri
Normal file
@@ -0,0 +1,22 @@
|
||||
INCLUDEPATH += $$PWD
|
||||
|
||||
FORMS += $$PWD/propertieswidget.ui \
|
||||
$$PWD/trackersadditiondlg.ui \
|
||||
$$PWD/peer.ui
|
||||
|
||||
HEADERS += $$PWD/propertieswidget.h \
|
||||
$$PWD/peerlistwidget.h \
|
||||
$$PWD/proplistdelegate.h \
|
||||
$$PWD/trackerlist.h \
|
||||
$$PWD/downloadedpiecesbar.h \
|
||||
$$PWD/peerlistdelegate.h \
|
||||
$$PWD/peeraddition.h \
|
||||
$$PWD/trackersadditiondlg.h \
|
||||
$$PWD/pieceavailabilitybar.h \
|
||||
$$PWD/proptabbar.h
|
||||
|
||||
SOURCES += $$PWD/propertieswidget.cpp \
|
||||
$$PWD/peerlistwidget.cpp \
|
||||
$$PWD/trackerlist.cpp \
|
||||
$$PWD/proptabbar.cpp
|
||||
|
||||
731
src/properties/propertieswidget.cpp
Normal file
731
src/properties/propertieswidget.cpp
Normal file
@@ -0,0 +1,731 @@
|
||||
/*
|
||||
* 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 <QTimer>
|
||||
#include <QListWidgetItem>
|
||||
#include <QVBoxLayout>
|
||||
#include <QStackedWidget>
|
||||
#include <QSplitter>
|
||||
#include <QHeaderView>
|
||||
#include <QAction>
|
||||
#include <QMessageBox>
|
||||
#include <QMenu>
|
||||
#include <QFileDialog>
|
||||
#include <QDesktopServices>
|
||||
#include <QInputDialog>
|
||||
#include <libtorrent/version.hpp>
|
||||
#include "propertieswidget.h"
|
||||
#include "transferlistwidget.h"
|
||||
#include "torrentpersistentdata.h"
|
||||
#include "qbtsession.h"
|
||||
#include "proplistdelegate.h"
|
||||
#include "torrentfilesmodel.h"
|
||||
#include "peerlistwidget.h"
|
||||
#include "trackerlist.h"
|
||||
#include "mainwindow.h"
|
||||
#include "downloadedpiecesbar.h"
|
||||
#include "pieceavailabilitybar.h"
|
||||
#include "qinisettings.h"
|
||||
#include "proptabbar.h"
|
||||
#include "iconprovider.h"
|
||||
#include "lineedit.h"
|
||||
|
||||
using namespace libtorrent;
|
||||
|
||||
PropertiesWidget::PropertiesWidget(QWidget *parent, MainWindow* main_window, TransferListWidget *transferList):
|
||||
QWidget(parent), transferList(transferList), main_window(main_window) {
|
||||
setupUi(this);
|
||||
|
||||
// Icons
|
||||
deleteWS_button->setIcon(IconProvider::instance()->getIcon("list-remove"));
|
||||
addWS_button->setIcon(IconProvider::instance()->getIcon("list-add"));
|
||||
trackerUpButton->setIcon(IconProvider::instance()->getIcon("go-up"));
|
||||
trackerDownButton->setIcon(IconProvider::instance()->getIcon("go-down"));
|
||||
|
||||
state = VISIBLE;
|
||||
setEnabled(false);
|
||||
|
||||
// Set Properties list model
|
||||
PropListModel = new TorrentFilesFilterModel();
|
||||
filesList->setModel(PropListModel);
|
||||
PropDelegate = new PropListDelegate(this);
|
||||
filesList->setItemDelegate(PropDelegate);
|
||||
filesList->setSortingEnabled(true);
|
||||
// Torrent content filtering
|
||||
m_contentFilerLine = new LineEdit(this);
|
||||
connect(m_contentFilerLine, SIGNAL(textChanged(QString)), PropListModel, SLOT(setFilterFixedString(QString)));
|
||||
contentFilterLayout->insertWidget(1, m_contentFilerLine);
|
||||
|
||||
// SIGNAL/SLOTS
|
||||
connect(filesList, SIGNAL(clicked(const QModelIndex&)), filesList, SLOT(edit(const QModelIndex&)));
|
||||
connect(selectAllButton, SIGNAL(clicked()), PropListModel, SLOT(selectAll()));
|
||||
connect(selectNoneButton, SIGNAL(clicked()), PropListModel, SLOT(selectNone()));
|
||||
connect(filesList, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayFilesListMenu(const QPoint&)));
|
||||
connect(filesList, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(openDoubleClickedFile(QModelIndex)));
|
||||
connect(PropListModel, SIGNAL(filteredFilesChanged()), this, SLOT(filteredFilesChanged()));
|
||||
connect(addWS_button, SIGNAL(clicked()), this, SLOT(askWebSeed()));
|
||||
connect(deleteWS_button, SIGNAL(clicked()), this, SLOT(deleteSelectedUrlSeeds()));
|
||||
connect(transferList, SIGNAL(currentTorrentChanged(QTorrentHandle)), this, SLOT(loadTorrentInfos(QTorrentHandle)));
|
||||
connect(PropDelegate, SIGNAL(filteredFilesChanged()), this, SLOT(filteredFilesChanged()));
|
||||
connect(stackedProperties, SIGNAL(currentChanged(int)), this, SLOT(loadDynamicData()));
|
||||
connect(QBtSession::instance(), SIGNAL(savePathChanged(QTorrentHandle)), this, SLOT(updateSavePath(QTorrentHandle)));
|
||||
connect(QBtSession::instance(), SIGNAL(metadataReceived(QTorrentHandle)), this, SLOT(updateTorrentInfos(QTorrentHandle)));
|
||||
|
||||
// Downloaded pieces progress bar
|
||||
downloaded_pieces = new DownloadedPiecesBar(this);
|
||||
ProgressHLayout->insertWidget(1, downloaded_pieces);
|
||||
// Pieces availability bar
|
||||
pieces_availability = new PieceAvailabilityBar(this);
|
||||
ProgressHLayout_2->insertWidget(1, pieces_availability);
|
||||
// Tracker list
|
||||
trackerList = new TrackerList(this);
|
||||
#if LIBTORRENT_VERSION_MINOR > 14
|
||||
trackerUpButton->setVisible(false);
|
||||
trackerDownButton->setVisible(false);
|
||||
#else
|
||||
connect(trackerUpButton, SIGNAL(clicked()), trackerList, SLOT(moveSelectionUp()));
|
||||
connect(trackerDownButton, SIGNAL(clicked()), trackerList, SLOT(moveSelectionDown()));
|
||||
#endif
|
||||
horizontalLayout_trackers->insertWidget(0, trackerList);
|
||||
// Peers list
|
||||
peersList = new PeerListWidget(this);
|
||||
peerpage_layout->addWidget(peersList);
|
||||
// Tab bar
|
||||
m_tabBar = new PropTabBar();
|
||||
verticalLayout->addLayout(m_tabBar);
|
||||
connect(m_tabBar, SIGNAL(tabChanged(int)), stackedProperties, SLOT(setCurrentIndex(int)));
|
||||
connect(m_tabBar, SIGNAL(visibilityToggled(bool)), SLOT(setVisibility(bool)));
|
||||
// Dynamic data refresher
|
||||
refreshTimer = new QTimer(this);
|
||||
connect(refreshTimer, SIGNAL(timeout()), this, SLOT(loadDynamicData()));
|
||||
refreshTimer->start(3000); // 3sec
|
||||
}
|
||||
|
||||
PropertiesWidget::~PropertiesWidget() {
|
||||
qDebug() << Q_FUNC_INFO << "ENTER";
|
||||
delete refreshTimer;
|
||||
delete trackerList;
|
||||
delete peersList;
|
||||
delete downloaded_pieces;
|
||||
delete pieces_availability;
|
||||
delete PropListModel;
|
||||
delete PropDelegate;
|
||||
delete m_tabBar;
|
||||
qDebug() << Q_FUNC_INFO << "EXIT";
|
||||
}
|
||||
|
||||
void PropertiesWidget::showPiecesAvailability(bool show) {
|
||||
avail_pieces_lbl->setVisible(show);
|
||||
pieces_availability->setVisible(show);
|
||||
avail_average_lbl->setVisible(show);
|
||||
if(show || (!show && !downloaded_pieces->isVisible()))
|
||||
line_2->setVisible(show);
|
||||
}
|
||||
|
||||
void PropertiesWidget::showPiecesDownloaded(bool show) {
|
||||
downloaded_pieces_lbl->setVisible(show);
|
||||
downloaded_pieces->setVisible(show);
|
||||
progress_lbl->setVisible(show);
|
||||
if(show || (!show && !pieces_availability->isVisible()))
|
||||
line_2->setVisible(show);
|
||||
}
|
||||
|
||||
void PropertiesWidget::setVisibility(bool visible) {
|
||||
if(!visible && state == VISIBLE) {
|
||||
QSplitter *hSplitter = static_cast<QSplitter*>(parentWidget());
|
||||
stackedProperties->setVisible(false);
|
||||
slideSizes = hSplitter->sizes();
|
||||
hSplitter->handle(1)->setVisible(false);
|
||||
hSplitter->handle(1)->setDisabled(true);
|
||||
QList<int> sizes = QList<int>() << hSplitter->geometry().height()-30 << 30;
|
||||
hSplitter->setSizes(sizes);
|
||||
state = REDUCED;
|
||||
return;
|
||||
}
|
||||
|
||||
if(visible && state == REDUCED) {
|
||||
stackedProperties->setVisible(true);
|
||||
QSplitter *hSplitter = static_cast<QSplitter*>(parentWidget());
|
||||
hSplitter->handle(1)->setDisabled(false);
|
||||
hSplitter->handle(1)->setVisible(true);
|
||||
hSplitter->setSizes(slideSizes);
|
||||
state = VISIBLE;
|
||||
// Force refresh
|
||||
loadDynamicData();
|
||||
}
|
||||
}
|
||||
|
||||
void PropertiesWidget::clear() {
|
||||
qDebug("Clearing torrent properties");
|
||||
save_path->clear();
|
||||
lbl_creationDate->clear();
|
||||
pieceSize_lbl->clear();
|
||||
hash_lbl->clear();
|
||||
comment_text->clear();
|
||||
progress_lbl->clear();
|
||||
trackerList->clear();
|
||||
downloaded_pieces->clear();
|
||||
pieces_availability->clear();
|
||||
avail_average_lbl->clear();
|
||||
wasted->clear();
|
||||
upTotal->clear();
|
||||
dlTotal->clear();
|
||||
peersList->clear();
|
||||
lbl_uplimit->clear();
|
||||
lbl_dllimit->clear();
|
||||
lbl_elapsed->clear();
|
||||
lbl_connections->clear();
|
||||
reannounce_lbl->clear();
|
||||
shareRatio->clear();
|
||||
listWebSeeds->clear();
|
||||
m_contentFilerLine->clear();
|
||||
PropListModel->model()->clear();
|
||||
showPiecesAvailability(false);
|
||||
showPiecesDownloaded(false);
|
||||
setEnabled(false);
|
||||
}
|
||||
|
||||
QTorrentHandle PropertiesWidget::getCurrentTorrent() const {
|
||||
return h;
|
||||
}
|
||||
|
||||
void PropertiesWidget::updateSavePath(const QTorrentHandle& _h) {
|
||||
if(h.is_valid() && h == _h) {
|
||||
QString p;
|
||||
if(h.has_metadata() && h.num_files() == 1) {
|
||||
p = h.firstFileSavePath();
|
||||
} else {
|
||||
p = TorrentPersistentData::getSavePath(h.hash());
|
||||
if(p.isEmpty())
|
||||
p = h.save_path();
|
||||
}
|
||||
#if defined(Q_WS_WIN) || defined(Q_OS_OS2)
|
||||
p = p.replace("/", "\\");
|
||||
#endif
|
||||
save_path->setText(p);
|
||||
}
|
||||
}
|
||||
|
||||
void PropertiesWidget::updateTorrentInfos(const QTorrentHandle& _h) {
|
||||
if(h.is_valid() && h == _h) {
|
||||
loadTorrentInfos(h);
|
||||
}
|
||||
}
|
||||
|
||||
void PropertiesWidget::loadTorrentInfos(const QTorrentHandle &_h) {
|
||||
clear();
|
||||
h = _h;
|
||||
if(!h.is_valid()) {
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
setEnabled(true);
|
||||
|
||||
try {
|
||||
// Save path
|
||||
updateSavePath(h);
|
||||
changeSavePathButton->setEnabled(h.has_metadata());
|
||||
// Hash
|
||||
hash_lbl->setText(h.hash());
|
||||
PropListModel->model()->clear();
|
||||
if(h.has_metadata()) {
|
||||
// Creation date
|
||||
lbl_creationDate->setText(h.creation_date());
|
||||
// Pieces size
|
||||
pieceSize_lbl->setText(misc::friendlyUnit(h.piece_length()));
|
||||
// Comment
|
||||
comment_text->setHtml(misc::parseHtmlLinks(h.comment()));
|
||||
// URL seeds
|
||||
loadUrlSeeds();
|
||||
// List files in torrent
|
||||
PropListModel->model()->setupModelData(h.get_torrent_info());
|
||||
}
|
||||
} catch(invalid_handle& e) {
|
||||
|
||||
}
|
||||
// Load dynamic data
|
||||
loadDynamicData();
|
||||
}
|
||||
|
||||
void PropertiesWidget::readSettings() {
|
||||
QIniSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
|
||||
// Restore splitter sizes
|
||||
QStringList sizes_str = settings.value(QString::fromUtf8("TorrentProperties/SplitterSizes"), QString()).toString().split(",");
|
||||
if(sizes_str.size() == 2) {
|
||||
slideSizes << sizes_str.first().toInt();
|
||||
slideSizes << sizes_str.last().toInt();
|
||||
QSplitter *hSplitter = static_cast<QSplitter*>(parentWidget());
|
||||
hSplitter->setSizes(slideSizes);
|
||||
}
|
||||
if (!filesList->header()->restoreState(settings.value("TorrentProperties/FilesListState").toByteArray())) {
|
||||
filesList->header()->resizeSection(0, 400); //Default
|
||||
}
|
||||
const int current_tab = settings.value("TorrentProperties/CurrentTab", -1).toInt();
|
||||
m_tabBar->setCurrentIndex(current_tab);
|
||||
if(!settings.value("TorrentProperties/Visible", false).toBool()) {
|
||||
setVisibility(false);
|
||||
}
|
||||
}
|
||||
|
||||
void PropertiesWidget::saveSettings() {
|
||||
QIniSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
|
||||
settings.setValue("TorrentProperties/Visible", state==VISIBLE);
|
||||
// Splitter sizes
|
||||
QSplitter *hSplitter = static_cast<QSplitter*>(parentWidget());
|
||||
QList<int> sizes;
|
||||
if(state == VISIBLE)
|
||||
sizes = hSplitter->sizes();
|
||||
else
|
||||
sizes = slideSizes;
|
||||
qDebug("Sizes: %d", sizes.size());
|
||||
if(sizes.size() == 2) {
|
||||
settings.setValue(QString::fromUtf8("TorrentProperties/SplitterSizes"), QVariant(QString::number(sizes.first())+','+QString::number(sizes.last())));
|
||||
}
|
||||
settings.setValue("TorrentProperties/FilesListState", filesList->header()->saveState());
|
||||
// Remember current tab
|
||||
settings.setValue("TorrentProperties/CurrentTab", m_tabBar->currentIndex());
|
||||
}
|
||||
|
||||
void PropertiesWidget::reloadPreferences() {
|
||||
// Take program preferences into consideration
|
||||
peersList->updatePeerHostNameResolutionState();
|
||||
peersList->updatePeerCountryResolutionState();
|
||||
}
|
||||
|
||||
void PropertiesWidget::loadDynamicData() {
|
||||
// Refresh only if the torrent handle is valid and if visible
|
||||
if(!h.is_valid() || main_window->getCurrentTabWidget() != transferList || state != VISIBLE) return;
|
||||
try {
|
||||
// Transfer infos
|
||||
if(stackedProperties->currentIndex() == PropTabBar::MAIN_TAB) {
|
||||
wasted->setText(misc::friendlyUnit(h.total_failed_bytes()+h.total_redundant_bytes()));
|
||||
upTotal->setText(misc::friendlyUnit(h.all_time_upload()) + " ("+misc::friendlyUnit(h.total_payload_upload())+" "+tr("this session")+")");
|
||||
dlTotal->setText(misc::friendlyUnit(h.all_time_download()) + " ("+misc::friendlyUnit(h.total_payload_download())+" "+tr("this session")+")");
|
||||
if(h.upload_limit() <= 0)
|
||||
lbl_uplimit->setText(QString::fromUtf8("∞"));
|
||||
else
|
||||
lbl_uplimit->setText(misc::friendlyUnit(h.upload_limit())+tr("/s", "/second (i.e. per second)"));
|
||||
if(h.download_limit() <= 0)
|
||||
lbl_dllimit->setText(QString::fromUtf8("∞"));
|
||||
else
|
||||
lbl_dllimit->setText(misc::friendlyUnit(h.download_limit())+tr("/s", "/second (i.e. per second)"));
|
||||
QString elapsed_txt = misc::userFriendlyDuration(h.active_time());
|
||||
if(h.is_seed()) {
|
||||
elapsed_txt += " ("+tr("Seeded for %1", "e.g. Seeded for 3m10s").arg(misc::userFriendlyDuration(h.seeding_time()))+")";
|
||||
}
|
||||
lbl_elapsed->setText(elapsed_txt);
|
||||
if(h.connections_limit() > 0)
|
||||
lbl_connections->setText(QString::number(h.num_connections())+" ("+tr("%1 max", "e.g. 10 max").arg(QString::number(h.connections_limit()))+")");
|
||||
else
|
||||
lbl_connections->setText(QString::number(h.num_connections()));
|
||||
// Update next announce time
|
||||
reannounce_lbl->setText(h.next_announce());
|
||||
// Update ratio info
|
||||
const qreal ratio = QBtSession::instance()->getRealRatio(h.hash());
|
||||
if(ratio > QBtSession::MAX_RATIO)
|
||||
shareRatio->setText(QString::fromUtf8("∞"));
|
||||
else
|
||||
shareRatio->setText(QString(QByteArray::number(ratio, 'f', 2)));
|
||||
if(!h.is_seed()) {
|
||||
showPiecesDownloaded(true);
|
||||
// Downloaded pieces
|
||||
bitfield bf(h.get_torrent_info().num_pieces(), 0);
|
||||
h.downloading_pieces(bf);
|
||||
downloaded_pieces->setProgress(h.pieces(), bf);
|
||||
// Pieces availability
|
||||
if(h.has_metadata() && !h.is_paused() && !h.is_queued() && !h.is_checking()) {
|
||||
showPiecesAvailability(true);
|
||||
std::vector<int> avail;
|
||||
h.piece_availability(avail);
|
||||
pieces_availability->setAvailability(avail);
|
||||
avail_average_lbl->setText(QString::number(h.distributed_copies(), 'f', 3));
|
||||
} else {
|
||||
showPiecesAvailability(false);
|
||||
}
|
||||
// Progress
|
||||
qreal progress = h.progress()*100.;
|
||||
if(progress > 99.94 && progress < 100.)
|
||||
progress = 99.9;
|
||||
progress_lbl->setText(QString::number(progress, 'f', 1)+"%");
|
||||
} else {
|
||||
showPiecesAvailability(false);
|
||||
showPiecesDownloaded(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(stackedProperties->currentIndex() == PropTabBar::TRACKERS_TAB) {
|
||||
// Trackers
|
||||
trackerList->loadTrackers();
|
||||
return;
|
||||
}
|
||||
if(stackedProperties->currentIndex() == PropTabBar::PEERS_TAB) {
|
||||
// Load peers
|
||||
peersList->loadPeers(h);
|
||||
return;
|
||||
}
|
||||
if(stackedProperties->currentIndex() == PropTabBar::FILES_TAB) {
|
||||
// Files progress
|
||||
if(h.is_valid() && h.has_metadata()) {
|
||||
qDebug("Updating priorities in files tab");
|
||||
filesList->setUpdatesEnabled(false);
|
||||
std::vector<size_type> fp;
|
||||
h.file_progress(fp);
|
||||
PropListModel->model()->updateFilesPriorities(h.file_priorities());
|
||||
PropListModel->model()->updateFilesProgress(fp);
|
||||
filesList->setUpdatesEnabled(true);
|
||||
}
|
||||
}
|
||||
} catch(invalid_handle e) {}
|
||||
}
|
||||
|
||||
void PropertiesWidget::loadUrlSeeds(){
|
||||
listWebSeeds->clear();
|
||||
qDebug("Loading URL seeds");
|
||||
const QStringList hc_seeds = h.url_seeds();
|
||||
// Add url seeds
|
||||
foreach(const QString &hc_seed, hc_seeds){
|
||||
qDebug("Loading URL seed: %s", qPrintable(hc_seed));
|
||||
new QListWidgetItem(hc_seed, listWebSeeds);
|
||||
}
|
||||
}
|
||||
|
||||
void PropertiesWidget::openDoubleClickedFile(QModelIndex index) {
|
||||
if(!index.isValid()) return;
|
||||
if(!h.is_valid() || !h.has_metadata()) return;
|
||||
if(PropListModel->getType(index) == TorrentFileItem::TFILE) {
|
||||
int i = PropListModel->getFileIndex(index);
|
||||
const QDir saveDir(h.save_path());
|
||||
const QString filename = h.filepath_at(i);
|
||||
const QString file_path = QDir::cleanPath(saveDir.absoluteFilePath(filename));
|
||||
qDebug("Trying to open file at %s", qPrintable(file_path));
|
||||
#if LIBTORRENT_VERSION_MINOR > 14
|
||||
// Flush data
|
||||
h.flush_cache();
|
||||
#endif
|
||||
if(QFile::exists(file_path)) {
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(file_path));
|
||||
} else {
|
||||
QMessageBox::warning(this, tr("I/O Error"), tr("This file does not exist yet."));
|
||||
}
|
||||
} else {
|
||||
// FOLDER
|
||||
QStringList path_items;
|
||||
path_items << index.data().toString();
|
||||
QModelIndex parent = PropListModel->parent(index);
|
||||
while(parent.isValid()) {
|
||||
path_items.prepend(parent.data().toString());
|
||||
parent = PropListModel->parent(parent);
|
||||
}
|
||||
const QDir saveDir(h.save_path());
|
||||
const QString filename = path_items.join(QDir::separator());
|
||||
const QString file_path = QDir::cleanPath(saveDir.absoluteFilePath(filename));
|
||||
qDebug("Trying to open folder at %s", qPrintable(file_path));
|
||||
#if LIBTORRENT_VERSION_MINOR > 14
|
||||
// Flush data
|
||||
h.flush_cache();
|
||||
#endif
|
||||
if(QFile::exists(file_path)) {
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(file_path));
|
||||
} else {
|
||||
QMessageBox::warning(this, tr("I/O Error"), tr("This folder does not exist yet."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PropertiesWidget::displayFilesListMenu(const QPoint&){
|
||||
QMenu myFilesLlistMenu;
|
||||
QModelIndexList selectedRows = filesList->selectionModel()->selectedRows(0);
|
||||
QAction *actRename = 0;
|
||||
if(selectedRows.size() == 1) {
|
||||
actRename = myFilesLlistMenu.addAction(IconProvider::instance()->getIcon("edit-rename"), tr("Rename..."));
|
||||
myFilesLlistMenu.addSeparator();
|
||||
}
|
||||
QMenu subMenu;
|
||||
#if LIBTORRENT_VERSION_MINOR > 15
|
||||
if(!h.status(0x0).is_seeding) {
|
||||
#else
|
||||
if(!static_cast<torrent_handle>(h).is_seed()) {
|
||||
#endif
|
||||
subMenu.setTitle(tr("Priority"));
|
||||
subMenu.addAction(actionNot_downloaded);
|
||||
subMenu.addAction(actionNormal);
|
||||
subMenu.addAction(actionHigh);
|
||||
subMenu.addAction(actionMaximum);
|
||||
myFilesLlistMenu.addMenu(&subMenu);
|
||||
}
|
||||
// Call menu
|
||||
const QAction *act = myFilesLlistMenu.exec(QCursor::pos());
|
||||
if(act) {
|
||||
if(act == actRename) {
|
||||
renameSelectedFile();
|
||||
} else {
|
||||
int prio = 1;
|
||||
if(act == actionHigh) {
|
||||
prio = prio::HIGH;
|
||||
} else {
|
||||
if(act == actionMaximum) {
|
||||
prio = prio::MAXIMUM;
|
||||
} else {
|
||||
if(act == actionNot_downloaded) {
|
||||
prio = prio::IGNORED;
|
||||
}
|
||||
}
|
||||
}
|
||||
qDebug("Setting files priority");
|
||||
foreach(QModelIndex index, selectedRows) {
|
||||
qDebug("Setting priority(%d) for file at row %d", prio, index.row());
|
||||
PropListModel->setData(PropListModel->index(index.row(), PRIORITY, index.parent()), prio);
|
||||
}
|
||||
// Save changes
|
||||
filteredFilesChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PropertiesWidget::renameSelectedFile() {
|
||||
const QModelIndexList selectedIndexes = filesList->selectionModel()->selectedRows(0);
|
||||
Q_ASSERT(selectedIndexes.size() == 1);
|
||||
const QModelIndex index = selectedIndexes.first();
|
||||
// Ask for new name
|
||||
bool ok;
|
||||
QString new_name_last = QInputDialog::getText(this, tr("Rename the file"),
|
||||
tr("New name:"), QLineEdit::Normal,
|
||||
index.data().toString(), &ok);
|
||||
if (ok && !new_name_last.isEmpty()) {
|
||||
if(!misc::isValidFileSystemName(new_name_last)) {
|
||||
QMessageBox::warning(this, tr("The file could not be renamed"),
|
||||
tr("This file name contains forbidden characters, please choose a different one."),
|
||||
QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
if(PropListModel->getType(index) == TorrentFileItem::TFILE) {
|
||||
// File renaming
|
||||
const int file_index = PropListModel->getFileIndex(index);
|
||||
if(!h.is_valid() || !h.has_metadata()) return;
|
||||
QString old_name = h.filepath_at(file_index);
|
||||
old_name = old_name.replace("\\", "/");
|
||||
if(old_name.endsWith(".!qB") && !new_name_last.endsWith(".!qB")) {
|
||||
new_name_last += ".!qB";
|
||||
}
|
||||
QStringList path_items = old_name.split("/");
|
||||
path_items.removeLast();
|
||||
path_items << new_name_last;
|
||||
QString new_name = path_items.join("/");
|
||||
if(old_name == new_name) {
|
||||
qDebug("Name did not change");
|
||||
return;
|
||||
}
|
||||
new_name = QDir::cleanPath(new_name);
|
||||
// Check if that name is already used
|
||||
for(int i=0; i<h.num_files(); ++i) {
|
||||
if(i == file_index) continue;
|
||||
#if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
|
||||
if(h.filepath_at(i).compare(new_name, Qt::CaseSensitive) == 0) {
|
||||
#else
|
||||
if(h.filepath_at(i).compare(new_name, Qt::CaseInsensitive) == 0) {
|
||||
#endif
|
||||
// Display error message
|
||||
QMessageBox::warning(this, tr("The file could not be renamed"),
|
||||
tr("This name is already in use in this folder. Please use a different name."),
|
||||
QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
}
|
||||
const bool force_recheck = QFile::exists(h.save_path()+QDir::separator()+new_name);
|
||||
qDebug("Renaming %s to %s", qPrintable(old_name), qPrintable(new_name));
|
||||
h.rename_file(file_index, new_name);
|
||||
// Force recheck
|
||||
if(force_recheck) h.force_recheck();
|
||||
// Rename if torrent files model too
|
||||
if(new_name_last.endsWith(".!qB"))
|
||||
new_name_last.chop(4);
|
||||
PropListModel->setData(index, new_name_last);
|
||||
} else {
|
||||
// Folder renaming
|
||||
QStringList path_items;
|
||||
path_items << index.data().toString();
|
||||
QModelIndex parent = PropListModel->parent(index);
|
||||
while(parent.isValid()) {
|
||||
path_items.prepend(parent.data().toString());
|
||||
parent = PropListModel->parent(parent);
|
||||
}
|
||||
const QString old_path = path_items.join("/");
|
||||
path_items.removeLast();
|
||||
path_items << new_name_last;
|
||||
QString new_path = path_items.join("/");
|
||||
if(!new_path.endsWith("/")) new_path += "/";
|
||||
// Check for overwriting
|
||||
const int num_files = h.num_files();
|
||||
for(int i=0; i<num_files; ++i) {
|
||||
const QString current_name = h.filepath_at(i);
|
||||
#if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
|
||||
if(current_name.startsWith(new_path, Qt::CaseSensitive)) {
|
||||
#else
|
||||
if(current_name.startsWith(new_path, Qt::CaseInsensitive)) {
|
||||
#endif
|
||||
QMessageBox::warning(this, tr("The folder could not be renamed"),
|
||||
tr("This name is already in use in this folder. Please use a different name."),
|
||||
QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
}
|
||||
bool force_recheck = false;
|
||||
// Replace path in all files
|
||||
for(int i=0; i<num_files; ++i) {
|
||||
const QString current_name = h.filepath_at(i);
|
||||
if(current_name.startsWith(old_path)) {
|
||||
QString new_name = current_name;
|
||||
new_name.replace(0, old_path.length(), new_path);
|
||||
if(!force_recheck && QDir(h.save_path()).exists(new_name))
|
||||
force_recheck = true;
|
||||
new_name = QDir::cleanPath(new_name);
|
||||
qDebug("Rename %s to %s", qPrintable(current_name), qPrintable(new_name));
|
||||
h.rename_file(i, new_name);
|
||||
}
|
||||
}
|
||||
// Force recheck
|
||||
if(force_recheck) h.force_recheck();
|
||||
// Rename folder in torrent files model too
|
||||
PropListModel->setData(index, new_name_last);
|
||||
// Remove old folder
|
||||
const QDir old_folder(h.save_path()+"/"+old_path);
|
||||
int timeout = 10;
|
||||
while(!QDir().rmpath(old_folder.absolutePath()) && timeout > 0) {
|
||||
// XXX: We should not sleep here (freezes the UI for 1 second)
|
||||
SleeperThread::msleep(100);
|
||||
--timeout;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PropertiesWidget::askWebSeed(){
|
||||
bool ok;
|
||||
// Ask user for a new url seed
|
||||
const QString url_seed = QInputDialog::getText(this, tr("New url seed", "New HTTP source"),
|
||||
tr("New url seed:"), QLineEdit::Normal,
|
||||
QString::fromUtf8("http://www."), &ok);
|
||||
if(!ok) return;
|
||||
qDebug("Adding %s web seed", qPrintable(url_seed));
|
||||
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;
|
||||
}
|
||||
h.add_url_seed(url_seed);
|
||||
// Refresh the seeds list
|
||||
loadUrlSeeds();
|
||||
}
|
||||
|
||||
void PropertiesWidget::deleteSelectedUrlSeeds(){
|
||||
const QList<QListWidgetItem *> selectedItems = listWebSeeds->selectedItems();
|
||||
bool change = false;
|
||||
foreach(const QListWidgetItem *item, selectedItems){
|
||||
QString url_seed = item->text();
|
||||
h.remove_url_seed(url_seed);
|
||||
change = true;
|
||||
}
|
||||
if(change){
|
||||
// Refresh list
|
||||
loadUrlSeeds();
|
||||
}
|
||||
}
|
||||
|
||||
bool PropertiesWidget::applyPriorities() {
|
||||
qDebug("Saving files priorities");
|
||||
const std::vector<int> priorities = PropListModel->model()->getFilesPriorities(h.get_torrent_info().num_files());
|
||||
// Save first/last piece first option state
|
||||
bool first_last_piece_first = h.first_last_piece_first();
|
||||
// Prioritize the files
|
||||
qDebug("prioritize files: %d", priorities[0]);
|
||||
h.prioritize_files(priorities);
|
||||
// Restore first/last piece first option if necessary
|
||||
if(first_last_piece_first)
|
||||
h.prioritize_first_last_piece(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PropertiesWidget::on_changeSavePathButton_clicked() {
|
||||
if(!h.is_valid()) return;
|
||||
QString new_path;
|
||||
if(h.has_metadata() && h.num_files() == 1) {
|
||||
new_path = QFileDialog::getSaveFileName(this, tr("Choose save path"), h.firstFileSavePath());
|
||||
} else {
|
||||
const QDir saveDir(TorrentPersistentData::getSavePath(h.hash()));
|
||||
new_path = QFileDialog::getExistingDirectory(this, tr("Choose save path"), saveDir.absolutePath(),
|
||||
QFileDialog::DontConfirmOverwrite|QFileDialog::ShowDirsOnly|QFileDialog::HideNameFilterDetails);
|
||||
}
|
||||
if(!new_path.isEmpty()){
|
||||
// Check if savePath exists
|
||||
QString save_path_dir = new_path.replace("\\", "/");
|
||||
QString new_file_name;
|
||||
if(h.has_metadata() && h.num_files() == 1) {
|
||||
new_file_name = misc::fileName(save_path_dir); // New file name
|
||||
save_path_dir = misc::branchPath(save_path_dir, true); // Skip file name
|
||||
}
|
||||
QDir savePath(misc::expandPath(save_path_dir));
|
||||
// Actually move storage
|
||||
if(!QBtSession::instance()->useTemporaryFolder() || h.is_seed()) {
|
||||
if(!savePath.exists()) savePath.mkpath(savePath.absolutePath());
|
||||
h.move_storage(savePath.absolutePath());
|
||||
}
|
||||
// Update save_path in dialog
|
||||
QString display_path;
|
||||
if(h.has_metadata() && h.num_files() == 1) {
|
||||
// Rename the file
|
||||
Q_ASSERT(!new_file_name.isEmpty());
|
||||
#if defined(Q_WS_WIN) || defined(Q_OS_OS2)
|
||||
if(h.filename_at(0).compare(new_file_name, Qt::CaseInsensitive) != 0) {
|
||||
#else
|
||||
if(h.filename_at(0).compare(new_file_name, Qt::CaseSensitive) != 0) {
|
||||
#endif
|
||||
qDebug("Renaming single file to %s", qPrintable(new_file_name));
|
||||
h.rename_file(0, new_file_name);
|
||||
// Also rename it in the files list model
|
||||
PropListModel->setData(PropListModel->index(0, 0), new_file_name);
|
||||
}
|
||||
display_path = h.firstFileSavePath();
|
||||
} else {
|
||||
display_path = savePath.absolutePath();
|
||||
}
|
||||
#if defined(Q_WS_WIN) || defined(Q_OS_OS2)
|
||||
display_path = display_path.replace("/", "\\");
|
||||
#endif
|
||||
save_path->setText(display_path);
|
||||
}
|
||||
}
|
||||
|
||||
void PropertiesWidget::filteredFilesChanged() {
|
||||
if(h.is_valid()) {
|
||||
applyPriorities();
|
||||
}
|
||||
}
|
||||
115
src/properties/propertieswidget.h
Normal file
115
src/properties/propertieswidget.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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 TorrentFilesFilterModel;
|
||||
class PropListDelegate;
|
||||
class torrent_file;
|
||||
class PeerListWidget;
|
||||
class TrackerList;
|
||||
class MainWindow;
|
||||
class DownloadedPiecesBar;
|
||||
class PieceAvailabilityBar;
|
||||
class PropTabBar;
|
||||
class LineEdit;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QAction;
|
||||
class QTimer;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class PropertiesWidget : public QWidget, private Ui::PropertiesWidget {
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(PropertiesWidget)
|
||||
|
||||
public:
|
||||
enum SlideState {REDUCED, VISIBLE};
|
||||
|
||||
public:
|
||||
PropertiesWidget(QWidget *parent, MainWindow* main_window, TransferListWidget *transferList);
|
||||
~PropertiesWidget();
|
||||
QTorrentHandle getCurrentTorrent() const;
|
||||
TrackerList* getTrackerList() const { return trackerList; }
|
||||
PeerListWidget* getPeerList() const { return peersList; }
|
||||
QTreeView* getFilesList() const { return filesList; }
|
||||
|
||||
protected:
|
||||
QPushButton* getButtonFromIndex(int index);
|
||||
bool applyPriorities();
|
||||
|
||||
protected slots:
|
||||
void loadTorrentInfos(const QTorrentHandle &h);
|
||||
void updateTorrentInfos(const QTorrentHandle &h);
|
||||
void loadUrlSeeds();
|
||||
void askWebSeed();
|
||||
void deleteSelectedUrlSeeds();
|
||||
void displayFilesListMenu(const QPoint& pos);
|
||||
void on_changeSavePathButton_clicked();
|
||||
void filteredFilesChanged();
|
||||
void showPiecesDownloaded(bool show);
|
||||
void showPiecesAvailability(bool show);
|
||||
void renameSelectedFile();
|
||||
|
||||
public slots:
|
||||
void setVisibility(bool visible);
|
||||
void loadDynamicData();
|
||||
void clear();
|
||||
void readSettings();
|
||||
void saveSettings();
|
||||
void reloadPreferences();
|
||||
void openDoubleClickedFile(QModelIndex);
|
||||
void updateSavePath(const QTorrentHandle& h);
|
||||
|
||||
private:
|
||||
TransferListWidget *transferList;
|
||||
MainWindow *main_window;
|
||||
QTorrentHandle h;
|
||||
QTimer *refreshTimer;
|
||||
SlideState state;
|
||||
TorrentFilesFilterModel *PropListModel;
|
||||
PropListDelegate *PropDelegate;
|
||||
PeerListWidget *peersList;
|
||||
TrackerList *trackerList;
|
||||
QList<int> slideSizes;
|
||||
DownloadedPiecesBar *downloaded_pieces;
|
||||
PieceAvailabilityBar *pieces_availability;
|
||||
PropTabBar *m_tabBar;
|
||||
LineEdit *m_contentFilerLine;
|
||||
};
|
||||
|
||||
#endif // PROPERTIESWIDGET_H
|
||||
891
src/properties/propertieswidget.ui
Normal file
891
src/properties/propertieswidget.ui
Normal file
@@ -0,0 +1,891 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PropertiesWidget</class>
|
||||
<widget class="QWidget" name="PropertiesWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>540</width>
|
||||
<height>274</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>8</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="stackedProperties">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>520</width>
|
||||
<height>373</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="ProgressHLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="downloaded_pieces_lbl">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Downloaded:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="progress_lbl">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">0.0%</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="ProgressHLayout_2">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="avail_pieces_lbl">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Availability:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="avail_average_lbl">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">0.0</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Transfer</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Uploaded:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="upTotal">
|
||||
<property name="text">
|
||||
<string notr="true">0 Kb</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>UP limit:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="lbl_uplimit">
|
||||
<property name="text">
|
||||
<string notr="true">∞</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QLabel" name="lbl_ratio">
|
||||
<property name="text">
|
||||
<string>Share ratio:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="6">
|
||||
<widget class="QLabel" name="shareRatio">
|
||||
<property name="text">
|
||||
<string notr="true">1.0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Downloaded:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="dlTotal">
|
||||
<property name="text">
|
||||
<string notr="true">0 Kb</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>DL limit:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="lbl_dllimit">
|
||||
<property name="text">
|
||||
<string notr="true">∞</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Connections:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="6">
|
||||
<widget class="QLabel" name="lbl_connections">
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Wasted:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="wasted">
|
||||
<property name="text">
|
||||
<string notr="true">0 kb</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string extracomment="Time (duration) the torrent is active (not paused)">Time active:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QLabel" name="lbl_elapsed">
|
||||
<property name="text">
|
||||
<string notr="true">∞</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Reannounce in:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="6">
|
||||
<widget class="QLabel" name="reannounce_lbl">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupTorrentInfos">
|
||||
<property name="title">
|
||||
<string>Information</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="savePath_lbl">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save path:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="save_path">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">path</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="changeSavePathButton">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>15</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">...</string>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>14</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Created on:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="lbl_creationDate">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">date</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>14</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="hash_lbl2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Torrent hash:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="hash_lbl">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">hash</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_7">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>14</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Pieces size:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QLabel" name="pieceSize_lbl">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">piece size</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_8">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>14</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="comment_lbl2">
|
||||
<property name="text">
|
||||
<string>Comment:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="comment_text">
|
||||
<property name="html">
|
||||
<string notr="true"><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans'; font-size:8pt; font-weight:400; font-style:normal;">
|
||||
<table border="0" style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;">
|
||||
<tr>
|
||||
<td style="border: none;">
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Ubuntu';"></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Ubuntu';"></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Ubuntu';"></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p></td></tr></table></body></html></string>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="openLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_trackers">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_trackers">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_10">
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="trackerUpButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>31</horstretch>
|
||||
<verstretch>27</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>31</width>
|
||||
<height>27</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>31</width>
|
||||
<height>27</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="trackerDownButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>31</horstretch>
|
||||
<verstretch>27</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>31</width>
|
||||
<height>27</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>31</width>
|
||||
<height>27</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_5">
|
||||
<layout class="QVBoxLayout" name="peerpage_layout"/>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_3">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_9">
|
||||
<item>
|
||||
<widget class="QListWidget" name="listWebSeeds"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="_19">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="deleteWS_button">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="addWS_button">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_4">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="contentFilterLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Torrent content:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeView" name="filesList">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::AllEditTriggers</set>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<property name="allColumnsShowFocus">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="_6">
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="selectAllButton">
|
||||
<property name="text">
|
||||
<string>Select All</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="selectNoneButton">
|
||||
<property name="text">
|
||||
<string>Select None</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<action name="actionNormal">
|
||||
<property name="text">
|
||||
<string>Normal</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionHigh">
|
||||
<property name="text">
|
||||
<string>High</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionMaximum">
|
||||
<property name="text">
|
||||
<string>Maximum</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionNot_downloaded">
|
||||
<property name="text">
|
||||
<string>Do not download</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Do not download</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
202
src/properties/proplistdelegate.h
Normal file
202
src/properties/proplistdelegate.h
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* 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 PROPLISTDELEGATE_H
|
||||
#define PROPLISTDELEGATE_H
|
||||
|
||||
#include <QItemDelegate>
|
||||
#include <QStyleOptionProgressBarV2>
|
||||
#include <QStyleOptionViewItemV2>
|
||||
#include <QStyleOptionComboBox>
|
||||
#include <QComboBox>
|
||||
#include <QModelIndex>
|
||||
#include <QPainter>
|
||||
#include <QProgressBar>
|
||||
#include <QApplication>
|
||||
#include "misc.h"
|
||||
#include "propertieswidget.h"
|
||||
|
||||
#ifdef Q_WS_WIN
|
||||
#include <QPlastiqueStyle>
|
||||
#endif
|
||||
|
||||
// Defines for properties list columns
|
||||
enum PropColumn {NAME, PCSIZE, PROGRESS, PRIORITY};
|
||||
|
||||
class PropListDelegate: public QItemDelegate {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
PropertiesWidget *properties;
|
||||
|
||||
signals:
|
||||
void filteredFilesChanged() const;
|
||||
|
||||
public:
|
||||
PropListDelegate(PropertiesWidget* properties=0, QObject *parent=0) : QItemDelegate(parent), properties(properties){
|
||||
}
|
||||
|
||||
~PropListDelegate(){}
|
||||
|
||||
void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const{
|
||||
painter->save();
|
||||
QStyleOptionViewItemV2 opt = QItemDelegate::setOptions(index, option);
|
||||
switch(index.column()){
|
||||
case PCSIZE:
|
||||
QItemDelegate::drawBackground(painter, opt, index);
|
||||
QItemDelegate::drawDisplay(painter, opt, option.rect, misc::friendlyUnit(index.data().toLongLong()));
|
||||
break;
|
||||
case PROGRESS:{
|
||||
QStyleOptionProgressBarV2 newopt;
|
||||
qreal progress = index.data().toDouble()*100.;
|
||||
newopt.rect = opt.rect;
|
||||
// We don't want to display 100% unless
|
||||
// the torrent is really complete
|
||||
if(progress > 99.94 && progress < 100.)
|
||||
progress = 99.9;
|
||||
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;
|
||||
#ifndef Q_WS_WIN
|
||||
QApplication::style()->drawControl(QStyle::CE_ProgressBar, &newopt, painter);
|
||||
#else
|
||||
// XXX: To avoid having the progress text on the right of the bar
|
||||
QPlastiqueStyle st;
|
||||
st.drawControl(QStyle::CE_ProgressBar, &newopt, painter, 0);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case PRIORITY: {
|
||||
QItemDelegate::drawBackground(painter, opt, index);
|
||||
QString text = "";
|
||||
switch(index.data().toInt()) {
|
||||
case -1:
|
||||
text = tr("Mixed", "Mixed (priorities");
|
||||
break;
|
||||
case 0:
|
||||
text = tr("Not downloaded");
|
||||
break;
|
||||
case 2:
|
||||
text = tr("High", "High (priority)");
|
||||
break;
|
||||
case 7:
|
||||
text = tr("Maximum", "Maximum (priority)");
|
||||
break;
|
||||
default:
|
||||
text = tr("Normal", "Normal (priority)");
|
||||
break;
|
||||
}
|
||||
QItemDelegate::drawDisplay(painter, opt, option.rect, text);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
QItemDelegate::paint(painter, option, index);
|
||||
break;
|
||||
}
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void setEditorData(QWidget *editor, const QModelIndex &index) const {
|
||||
QComboBox *combobox = static_cast<QComboBox*>(editor);
|
||||
// Set combobox index
|
||||
switch(index.data().toInt()) {
|
||||
case 2:
|
||||
combobox->setCurrentIndex(1);
|
||||
break;
|
||||
case 7:
|
||||
combobox->setCurrentIndex(2);
|
||||
break;
|
||||
default:
|
||||
combobox->setCurrentIndex(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */, const QModelIndex &index) const {
|
||||
if(index.column() != PRIORITY) return 0;
|
||||
if(properties) {
|
||||
QTorrentHandle h = properties->getCurrentTorrent();
|
||||
#if LIBTORRENT_VERSION_MINOR > 15
|
||||
if(!h.is_valid() || !h.has_metadata() || h.status(0x0).is_seeding) return 0;
|
||||
#else
|
||||
if(!h.is_valid() || !h.has_metadata() || static_cast<libtorrent::torrent_handle>(h).is_seed()) return 0;
|
||||
#endif
|
||||
}
|
||||
if(index.data().toInt() <= 0) {
|
||||
// IGNORED or MIXED
|
||||
return 0;
|
||||
}
|
||||
QComboBox* editor = new QComboBox(parent);
|
||||
editor->setFocusPolicy(Qt::StrongFocus);
|
||||
editor->addItem(tr("Normal", "Normal (priority)"));
|
||||
editor->addItem(tr("High", "High (priority)"));
|
||||
editor->addItem(tr("Maximum", "Maximum (priority)"));
|
||||
return editor;
|
||||
}
|
||||
|
||||
public slots:
|
||||
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const {
|
||||
QComboBox *combobox = static_cast<QComboBox*>(editor);
|
||||
int value = combobox->currentIndex();
|
||||
qDebug("PropListDelegate: setModelData(%d)", value);
|
||||
switch(value) {
|
||||
case 1:
|
||||
model->setData(index, 2); // HIGH
|
||||
break;
|
||||
case 2:
|
||||
model->setData(index, 7); // MAX
|
||||
break;
|
||||
default:
|
||||
model->setData(index, 1); // NORMAL
|
||||
}
|
||||
emit filteredFilesChanged();
|
||||
}
|
||||
|
||||
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const {
|
||||
qDebug("UpdateEditor Geometry called");
|
||||
editor->setGeometry(option.rect);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
129
src/properties/proptabbar.cpp
Normal file
129
src/properties/proptabbar.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Copyright (C) 2010 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 <QButtonGroup>
|
||||
#include <QPushButton>
|
||||
#include <QSpacerItem>
|
||||
#include <QKeySequence>
|
||||
|
||||
#include "proptabbar.h"
|
||||
#include "iconprovider.h"
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
#define DEFAULT_BUTTON_CSS "QPushButton {border: 1px solid #888;border-radius: 2px; padding: 4px; margin-left: 0px; margin-right: 8px;}"
|
||||
#define SELECTED_BUTTON_CSS "QPushButton {border: 1px solid #888;border-radius: 2px; padding: 4px;background-color: palette(highlight); color: palette(highlighted-text); margin-left: 0px; margin-right: 8px;}"
|
||||
#else
|
||||
#define DEFAULT_BUTTON_CSS "QPushButton {border: 1px solid #888;border-radius: 2px; padding: 4px; margin-left: 0px; margin-right: 3px;}"
|
||||
#define SELECTED_BUTTON_CSS "QPushButton {border: 1px solid #888;border-radius: 2px; padding: 4px;background-color: palette(highlight); color: palette(highlighted-text); margin-left: 0px; margin-right: 3px;}"
|
||||
#endif
|
||||
|
||||
const int BTN_ICON_SIZE = 16;
|
||||
|
||||
PropTabBar::PropTabBar(QWidget *parent) :
|
||||
QHBoxLayout(parent), m_currentIndex(-1)
|
||||
{
|
||||
m_btnGroup = new QButtonGroup(this);
|
||||
setContentsMargins(0, 4, 0, 4);
|
||||
// General tab
|
||||
QPushButton *main_infos_button = new QPushButton(IconProvider::instance()->getIcon("document-properties"), tr("General"), parent);
|
||||
main_infos_button->setShortcut(QKeySequence(QString::fromUtf8("Alt+P")));
|
||||
main_infos_button->setStyleSheet(DEFAULT_BUTTON_CSS);
|
||||
main_infos_button->setIconSize(QSize(BTN_ICON_SIZE, BTN_ICON_SIZE));
|
||||
addWidget(main_infos_button);
|
||||
m_btnGroup->addButton(main_infos_button, MAIN_TAB);
|
||||
// Trackers tab
|
||||
QPushButton *trackers_button = new QPushButton(IconProvider::instance()->getIcon("network-server"), tr("Trackers"), parent);
|
||||
trackers_button->setStyleSheet(DEFAULT_BUTTON_CSS);
|
||||
trackers_button->setIconSize(QSize(BTN_ICON_SIZE, BTN_ICON_SIZE));
|
||||
addWidget(trackers_button);
|
||||
m_btnGroup->addButton(trackers_button, TRACKERS_TAB);
|
||||
// Peers tab
|
||||
QPushButton *peers_button = new QPushButton(IconProvider::instance()->getIcon("edit-find-user"), tr("Peers"), parent);
|
||||
peers_button->setStyleSheet(DEFAULT_BUTTON_CSS);
|
||||
peers_button->setIconSize(QSize(BTN_ICON_SIZE, BTN_ICON_SIZE));
|
||||
addWidget(peers_button);
|
||||
m_btnGroup->addButton(peers_button, PEERS_TAB);
|
||||
// URL seeds tab
|
||||
QPushButton *urlseeds_button = new QPushButton(IconProvider::instance()->getIcon("network-server"), tr("HTTP Sources"), parent);
|
||||
urlseeds_button->setStyleSheet(DEFAULT_BUTTON_CSS);
|
||||
urlseeds_button->setIconSize(QSize(BTN_ICON_SIZE, BTN_ICON_SIZE));
|
||||
addWidget(urlseeds_button);
|
||||
m_btnGroup->addButton(urlseeds_button, URLSEEDS_TAB);
|
||||
// Files tab
|
||||
QPushButton *files_button = new QPushButton(IconProvider::instance()->getIcon("inode-directory"), tr("Content"), parent);
|
||||
files_button->setStyleSheet(DEFAULT_BUTTON_CSS);
|
||||
files_button->setIconSize(QSize(BTN_ICON_SIZE, BTN_ICON_SIZE));
|
||||
addWidget(files_button);
|
||||
m_btnGroup->addButton(files_button, FILES_TAB);
|
||||
// Spacer
|
||||
addItem(new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum));
|
||||
// SIGNAL/SLOT
|
||||
connect(m_btnGroup, SIGNAL(buttonClicked(int)), SLOT(setCurrentIndex(int)));
|
||||
// Disable buttons focus
|
||||
foreach(QAbstractButton *btn, m_btnGroup->buttons()) {
|
||||
btn->setFocusPolicy(Qt::NoFocus);
|
||||
}
|
||||
}
|
||||
|
||||
PropTabBar::~PropTabBar() {
|
||||
delete m_btnGroup;
|
||||
}
|
||||
|
||||
int PropTabBar::currentIndex() const
|
||||
{
|
||||
return m_currentIndex;
|
||||
}
|
||||
|
||||
void PropTabBar::setCurrentIndex(int index)
|
||||
{
|
||||
if(index >= m_btnGroup->buttons().size())
|
||||
index = 0;
|
||||
// If asked to hide or if the currently selected tab is clicked
|
||||
if(index < 0 || m_currentIndex == index) {
|
||||
if(m_currentIndex >= 0) {
|
||||
m_btnGroup->button(m_currentIndex)->setStyleSheet(DEFAULT_BUTTON_CSS);
|
||||
m_currentIndex = -1;
|
||||
emit visibilityToggled(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Unselect previous tab
|
||||
if(m_currentIndex >= 0) {
|
||||
m_btnGroup->button(m_currentIndex)->setStyleSheet(DEFAULT_BUTTON_CSS);
|
||||
} else {
|
||||
// Nothing was selected, show!
|
||||
emit visibilityToggled(true);
|
||||
}
|
||||
// Select the new button
|
||||
m_btnGroup->button(index)->setStyleSheet(SELECTED_BUTTON_CSS);
|
||||
m_currentIndex = index;
|
||||
// Emit the signal
|
||||
emit tabChanged(index);
|
||||
}
|
||||
66
src/properties/proptabbar.h
Normal file
66
src/properties/proptabbar.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Copyright (C) 2010 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 PROPTABBAR_H
|
||||
#define PROPTABBAR_H
|
||||
|
||||
#include <QHBoxLayout>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QButtonGroup;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class PropTabBar : public QHBoxLayout
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(PropTabBar)
|
||||
|
||||
public:
|
||||
enum PropertyTab {MAIN_TAB, TRACKERS_TAB, PEERS_TAB, URLSEEDS_TAB, FILES_TAB};
|
||||
|
||||
public:
|
||||
explicit PropTabBar(QWidget *parent = 0);
|
||||
~PropTabBar();
|
||||
int currentIndex() const;
|
||||
|
||||
signals:
|
||||
void tabChanged(int index);
|
||||
void visibilityToggled(bool visible);
|
||||
|
||||
public slots:
|
||||
void setCurrentIndex(int index);
|
||||
|
||||
private:
|
||||
QButtonGroup *m_btnGroup;
|
||||
int m_currentIndex;
|
||||
|
||||
};
|
||||
|
||||
#endif // PROPTABBAR_H
|
||||
379
src/properties/trackerlist.cpp
Normal file
379
src/properties/trackerlist.cpp
Normal file
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
* 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 <QTreeWidgetItem>
|
||||
#include <QStringList>
|
||||
#include <QMenu>
|
||||
#include <QHash>
|
||||
#include <QAction>
|
||||
#include <QColor>
|
||||
#include <libtorrent/version.hpp>
|
||||
#include <libtorrent/peer_info.hpp>
|
||||
#include "trackerlist.h"
|
||||
#include "propertieswidget.h"
|
||||
#include "trackersadditiondlg.h"
|
||||
#include "iconprovider.h"
|
||||
#include "qbtsession.h"
|
||||
#include "qinisettings.h"
|
||||
#include "misc.h"
|
||||
|
||||
using namespace libtorrent;
|
||||
|
||||
TrackerList::TrackerList(PropertiesWidget *properties): QTreeWidget(), properties(properties) {
|
||||
loadSettings();
|
||||
// Graphical settings
|
||||
setRootIsDecorated(false);
|
||||
setAllColumnsShowFocus(true);
|
||||
setItemsExpandable(false);
|
||||
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
// Context menu
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showTrackerListMenu(QPoint)));
|
||||
// Set header
|
||||
QStringList header;
|
||||
header << tr("URL");
|
||||
header << tr("Status");
|
||||
header << tr("Peers");
|
||||
header << tr("Message");
|
||||
setHeaderItem(new QTreeWidgetItem(header));
|
||||
dht_item = new QTreeWidgetItem(QStringList("** "+tr("[DHT]")+" **"));
|
||||
insertTopLevelItem(0, dht_item);
|
||||
setRowColor(0, QColor("grey"));
|
||||
pex_item = new QTreeWidgetItem(QStringList("** "+tr("[PeX]")+" **"));
|
||||
insertTopLevelItem(1, pex_item);
|
||||
setRowColor(1, QColor("grey"));
|
||||
lsd_item = new QTreeWidgetItem(QStringList("** "+tr("[LSD]")+" **"));
|
||||
insertTopLevelItem(2, lsd_item);
|
||||
setRowColor(2, QColor("grey"));
|
||||
}
|
||||
|
||||
TrackerList::~TrackerList() {
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
QList<QTreeWidgetItem*> TrackerList::getSelectedTrackerItems() const {
|
||||
QList<QTreeWidgetItem*> selected_items = selectedItems();
|
||||
QList<QTreeWidgetItem*> selected_trackers;
|
||||
foreach(QTreeWidgetItem *item, selectedItems()) {
|
||||
if(indexOfTopLevelItem(item) >= NB_STICKY_ITEM) { // Ignore STICKY ITEMS
|
||||
selected_trackers << item;
|
||||
}
|
||||
}
|
||||
return selected_trackers;
|
||||
}
|
||||
|
||||
void TrackerList::setRowColor(int row, QColor color) {
|
||||
unsigned int nbColumns = columnCount();
|
||||
QTreeWidgetItem *item = topLevelItem(row);
|
||||
for(unsigned int i=0; i<nbColumns; ++i) {
|
||||
item->setData(i, Qt::ForegroundRole, color);
|
||||
}
|
||||
}
|
||||
|
||||
void TrackerList::moveSelectionUp() {
|
||||
#if LIBTORRENT_VERSION_MINOR < 15
|
||||
QTorrentHandle h = properties->getCurrentTorrent();
|
||||
if(!h.is_valid()) {
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
QList<QTreeWidgetItem *> selected_items = getSelectedTrackerItems();
|
||||
if(selected_items.isEmpty()) return;
|
||||
bool change = false;
|
||||
foreach(QTreeWidgetItem *item, selected_items){
|
||||
int index = indexOfTopLevelItem(item);
|
||||
if(index > NB_STICKY_ITEM) {
|
||||
insertTopLevelItem(index-1, takeTopLevelItem(index));
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
if(!change) return;
|
||||
// Restore selection
|
||||
QItemSelectionModel *selection = selectionModel();
|
||||
foreach(QTreeWidgetItem *item, selected_items) {
|
||||
selection->select(indexFromItem(item), QItemSelectionModel::Rows|QItemSelectionModel::Select);
|
||||
}
|
||||
setSelectionModel(selection);
|
||||
// Update torrent trackers
|
||||
std::vector<announce_entry> trackers;
|
||||
for(int i=NB_STICKY_ITEM; i<topLevelItemCount(); ++i) {
|
||||
QString tracker_url = topLevelItem(i)->data(COL_URL, Qt::DisplayRole).toString();
|
||||
announce_entry e(tracker_url.toStdString());
|
||||
e.tier = i-NB_STICKY_ITEM;
|
||||
trackers.push_back(e);
|
||||
}
|
||||
h.replace_trackers(trackers);
|
||||
// Reannounce
|
||||
h.force_reannounce();
|
||||
#endif
|
||||
}
|
||||
|
||||
void TrackerList::moveSelectionDown() {
|
||||
#if LIBTORRENT_VERSION_MINOR < 15
|
||||
QTorrentHandle h = properties->getCurrentTorrent();
|
||||
if(!h.is_valid()) {
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
QList<QTreeWidgetItem *> selected_items = getSelectedTrackerItems();
|
||||
if(selected_items.isEmpty()) return;
|
||||
bool change = false;
|
||||
for(int i=selectedItems().size()-1; i>= 0; --i) {
|
||||
int index = indexOfTopLevelItem(selected_items.at(i));
|
||||
if(index < topLevelItemCount()-1) {
|
||||
insertTopLevelItem(index+1, takeTopLevelItem(index));
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
if(!change) return;
|
||||
// Restore selection
|
||||
QItemSelectionModel *selection = selectionModel();
|
||||
foreach(QTreeWidgetItem *item, selected_items) {
|
||||
selection->select(indexFromItem(item), QItemSelectionModel::Rows|QItemSelectionModel::Select);
|
||||
}
|
||||
setSelectionModel(selection);
|
||||
// Update torrent trackers
|
||||
std::vector<announce_entry> trackers;
|
||||
for(int i=NB_STICKY_ITEM; i<topLevelItemCount(); ++i) {
|
||||
QString tracker_url = topLevelItem(i)->data(COL_URL, Qt::DisplayRole).toString();
|
||||
announce_entry e(tracker_url.toStdString());
|
||||
e.tier = i-NB_STICKY_ITEM;
|
||||
trackers.push_back(e);
|
||||
}
|
||||
h.replace_trackers(trackers);
|
||||
// Reannounce
|
||||
h.force_reannounce();
|
||||
#endif
|
||||
}
|
||||
|
||||
void TrackerList::clear() {
|
||||
qDeleteAll(tracker_items.values());
|
||||
tracker_items.clear();
|
||||
dht_item->setText(COL_PEERS, "");
|
||||
dht_item->setText(COL_STATUS, "");
|
||||
dht_item->setText(COL_MSG, "");
|
||||
pex_item->setText(COL_PEERS, "");
|
||||
pex_item->setText(COL_STATUS, "");
|
||||
pex_item->setText(COL_MSG, "");
|
||||
lsd_item->setText(COL_PEERS, "");
|
||||
lsd_item->setText(COL_STATUS, "");
|
||||
lsd_item->setText(COL_MSG, "");
|
||||
}
|
||||
|
||||
void TrackerList::loadStickyItems(const QTorrentHandle &h) {
|
||||
// XXX: libtorrent should provide this info...
|
||||
// Count peers from DHT, LSD, PeX
|
||||
uint nb_dht=0, nb_lsd=0, nb_pex=0;
|
||||
std::vector<peer_info> peers;
|
||||
h.get_peer_info(peers);
|
||||
std::vector<peer_info>::iterator it;
|
||||
for(it=peers.begin(); it!=peers.end(); it++) {
|
||||
if(it->source & peer_info::dht)
|
||||
++nb_dht;
|
||||
if(it->source & peer_info::lsd)
|
||||
++nb_lsd;
|
||||
if(it->source & peer_info::pex)
|
||||
++nb_pex;
|
||||
}
|
||||
// load DHT information
|
||||
if(QBtSession::instance()->isDHTEnabled() && h.has_metadata() && !h.priv()) {
|
||||
dht_item->setText(COL_STATUS, tr("Working"));
|
||||
} else {
|
||||
dht_item->setText(COL_STATUS, tr("Disabled"));
|
||||
}
|
||||
dht_item->setText(COL_PEERS, QString::number(nb_dht));
|
||||
if(h.has_metadata() && h.priv()) {
|
||||
dht_item->setText(COL_MSG, tr("This torrent is private"));
|
||||
}
|
||||
// Load PeX Information
|
||||
if(QBtSession::instance()->isPexEnabled())
|
||||
pex_item->setText(COL_STATUS, tr("Working"));
|
||||
else
|
||||
pex_item->setText(COL_STATUS, tr("Disabled"));
|
||||
pex_item->setText(COL_PEERS, QString::number(nb_pex));
|
||||
// Load LSD Information
|
||||
if(QBtSession::instance()->isLSDEnabled())
|
||||
lsd_item->setText(COL_STATUS, tr("Working"));
|
||||
else
|
||||
lsd_item->setText(COL_STATUS, tr("Disabled"));
|
||||
lsd_item->setText(COL_PEERS, QString::number(nb_lsd));
|
||||
}
|
||||
|
||||
void TrackerList::loadTrackers() {
|
||||
// Load trackers from torrent handle
|
||||
QTorrentHandle h = properties->getCurrentTorrent();
|
||||
if(!h.is_valid()) return;
|
||||
loadStickyItems(h);
|
||||
// Load actual trackers information
|
||||
QHash<QString, TrackerInfos> trackers_data = QBtSession::instance()->getTrackersInfo(h.hash());
|
||||
QStringList old_trackers_urls = tracker_items.keys();
|
||||
const std::vector<announce_entry> trackers = h.trackers();
|
||||
for(std::vector<announce_entry>::const_iterator it = trackers.begin(); it != trackers.end(); it++) {
|
||||
QString tracker_url = misc::toQString(it->url);
|
||||
QTreeWidgetItem *item = tracker_items.value(tracker_url, 0);
|
||||
if(!item) {
|
||||
item = new QTreeWidgetItem();
|
||||
item->setText(COL_URL, tracker_url);
|
||||
addTopLevelItem(item);
|
||||
tracker_items[tracker_url] = item;
|
||||
} else {
|
||||
old_trackers_urls.removeOne(tracker_url);
|
||||
}
|
||||
TrackerInfos data = trackers_data.value(tracker_url, TrackerInfos(tracker_url));
|
||||
QString error_message = data.last_message.trimmed();
|
||||
#if LIBTORRENT_VERSION_MINOR > 14
|
||||
if(it->verified) {
|
||||
item->setText(COL_STATUS, tr("Working"));
|
||||
item->setText(COL_MSG, "");
|
||||
} else {
|
||||
if(it->updating && it->fails == 0) {
|
||||
item->setText(COL_STATUS, tr("Updating..."));
|
||||
item->setText(COL_MSG, "");
|
||||
} else {
|
||||
if(it->fails > 0) {
|
||||
item->setText(COL_STATUS, tr("Not working"));
|
||||
item->setText(COL_MSG, error_message);
|
||||
} else {
|
||||
item->setText(COL_STATUS, tr("Not contacted yet"));
|
||||
item->setText(COL_MSG, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
if(data.verified) {
|
||||
item->setText(COL_STATUS, tr("Working"));
|
||||
item->setText(COL_MSG, "");
|
||||
} else {
|
||||
if(data.fail_count > 0) {
|
||||
item->setText(COL_STATUS, tr("Not working"));
|
||||
item->setText(COL_MSG, error_message);
|
||||
} else {
|
||||
item->setText(COL_STATUS, tr("Not contacted yet"));
|
||||
item->setText(COL_MSG, "");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
item->setText(COL_PEERS, QString::number(trackers_data.value(tracker_url, TrackerInfos(tracker_url)).num_peers));
|
||||
}
|
||||
// Remove old trackers
|
||||
foreach(const QString &tracker, old_trackers_urls) {
|
||||
delete tracker_items.take(tracker);
|
||||
}
|
||||
}
|
||||
|
||||
// Ask the user for new trackers and add them to the torrent
|
||||
void TrackerList::askForTrackers(){
|
||||
QTorrentHandle h = properties->getCurrentTorrent();
|
||||
if(!h.is_valid()) return;
|
||||
QStringList trackers = TrackersAdditionDlg::askForTrackers(h);
|
||||
if(!trackers.empty()) {
|
||||
foreach(const QString& tracker, trackers) {
|
||||
if(tracker.trimmed().isEmpty()) continue;
|
||||
announce_entry url(tracker.toStdString());
|
||||
url.tier = 0;
|
||||
h.add_tracker(url);
|
||||
}
|
||||
// Reannounce to new trackers
|
||||
h.force_reannounce();
|
||||
// Reload tracker list
|
||||
loadTrackers();
|
||||
}
|
||||
}
|
||||
|
||||
void TrackerList::deleteSelectedTrackers(){
|
||||
QTorrentHandle h = properties->getCurrentTorrent();
|
||||
if(!h.is_valid()) {
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
QList<QTreeWidgetItem *> selected_items = getSelectedTrackerItems();
|
||||
if(selected_items.isEmpty()) return;
|
||||
QStringList urls_to_remove;
|
||||
foreach(QTreeWidgetItem *item, selected_items){
|
||||
QString tracker_url = item->data(COL_URL, Qt::DisplayRole).toString();
|
||||
urls_to_remove << tracker_url;
|
||||
tracker_items.remove(tracker_url);
|
||||
delete item;
|
||||
}
|
||||
// Iterate of trackers and remove selected ones
|
||||
std::vector<announce_entry> remaining_trackers;
|
||||
std::vector<announce_entry> trackers = h.trackers();
|
||||
std::vector<announce_entry>::iterator it;
|
||||
for(it = trackers.begin(); it != trackers.end(); it++) {
|
||||
if(!urls_to_remove.contains(misc::toQString((*it).url))) {
|
||||
remaining_trackers.push_back(*it);
|
||||
}
|
||||
}
|
||||
h.replace_trackers(remaining_trackers);
|
||||
h.force_reannounce();
|
||||
// Reload Trackers
|
||||
loadTrackers();
|
||||
}
|
||||
|
||||
void TrackerList::showTrackerListMenu(QPoint) {
|
||||
QTorrentHandle h = properties->getCurrentTorrent();
|
||||
if(!h.is_valid()) return;
|
||||
//QList<QTreeWidgetItem*> selected_items = getSelectedTrackerItems();
|
||||
QMenu menu;
|
||||
// Add actions
|
||||
QAction *addAct = menu.addAction(IconProvider::instance()->getIcon("list-add"), tr("Add a new tracker..."));
|
||||
QAction *delAct = 0;
|
||||
if(!getSelectedTrackerItems().isEmpty()) {
|
||||
delAct = menu.addAction(IconProvider::instance()->getIcon("list-remove"), tr("Remove tracker"));
|
||||
}
|
||||
menu.addSeparator();
|
||||
QAction *reannounceAct = menu.addAction(IconProvider::instance()->getIcon("view-refresh"), tr("Force reannounce"));
|
||||
QAction *act = menu.exec(QCursor::pos());
|
||||
if(act == 0) return;
|
||||
if(act == addAct) {
|
||||
askForTrackers();
|
||||
return;
|
||||
}
|
||||
if(act == delAct) {
|
||||
deleteSelectedTrackers();
|
||||
return;
|
||||
}
|
||||
if(act == reannounceAct) {
|
||||
properties->getCurrentTorrent().force_reannounce();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void TrackerList::loadSettings() {
|
||||
QIniSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
|
||||
if(!header()->restoreState(settings.value("TorrentProperties/Trackers/TrackerListState").toByteArray())) {
|
||||
setColumnWidth(0, 300);
|
||||
}
|
||||
}
|
||||
|
||||
void TrackerList::saveSettings() const {
|
||||
QIniSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
|
||||
settings.setValue("TorrentProperties/Trackers/TrackerListState", header()->saveState());
|
||||
}
|
||||
79
src/properties/trackerlist.h
Normal file
79
src/properties/trackerlist.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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 TRACKERLIST_H
|
||||
#define TRACKERLIST_H
|
||||
|
||||
#include <QTreeWidget>
|
||||
#include <QList>
|
||||
|
||||
#include <libtorrent/version.hpp>
|
||||
#include "qtorrenthandle.h"
|
||||
#include "propertieswidget.h"
|
||||
|
||||
enum TrackerListColumn {COL_URL, COL_STATUS, COL_PEERS, COL_MSG};
|
||||
#define NB_STICKY_ITEM 3
|
||||
|
||||
class TrackerList: public QTreeWidget {
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(TrackerList)
|
||||
|
||||
private:
|
||||
PropertiesWidget *properties;
|
||||
QHash<QString, QTreeWidgetItem*> tracker_items;
|
||||
QTreeWidgetItem* dht_item;
|
||||
QTreeWidgetItem* pex_item;
|
||||
QTreeWidgetItem* lsd_item;
|
||||
|
||||
public:
|
||||
TrackerList(PropertiesWidget *properties);
|
||||
~TrackerList();
|
||||
|
||||
protected:
|
||||
QList<QTreeWidgetItem*> getSelectedTrackerItems() const;
|
||||
|
||||
public slots:
|
||||
void setRowColor(int row, QColor color);
|
||||
|
||||
void moveSelectionUp();
|
||||
void moveSelectionDown();
|
||||
|
||||
void clear();
|
||||
void loadStickyItems(const QTorrentHandle &h);
|
||||
void loadTrackers();
|
||||
void askForTrackers();
|
||||
void deleteSelectedTrackers();
|
||||
void showTrackerListMenu(QPoint);
|
||||
void loadSettings();
|
||||
void saveSettings() const;
|
||||
|
||||
};
|
||||
|
||||
#endif // TRACKERLIST_H
|
||||
148
src/properties/trackersadditiondlg.h
Normal file
148
src/properties/trackersadditiondlg.h
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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 TRACKERSADDITION_H
|
||||
#define TRACKERSADDITION_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QStringList>
|
||||
#include <QMessageBox>
|
||||
#include <QFile>
|
||||
#include <QUrl>
|
||||
#include "iconprovider.h"
|
||||
#include "misc.h"
|
||||
#include "ui_trackersadditiondlg.h"
|
||||
#include "downloadthread.h"
|
||||
#include "qtorrenthandle.h"
|
||||
|
||||
class TrackersAdditionDlg : public QDialog, private Ui::TrackersAdditionDlg{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
QTorrentHandle h;
|
||||
|
||||
public:
|
||||
TrackersAdditionDlg(QTorrentHandle h, QWidget *parent=0): QDialog(parent), h(h) {
|
||||
setupUi(this);
|
||||
// Icons
|
||||
uTorrentListButton->setIcon(IconProvider::instance()->getIcon("download"));
|
||||
// As a default, use torrentz.com link
|
||||
list_url->setText("http://www.torrentz.com/announce_"+h.hash());
|
||||
list_url->setCursorPosition(0);
|
||||
}
|
||||
|
||||
~TrackersAdditionDlg(){}
|
||||
|
||||
QStringList newTrackers() const {
|
||||
return trackers_list->toPlainText().trimmed().split("\n");
|
||||
}
|
||||
|
||||
public slots:
|
||||
void on_uTorrentListButton_clicked() {
|
||||
uTorrentListButton->setEnabled(false);
|
||||
DownloadThread *d = new DownloadThread(this);
|
||||
connect(d, SIGNAL(downloadFinished(QString,QString)), SLOT(parseUTorrentList(QString,QString)));
|
||||
connect(d, SIGNAL(downloadFailure(QString,QString)), SLOT(getTrackerError(QString,QString)));
|
||||
//Just to show that it takes times
|
||||
setCursor(Qt::WaitCursor);
|
||||
d->downloadUrl("http://www.torrentz.com/announce_"+h.hash());
|
||||
}
|
||||
|
||||
void parseUTorrentList(QString, QString path) {
|
||||
QFile list_file(path);
|
||||
if (!list_file.open(QFile::ReadOnly)) {
|
||||
QMessageBox::warning(this, tr("I/O Error"), tr("Error while trying to open the downloaded file."), QMessageBox::Ok);
|
||||
setCursor(Qt::ArrowCursor);
|
||||
uTorrentListButton->setEnabled(true);
|
||||
sender()->deleteLater();
|
||||
return;
|
||||
}
|
||||
QList<QUrl> existingTrackers;
|
||||
// Load from torrent handle
|
||||
std::vector<libtorrent::announce_entry> tor_trackers = h.trackers();
|
||||
std::vector<libtorrent::announce_entry>::iterator itr = tor_trackers.begin();
|
||||
while(itr != tor_trackers.end()) {
|
||||
existingTrackers << QUrl(misc::toQString(itr->url));
|
||||
itr++;
|
||||
}
|
||||
// Load from current user list
|
||||
QStringList tmp = trackers_list->toPlainText().split("\n");
|
||||
foreach(const QString &user_url_str, tmp) {
|
||||
QUrl user_url(user_url_str);
|
||||
if(!existingTrackers.contains(user_url))
|
||||
existingTrackers << user_url;
|
||||
}
|
||||
// Add new trackers to the list
|
||||
if(!trackers_list->toPlainText().isEmpty() && !trackers_list->toPlainText().endsWith("\n"))
|
||||
trackers_list->insertPlainText("\n");
|
||||
int nb = 0;
|
||||
while (!list_file.atEnd()) {
|
||||
const QByteArray line = list_file.readLine().trimmed();
|
||||
if(line.isEmpty()) continue;
|
||||
QUrl url(line);
|
||||
if (!existingTrackers.contains(url)) {
|
||||
trackers_list->insertPlainText(line + "\n");
|
||||
++nb;
|
||||
}
|
||||
}
|
||||
// Clean up
|
||||
list_file.close();
|
||||
list_file.remove();
|
||||
//To restore the cursor ...
|
||||
setCursor(Qt::ArrowCursor);
|
||||
uTorrentListButton->setEnabled(true);
|
||||
// Display information message if necessary
|
||||
if(nb == 0) {
|
||||
QMessageBox::information(this, tr("No change"), tr("No additional trackers were found."), QMessageBox::Ok);
|
||||
}
|
||||
sender()->deleteLater();
|
||||
}
|
||||
|
||||
void getTrackerError(const QString&, const QString &error) {
|
||||
//To restore the cursor ...
|
||||
setCursor(Qt::ArrowCursor);
|
||||
uTorrentListButton->setEnabled(true);
|
||||
QMessageBox::warning(this, tr("Download error"), tr("The trackers list could not be downloaded, reason: %1").arg(error), QMessageBox::Ok);
|
||||
sender()->deleteLater();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
static QStringList askForTrackers(QTorrentHandle h) {
|
||||
QStringList trackers;
|
||||
TrackersAdditionDlg dlg(h);
|
||||
if(dlg.exec() == QDialog::Accepted) {
|
||||
return dlg.newTrackers();
|
||||
}
|
||||
return trackers;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
121
src/properties/trackersadditiondlg.ui
Normal file
121
src/properties/trackersadditiondlg.ui
Normal file
@@ -0,0 +1,121 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TrackersAdditionDlg</class>
|
||||
<widget class="QDialog" name="TrackersAdditionDlg">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>367</width>
|
||||
<height>274</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Trackers addition dialog</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>List of trackers to add (one per line):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="trackers_list">
|
||||
<property name="lineWrapMode">
|
||||
<enum>QTextEdit::NoWrap</enum>
|
||||
</property>
|
||||
<property name="html">
|
||||
<string notr="true"><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans'; font-size:10pt;"></p></body></html></string>
|
||||
</property>
|
||||
<property name="acceptRichText">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>µTorrent compatible list URL:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="list_url"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="uTorrentListButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>31</width>
|
||||
<height>31</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>31</width>
|
||||
<height>31</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>TrackersAdditionDlg</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>TrackersAdditionDlg</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
Reference in New Issue
Block a user