Redesign main core classes.

This commit is contained in:
Vladimir Golovnev (Glassez)
2015-04-19 18:17:47 +03:00
parent 60c0939e05
commit d16d1fdb3a
152 changed files with 11366 additions and 8967 deletions

View File

@@ -1,5 +1,5 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2012 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
@@ -34,9 +34,12 @@
#include "torrentcontentmodel.h"
#include "torrentcontentfiltermodel.h"
#include "core/preferences.h"
#include "core/torrentpersistentdata.h"
#include "qbtsession.h"
#include "iconprovider.h"
#include "core/net/downloadmanager.h"
#include "core/net/downloadhandler.h"
#include "core/bittorrent/session.h"
#include "core/bittorrent/magneturi.h"
#include "core/bittorrent/torrentinfo.h"
#include "guiiconprovider.h"
#include "core/fs_utils.h"
#include "autoexpandabledialog.h"
#include "messageboxraised.h"
@@ -47,18 +50,13 @@
#include <QUrl>
#include <QMenu>
#include <QFileDialog>
#include <libtorrent/version.hpp>
using namespace libtorrent;
AddNewTorrentDialog::AddNewTorrentDialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::AddNewTorrentDialog)
, m_contentModel(0)
, m_contentDelegate(0)
, m_isMagnet(false)
, m_hasMetadata(false)
, m_hasRenamedFile(false)
, m_oldIndex(0)
{
ui->setupUi(this);
@@ -123,22 +121,115 @@ void AddNewTorrentDialog::saveState()
pref->setAddNewTorrentDialogExpanded(ui->adv_button->isChecked());
}
void AddNewTorrentDialog::showTorrent(const QString &torrent_path, const QString& from_url, QWidget *parent)
void AddNewTorrentDialog::show(QString source, QWidget *parent)
{
if (source.startsWith("bc://bt/", Qt::CaseInsensitive)) {
qDebug("Converting bc link to magnet link");
source = misc::bcLinkToMagnet(source);
}
AddNewTorrentDialog *dlg = new AddNewTorrentDialog(parent);
if (dlg->loadTorrent(torrent_path, from_url))
dlg->open();
else
delete dlg;
if (misc::isUrl(source)) {
// Launch downloader
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(source, 10485760 /* 10MB */);
connect(handler, SIGNAL(downloadFinished(QString, QString)), dlg, SLOT(handleDownloadFinished(QString, QString)));
connect(handler, SIGNAL(downloadFailed(QString, QString)), dlg, SLOT(handleDownloadFailed(QString, QString)));
connect(handler, SIGNAL(redirectedToMagnet(QString, QString)), dlg, SLOT(handleRedirectedToMagnet(QString, QString)));
}
else {
bool ok = false;
if (source.startsWith("magnet:", Qt::CaseInsensitive))
ok = dlg->loadMagnet(source);
else
ok = dlg->loadTorrent(source);
if (ok)
dlg->open();
else
delete dlg;
}
}
void AddNewTorrentDialog::showMagnet(const QString& link, QWidget *parent)
bool AddNewTorrentDialog::loadTorrent(const QString& torrent_path)
{
AddNewTorrentDialog *dlg = new AddNewTorrentDialog(parent);
if (dlg->loadMagnet(link))
dlg->open();
if (torrent_path.startsWith("file://", Qt::CaseInsensitive))
m_filePath = QUrl::fromEncoded(torrent_path.toLocal8Bit()).toLocalFile();
else
delete dlg;
m_filePath = torrent_path;
if (!QFile::exists(m_filePath)) {
MessageBoxRaised::critical(0, tr("I/O Error"), tr("The torrent file does not exist."));
return false;
}
m_hasMetadata = true;
QString error;
m_torrentInfo = BitTorrent::TorrentInfo::loadFromFile(m_filePath, error);
if (!m_torrentInfo.isValid()) {
MessageBoxRaised::critical(0, tr("Invalid torrent"), tr("Failed to load the torrent: %1").arg(error));
return false;
}
m_hash = m_torrentInfo.hash();
// Prevent showing the dialog if download is already present
if (BitTorrent::Session::instance()->isKnownTorrent(m_hash)) {
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(m_hash);
if (torrent) {
torrent->addTrackers(m_torrentInfo.trackers());
torrent->addUrlSeeds(m_torrentInfo.urlSeeds());
MessageBoxRaised::information(0, tr("Already in download list"), tr("Torrent is already in download list. Trackers were merged."), QMessageBox::Ok);
}
else {
MessageBoxRaised::critical(0, tr("Cannot add torrent"), tr("Cannot add this torrent. Perhaps it is already in adding state."), QMessageBox::Ok);
}
return false;
}
ui->lblhash->setText(m_hash);
setupTreeview();
return true;
}
bool AddNewTorrentDialog::loadMagnet(const QString &magnet_uri)
{
BitTorrent::MagnetUri magnet(magnet_uri);
if (!magnet.isValid()) {
MessageBoxRaised::critical(0, tr("Invalid magnet link"), tr("This magnet link was not recognized"));
return false;
}
m_hash = magnet.hash();
// Prevent showing the dialog if download is already present
if (BitTorrent::Session::instance()->isKnownTorrent(m_hash)) {
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(m_hash);
if (torrent) {
torrent->addTrackers(magnet.trackers());
torrent->addUrlSeeds(magnet.urlSeeds());
MessageBoxRaised::information(0, tr("Already in download list"), tr("Magnet link is already in download list. Trackers were merged."), QMessageBox::Ok);
}
else {
MessageBoxRaised::critical(0, tr("Cannot add torrent"), tr("Cannot add this torrent. Perhaps it is already in adding."), QMessageBox::Ok);
}
return false;
}
connect(BitTorrent::Session::instance(), SIGNAL(metadataLoaded(BitTorrent::TorrentInfo)), SLOT(updateMetadata(BitTorrent::TorrentInfo)));
// Set dialog title
QString torrent_name = magnet.name();
setWindowTitle(torrent_name.isEmpty() ? tr("Magnet link") : torrent_name);
setupTreeview();
// Set dialog position
setdialogPosition();
BitTorrent::Session::instance()->loadMetadata(magnet_uri);
setMetadataProgressIndicator(true, tr("Retrieving metadata..."));
ui->lblhash->setText(m_hash);
return true;
}
void AddNewTorrentDialog::showEvent(QShowEvent *event)
@@ -158,7 +249,7 @@ void AddNewTorrentDialog::showAdvancedSettings(bool show)
ui->adv_button->setText(QString::fromUtf8(""));
ui->settings_group->setVisible(true);
ui->info_group->setVisible(true);
if (m_hasMetadata && (m_torrentInfo->num_files() > 1)) {
if (m_hasMetadata && (m_torrentInfo.filesCount() > 1)) {
ui->content_tree->setVisible(true);
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
}
@@ -178,83 +269,6 @@ void AddNewTorrentDialog::showAdvancedSettings(bool show)
relayout();
}
bool AddNewTorrentDialog::loadTorrent(const QString& torrent_path, const QString& from_url)
{
m_isMagnet = false;
m_url = from_url;
if (torrent_path.startsWith("file://", Qt::CaseInsensitive))
m_filePath = QUrl::fromEncoded(torrent_path.toLocal8Bit()).toLocalFile();
else
m_filePath = torrent_path;
if (!QFile::exists(m_filePath)) {
MessageBoxRaised::critical(0, tr("I/O Error"), tr("The torrent file does not exist."));
return false;
}
m_hasMetadata = true;
try {
std::vector<char> buffer;
lazy_entry entry;
libtorrent::error_code ec;
misc::loadBencodedFile(m_filePath, buffer, entry, ec);
m_torrentInfo = new torrent_info(entry);
m_hash = misc::toQString(m_torrentInfo->info_hash());
}
catch(const std::exception& e) {
MessageBoxRaised::critical(0, tr("Invalid torrent"), tr("Failed to load the torrent: %1").arg(misc::toQStringU(e.what())));
return false;
}
// Prevent showing the dialog if download is already present
if (QBtSession::instance()->getTorrentHandle(m_hash).is_valid()) {
MessageBoxRaised::information(0, tr("Already in download list"), tr("Torrent is already in download list. Merging trackers."), QMessageBox::Ok);
QBtSession::instance()->addTorrent(m_filePath, false, m_url);;
return false;
}
ui->lblhash->setText(m_hash);
setupTreeview();
return true;
}
bool AddNewTorrentDialog::loadMagnet(const QString &magnet_uri)
{
connect(QBtSession::instance(), SIGNAL(metadataReceivedHidden(const QTorrentHandle &)), SLOT(updateMetadata(const QTorrentHandle &)));
m_isMagnet = true;
m_url = magnet_uri;
m_hash = misc::magnetUriToHash(m_url);
if (m_hash.isEmpty()) {
MessageBoxRaised::critical(0, tr("Invalid magnet link"), tr("This magnet link was not recognized"));
return false;
}
// Prevent showing the dialog if download is already present
if (QBtSession::instance()->getTorrentHandle(m_hash).is_valid()) {
MessageBoxRaised::information(0, tr("Already in download list"), tr("Magnet link is already in download list. Merging trackers."), QMessageBox::Ok);
QBtSession::instance()->addMagnetUri(m_url, false);
return false;
}
// Set dialog title
QString torrent_name = misc::magnetUriToName(m_url);
setWindowTitle(torrent_name.isEmpty() ? tr("Magnet link") : torrent_name);
setupTreeview();
// Set dialog position
setdialogPosition();
// Override save path
TorrentTempData::setSavePath(m_hash, QString(QDir::tempPath() + "/" + m_hash));
HiddenData::addData(m_hash);
QBtSession::instance()->addMagnetUri(m_url, false);
setMetadataProgressIndicator(true, tr("Retrieving metadata..."));
ui->lblhash->setText(m_hash);
return true;
}
void AddNewTorrentDialog::saveSavePathHistory() const
{
QDir selected_save_path(ui->save_path_combo->itemData(ui->save_path_combo->currentIndex()).toString());
@@ -279,7 +293,7 @@ void AddNewTorrentDialog::saveSavePathHistory() const
int AddNewTorrentDialog::indexOfSavePath(const QString &save_path)
{
QDir saveDir(save_path);
for(int i = 0; i<ui->save_path_combo->count() - 1; ++i)
for(int i = 0; i < ui->save_path_combo->count(); ++i)
if (QDir(ui->save_path_combo->itemData(i).toString()) == saveDir)
return i;
return -1;
@@ -287,7 +301,7 @@ int AddNewTorrentDialog::indexOfSavePath(const QString &save_path)
void AddNewTorrentDialog::updateFileNameInSavePaths(const QString &new_filename)
{
for(int i = 0; i<ui->save_path_combo->count() - 1; ++i) {
for(int i = 0; i < ui->save_path_combo->count(); ++i) {
const QDir folder(ui->save_path_combo->itemData(i).toString());
ui->save_path_combo->setItemText(i, fsutils::toNativePath(folder.absoluteFilePath(new_filename)));
}
@@ -300,14 +314,14 @@ void AddNewTorrentDialog::updateDiskSpaceLabel()
if (m_hasMetadata) {
if (m_contentModel) {
const std::vector<int> priorities = m_contentModel->model()->getFilesPriorities();
Q_ASSERT(priorities.size() == (uint) m_torrentInfo->num_files());
for (uint i = 0; i<priorities.size(); ++i)
const QVector<int> priorities = m_contentModel->model()->getFilePriorities();
Q_ASSERT(priorities.size() == m_torrentInfo.filesCount());
for (int i = 0; i < priorities.size(); ++i)
if (priorities[i] > 0)
torrent_size += m_torrentInfo->files().file_size(i);
torrent_size += m_torrentInfo.fileSize(i);
}
else {
torrent_size = m_torrentInfo->total_size();
torrent_size = m_torrentInfo.totalSize();
}
}
@@ -338,7 +352,7 @@ void AddNewTorrentDialog::browseButton_clicked()
QString cur_save_path = ui->save_path_combo->itemText(m_oldIndex);
QString new_path, old_filename, new_filename;
if (m_torrentInfo && m_torrentInfo->num_files() == 1) {
if (m_torrentInfo.isValid() && (m_torrentInfo.filesCount() == 1)) {
old_filename = fsutils::fileName(cur_save_path);
new_path = QFileDialog::getSaveFileName(this, tr("Choose save path"), cur_save_path, QString(), 0, QFileDialog::DontConfirmOverwrite);
if (!new_path.isEmpty())
@@ -367,8 +381,7 @@ void AddNewTorrentDialog::browseButton_clicked()
}
// Update file name in all save_paths
if (!new_filename.isEmpty() && !fsutils::sameFileNames(old_filename, new_filename)) {
m_hasRenamedFile = true;
m_filesPath[0] = new_filename;
m_torrentInfo.renameFile(0, new_filename);
updateFileNameInSavePaths(new_filename);
}
@@ -415,7 +428,7 @@ void AddNewTorrentDialog::renameSelectedFile()
if (m_contentModel->itemType(index) == TorrentContentModelItem::FileType) {
// File renaming
const int file_index = m_contentModel->getFileIndex(index);
QString old_name = fsutils::fromNativePath(m_filesPath.at(file_index));
QString old_name = fsutils::fromNativePath(m_torrentInfo.filePath(file_index));
qDebug("Old name: %s", qPrintable(old_name));
QStringList path_items = old_name.split("/");
path_items.removeLast();
@@ -428,9 +441,9 @@ void AddNewTorrentDialog::renameSelectedFile()
new_name = fsutils::expandPath(new_name);
qDebug("New name: %s", qPrintable(new_name));
// Check if that name is already used
for (int i = 0; i<m_torrentInfo->num_files(); ++i) {
for (int i = 0; i < m_torrentInfo.filesCount(); ++i) {
if (i == file_index) continue;
if (fsutils::sameFileNames(m_filesPath.at(i), new_name)) {
if (fsutils::sameFileNames(m_torrentInfo.filePath(i), new_name)) {
// Display error message
MessageBoxRaised::warning(this, tr("The file could not be renamed"),
tr("This name is already in use in this folder. Please use a different name."),
@@ -439,9 +452,7 @@ void AddNewTorrentDialog::renameSelectedFile()
}
}
qDebug("Renaming %s to %s", qPrintable(old_name), qPrintable(new_name));
// Rename file in files_path
m_filesPath.replace(file_index, new_name);
m_hasRenamedFile = true;
m_torrentInfo.renameFile(file_index, new_name);
// Rename in torrent files model too
m_contentModel->setData(index, new_name_last);
}
@@ -460,8 +471,8 @@ void AddNewTorrentDialog::renameSelectedFile()
QString new_path = path_items.join("/");
if (!new_path.endsWith("/")) new_path += "/";
// Check for overwriting
for (int i = 0; i<m_torrentInfo->num_files(); ++i) {
const QString &current_name = m_filesPath.at(i);
for (int i = 0; i < m_torrentInfo.filesCount(); ++i) {
const QString &current_name = m_torrentInfo.filePath(i);
#if defined(Q_OS_UNIX) || defined(Q_WS_QWS)
if (current_name.startsWith(new_path, Qt::CaseSensitive)) {
#else
@@ -474,18 +485,17 @@ void AddNewTorrentDialog::renameSelectedFile()
}
}
// Replace path in all files
for (int i = 0; i<m_torrentInfo->num_files(); ++i) {
const QString &current_name = m_filesPath.at(i);
for (int i = 0; i < m_torrentInfo.filesCount(); ++i) {
const QString &current_name = m_torrentInfo.filePath(i);
if (current_name.startsWith(old_path)) {
QString new_name = current_name;
new_name.replace(0, old_path.length(), new_path);
new_name = fsutils::expandPath(new_name);
qDebug("Rename %s to %s", qPrintable(current_name), qPrintable(new_name));
// Rename in files_path
m_filesPath.replace(i, new_name);
m_torrentInfo.renameFile(i, new_name);
}
}
m_hasRenamedFile = true;
// Rename folder in torrent files model too
m_contentModel->setData(index, new_name_last);
}
@@ -524,8 +534,8 @@ void AddNewTorrentDialog::displayContentTreeMenu(const QPoint&)
QMenu myFilesLlistMenu;
const QModelIndexList selectedRows = ui->content_tree->selectionModel()->selectedRows(0);
QAction *actRename = 0;
if (selectedRows.size() == 1 && m_torrentInfo->num_files() > 1) {
actRename = myFilesLlistMenu.addAction(IconProvider::instance()->getIcon("edit-rename"), tr("Rename..."));
if ((selectedRows.size() == 1) && (m_torrentInfo.filesCount() > 1)) {
actRename = myFilesLlistMenu.addAction(GuiIconProvider::instance()->getIcon("edit-rename"), tr("Rename..."));
myFilesLlistMenu.addSeparator();
}
QMenu subMenu;
@@ -564,85 +574,78 @@ void AddNewTorrentDialog::displayContentTreeMenu(const QPoint&)
void AddNewTorrentDialog::accept()
{
if (m_isMagnet)
disconnect(this, SLOT(updateMetadata(const QTorrentHandle &)));
if (!m_hasMetadata)
disconnect(this, SLOT(updateMetadata(const BitTorrent::TorrentInfo &)));
Preferences *const pref = Preferences::instance();
BitTorrent::AddTorrentParams params;
Preferences* const pref = Preferences::instance();
// Save Temporary data about torrent
QString save_path = ui->save_path_combo->itemData(ui->save_path_combo->currentIndex()).toString();
TorrentTempData::setSavePath(m_hash, save_path);
if (ui->skip_check_cb->isChecked())
// TODO: Check if destination actually exists
TorrentTempData::setSeedingMode(m_hash, true);
params.skipChecking = true;
// Label
const QString label = ui->label_combo->currentText();
if (!label.isEmpty())
TorrentTempData::setLabel(m_hash, label);
params.label = ui->label_combo->currentText();
// Save file priorities
if (m_contentModel)
TorrentTempData::setFilesPriority(m_hash, m_contentModel->model()->getFilesPriorities());
params.filePriorities = m_contentModel->model()->getFilePriorities();
// Rename files if necessary
if (m_hasRenamedFile)
TorrentTempData::setFilesPath(m_hash, m_filesPath);
TorrentTempData::setAddPaused(m_hash, !ui->start_torrent_cb->isChecked());
// Add torrent
if (m_isMagnet)
QBtSession::instance()->unhideMagnet(m_hash);
else
QBtSession::instance()->addTorrent(m_filePath, false, m_url);
params.addPaused = !ui->start_torrent_cb->isChecked();
saveSavePathHistory();
// Save settings
pref->useAdditionDialog(!ui->never_show_cb->isChecked());
QString savePath = ui->save_path_combo->itemData(ui->save_path_combo->currentIndex()).toString();
if (ui->default_save_path_cb->isChecked()) {
pref->setSavePath(ui->save_path_combo->itemData(ui->save_path_combo->currentIndex()).toString());
QBtSession::instance()->setDefaultSavePath(pref->getSavePath());
pref->setSavePath(savePath);
pref->apply();
}
else {
// if we don't use default save path...
if (QDir(savePath) != QDir(pref->getSavePath()))
params.savePath = savePath;
}
// Add torrent
if (!m_hasMetadata)
BitTorrent::Session::instance()->addTorrent(m_hash, params);
else
BitTorrent::Session::instance()->addTorrent(m_torrentInfo, params);
QDialog::accept();
}
void AddNewTorrentDialog::reject()
{
if (m_isMagnet) {
disconnect(this, SLOT(updateMetadata(const QTorrentHandle &)));
if (!m_hasMetadata) {
disconnect(this, SLOT(updateMetadata(BitTorrent::TorrentInfo)));
setMetadataProgressIndicator(false);
QBtSession::instance()->deleteTorrent(m_hash, true);
BitTorrent::Session::instance()->cancelLoadMetadata(m_hash);
}
QDialog::reject();
}
void AddNewTorrentDialog::updateMetadata(const QTorrentHandle &h)
void AddNewTorrentDialog::updateMetadata(const BitTorrent::TorrentInfo &info)
{
try {
if (h.hash() != m_hash)
return;
if (info.hash() != m_hash) return;
disconnect(this, SLOT(updateMetadata(const QTorrentHandle &)));
Q_ASSERT(h.has_metadata());
#if LIBTORRENT_VERSION_NUM < 10000
m_torrentInfo = new torrent_info(h.get_torrent_info());
#else
m_torrentInfo = new torrent_info(*h.torrent_file());
#endif
// Good to go
m_hasMetadata = true;
setMetadataProgressIndicator(true, tr("Parsing metadata..."));
// Update UI
setupTreeview();
setMetadataProgressIndicator(false, tr("Metadata retrieval complete"));
} catch (invalid_handle&) {
MessageBoxRaised::critical(0, tr("I/O Error"), ("Unknown error."));
setMetadataProgressIndicator(false, tr("Unknown error"));
disconnect(this, SLOT(updateMetadata(BitTorrent::TorrentInfo)));
if (!info.isValid()) {
MessageBoxRaised::critical(0, tr("I/O Error"), ("Invalid metadata."));
setMetadataProgressIndicator(false, tr("Invalid metadata"));
return;
}
// Good to go
m_torrentInfo = info;
m_hasMetadata = true;
setMetadataProgressIndicator(true, tr("Parsing metadata..."));
// Update UI
setupTreeview();
setMetadataProgressIndicator(false, tr("Metadata retrieval complete"));
}
void AddNewTorrentDialog::setMetadataProgressIndicator(bool visibleIndicator, const QString &labelText)
@@ -661,21 +664,15 @@ void AddNewTorrentDialog::setupTreeview()
}
else {
// Set dialog title
setWindowTitle(misc::toQStringU(m_torrentInfo->name()));
setWindowTitle(m_torrentInfo.name());
// Set torrent information
QString comment = misc::toQString(m_torrentInfo->comment());
QString comment = m_torrentInfo.comment();
ui->comment_lbl->setText(comment.replace('\n', ' '));
ui->date_lbl->setText(m_torrentInfo->creation_date() ? misc::toQString(*m_torrentInfo->creation_date()) : tr("Not available"));
file_storage const& fs = m_torrentInfo->files();
// Populate m_filesList
for (int i = 0; i < fs.num_files(); ++i)
m_filesPath << misc::toQStringU(fs.file_path(i));
ui->date_lbl->setText(!m_torrentInfo.creationDate().isNull() ? m_torrentInfo.creationDate().toString(Qt::DefaultLocaleLongDate) : tr("Not available"));
// Prepare content tree
if (fs.num_files() > 1) {
if (m_torrentInfo.filesCount() > 1) {
m_contentModel = new TorrentContentFilterModel(this);
connect(m_contentModel->model(), SIGNAL(filteredFilesChanged()), SLOT(updateDiskSpaceLabel()));
ui->content_tree->setModel(m_contentModel);
@@ -686,7 +683,7 @@ void AddNewTorrentDialog::setupTreeview()
connect(ui->content_tree, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(displayContentTreeMenu(const QPoint &)));
// List files in torrent
m_contentModel->model()->setupModelData(*m_torrentInfo);
m_contentModel->model()->setupModelData(m_torrentInfo);
if (!m_headerState.isEmpty())
ui->content_tree->header()->restoreState(m_headerState);
@@ -695,8 +692,8 @@ void AddNewTorrentDialog::setupTreeview()
}
else {
// Update save paths (append file name to them)
QString single_file_relpath = misc::toQStringU(fs.file_path(0));
for (int i = 0; i<ui->save_path_combo->count() - 1; ++i)
QString single_file_relpath = m_torrentInfo.filePath(0);
for (int i = 0; i < ui->save_path_combo->count(); ++i)
ui->save_path_combo->setItemText(i, fsutils::toNativePath(QDir(ui->save_path_combo->itemText(i)).absoluteFilePath(single_file_relpath)));
}
}
@@ -706,3 +703,27 @@ void AddNewTorrentDialog::setupTreeview()
// Set dialog position
setdialogPosition();
}
void AddNewTorrentDialog::handleDownloadFailed(const QString &url, const QString &reason)
{
MessageBoxRaised::critical(0, tr("Download Error"), QString("Cannot download %1: %2").arg(url).arg(reason));
this->deleteLater();
}
void AddNewTorrentDialog::handleRedirectedToMagnet(const QString &url, const QString &magnetUri)
{
Q_UNUSED(url)
if (loadMagnet(magnetUri))
open();
else
this->deleteLater();
}
void AddNewTorrentDialog::handleDownloadFinished(const QString &url, const QString &filePath)
{
Q_UNUSED(url)
if (loadTorrent(filePath))
open();
else
this->deleteLater();
}

View File

@@ -35,8 +35,8 @@
#include <QDialog>
#include <QUrl>
#include <libtorrent/torrent_info.hpp>
#include "qtorrenthandle.h"
#include "core/bittorrent/infohash.h"
#include "core/bittorrent/torrentinfo.h"
QT_BEGIN_NAMESPACE
namespace Ui {
@@ -54,8 +54,7 @@ class AddNewTorrentDialog: public QDialog
public:
~AddNewTorrentDialog();
static void showTorrent(const QString& torrent_path, const QString& from_url, QWidget *parent = 0);
static void showMagnet(const QString& torrent_link, QWidget *parent = 0);
static void show(QString source, QWidget *parent = 0);
protected:
void showEvent(QShowEvent *event);
@@ -68,8 +67,11 @@ private slots:
void relayout();
void renameSelectedFile();
void setdialogPosition();
void updateMetadata(const QTorrentHandle& h);
void updateMetadata(const BitTorrent::TorrentInfo &info);
void browseButton_clicked();
void handleDownloadFailed(const QString &url, const QString &reason);
void handleRedirectedToMagnet(const QString &url, const QString &magnetUri);
void handleDownloadFinished(const QString &url, const QString &filePath);
protected slots:
virtual void accept();
@@ -77,7 +79,7 @@ protected slots:
private:
explicit AddNewTorrentDialog(QWidget *parent = 0);
bool loadTorrent(const QString& torrent_path, const QString& from_url);
bool loadTorrent(const QString& torrent_path);
bool loadMagnet(const QString& magnet_uri);
void loadSavePathHistory();
void saveSavePathHistory() const;
@@ -92,14 +94,10 @@ private:
Ui::AddNewTorrentDialog *ui;
TorrentContentFilterModel *m_contentModel;
PropListDelegate *m_contentDelegate;
bool m_isMagnet;
bool m_hasMetadata;
QString m_filePath;
QString m_url;
QString m_hash;
boost::intrusive_ptr<libtorrent::torrent_info> m_torrentInfo;
QStringList m_filesPath;
bool m_hasRenamedFile;
BitTorrent::InfoHash m_hash;
BitTorrent::TorrentInfo m_torrentInfo;
QShortcut *editHotkey;
QByteArray m_headerState;
int m_oldIndex;

View File

@@ -9,7 +9,7 @@
#include <QLineEdit>
#include <QComboBox>
#include <QNetworkInterface>
#include <libtorrent/version.hpp>
#include "core/preferences.h"
enum AdvSettingsCols {PROPERTY, VALUE};

View File

@@ -35,7 +35,7 @@
#include <QPushButton>
#include "ui_confirmdeletiondlg.h"
#include "core/preferences.h"
#include "iconprovider.h"
#include "guiiconprovider.h"
#include "core/misc.h"
class DeletionConfirmationDlg : public QDialog, private Ui::confirmDeletionDlg {
@@ -49,9 +49,9 @@ class DeletionConfirmationDlg : public QDialog, private Ui::confirmDeletionDlg {
else
label->setText(tr("Are you sure you want to delete these %1 torrents from the transfer list?", "Are you sure you want to delete these 5 torrents from the transfer list?").arg(QString::number(size)));
// Icons
lbl_warn->setPixmap(IconProvider::instance()->getIcon("dialog-warning").pixmap(lbl_warn->height()));
lbl_warn->setPixmap(GuiIconProvider::instance()->getIcon("dialog-warning").pixmap(lbl_warn->height()));
lbl_warn->setFixedWidth(lbl_warn->height());
rememberBtn->setIcon(IconProvider::instance()->getIcon("object-locked"));
rememberBtn->setIcon(GuiIconProvider::instance()->getIcon("object-locked"));
move(misc::screenCenter(this));
checkPermDelete->setChecked(Preferences::instance()->deleteTorrentFilesAsDefault());

View File

@@ -36,7 +36,7 @@
#include "executionlog.h"
#include "ui_executionlog.h"
#include "core/logger.h"
#include "iconprovider.h"
#include "guiiconprovider.h"
#include "loglistwidget.h"
ExecutionLog::ExecutionLog(QWidget *parent)
@@ -47,8 +47,8 @@ ExecutionLog::ExecutionLog(QWidget *parent)
{
ui->setupUi(this);
ui->tabConsole->setTabIcon(0, IconProvider::instance()->getIcon("view-calendar-journal"));
ui->tabConsole->setTabIcon(1, IconProvider::instance()->getIcon("view-filter"));
ui->tabConsole->setTabIcon(0, GuiIconProvider::instance()->getIcon("view-calendar-journal"));
ui->tabConsole->setTabIcon(1, GuiIconProvider::instance()->getIcon("view-filter"));
ui->tabGeneral->layout()->addWidget(m_msgList);
ui->tabBan->layout()->addWidget(m_peerList);

View File

@@ -183,21 +183,21 @@ const char * country_name[253] =
"Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey",
"Saint Barthelemy","Saint Martin"};
QString GeoIPManager::CountryISOCodeToName(const char* iso) {
if (iso[0] == 0) return "N/A";
QString GeoIPManager::CountryISOCodeToName(const QString &iso) {
if (iso.isEmpty()) return "N/A";
for (uint i = 0; i < num_countries; ++i) {
if (iso[0] == country_code[i][0] && iso[1] == country_code[i][1]) {
if (iso == country_code[i]) {
return QLatin1String(country_name[i]);
}
}
qDebug("GeoIPManager: Country name resolution failed for: %c%c", iso[0], iso[1]);
qDebug("GeoIPManager: Country name resolution failed for: %s", qPrintable(iso));
return "N/A";
}
// http://www.iso.org/iso/country_codes/iso_3166_code_lists/english_country_names_and_code_elements.htm
QIcon GeoIPManager::CountryISOCodeToIcon(const char* iso) {
if (iso[0] == 0 || iso[0] == '!') return QIcon();
const QString isoStr = QString(QByteArray(iso, 2)).toLower();
return QIcon(":/icons/flags/"+isoStr+".png");
QIcon GeoIPManager::CountryISOCodeToIcon(const QString &iso) {
if (iso.isEmpty() || (iso[0] == '!')) return QIcon();
return QIcon(":/icons/flags/" + iso.toLower() + ".png");
}

View File

@@ -43,8 +43,8 @@ class GeoIPManager : public QObject {
public:
static void loadDatabase(libtorrent::session *s);
static QIcon CountryISOCodeToIcon(const char* iso);
static QString CountryISOCodeToName(const char* iso);
static QIcon CountryISOCodeToIcon(const QString &iso);
static QString CountryISOCodeToName(const QString &iso);
private:
static QString geoipFolder(bool embedded=false);

View File

@@ -3,7 +3,6 @@ INCLUDEPATH += $$PWD
include(lineedit/lineedit.pri)
include(properties/properties.pri)
include(rss/rss.pri)
include(torrentcreator/torrentcreator.pri)
include(geoip/geoip.pri)
include(powermanagement/powermanagement.pri)
unix:!macx:dbus: include(qtnotify/qtnotify.pri)
@@ -32,18 +31,18 @@ HEADERS += \
$$PWD/hidabletabwidget.h \
$$PWD/torrentimportdlg.h \
$$PWD/executionlog.h \
$$PWD/iconprovider.h \
$$PWD/guiiconprovider.h \
$$PWD/updownratiodlg.h \
$$PWD/loglistwidget.h \
$$PWD/addnewtorrentdialog.h \
$$PWD/autoexpandabledialog.h \
$$PWD/statsdialog.h \
$$PWD/messageboxraised.h \
$$PWD/torrentfilterenum.h \
$$PWD/options_imp.h \
$$PWD/advancedsettings.h \
$$PWD/shutdownconfirm.h \
$$PWD/torrentmodel.h
$$PWD/torrentmodel.h \
$$PWD/torrentcreatordlg.h
SOURCES += \
$$PWD/mainwindow.cpp \
@@ -62,7 +61,7 @@ SOURCES += \
$$PWD/executionlog.cpp \
$$PWD/speedlimitdlg.cpp \
$$PWD/previewselect.cpp \
$$PWD/iconprovider.cpp \
$$PWD/guiiconprovider.cpp \
$$PWD/updownratiodlg.cpp \
$$PWD/loglistwidget.cpp \
$$PWD/addnewtorrentdialog.cpp \
@@ -73,7 +72,8 @@ SOURCES += \
$$PWD/trackerlogin.cpp \
$$PWD/options_imp.cpp \
$$PWD/shutdownconfirm.cpp \
$$PWD/torrentmodel.cpp
$$PWD/torrentmodel.cpp \
$$PWD/torrentcreatordlg.cpp
win32|macx {
HEADERS += $$PWD/programupdater.h
@@ -94,6 +94,7 @@ FORMS += \
$$PWD/addnewtorrentdialog.ui \
$$PWD/autoexpandabledialog.ui \
$$PWD/statsdialog.ui \
$$PWD/options.ui
$$PWD/options.ui \
$$PWD/createtorrent.ui
RESOURCES += $$PWD/about.qrc

125
src/gui/guiiconprovider.cpp Normal file
View File

@@ -0,0 +1,125 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2011 Christophe Dumez <chris@qbittorrent.org>
*
* 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.
*/
#include "guiiconprovider.h"
#include "core/preferences.h"
#include <QIcon>
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
#include <QDir>
#include <QFile>
#endif
GuiIconProvider::GuiIconProvider(QObject *parent)
: IconProvider(parent)
{
configure();
connect(Preferences::instance(), SIGNAL(changed()), SLOT(configure()));
}
GuiIconProvider::~GuiIconProvider() {}
void GuiIconProvider::initInstance()
{
if (!m_instance)
m_instance = new GuiIconProvider;
}
GuiIconProvider *GuiIconProvider::instance()
{
return static_cast<GuiIconProvider *>(m_instance);
}
QIcon GuiIconProvider::getIcon(const QString &iconId)
{
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
if (m_useSystemTheme) {
QIcon icon = QIcon::fromTheme(iconId, QIcon(IconProvider::getIconPath(iconId)));
icon = generateDifferentSizes(icon);
return icon;
}
#endif
return QIcon(IconProvider::getIconPath(iconId));
}
// Makes sure the icon is at least available in 16px and 24px size
// It scales the icon from the theme if necessary
// Otherwise, the UI looks broken if the icon is not available
// in the correct size.
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
QIcon GuiIconProvider::generateDifferentSizes(const QIcon &icon)
{
QIcon newIcon;
QList<QSize> requiredSizes;
requiredSizes << QSize(16, 16) << QSize(24, 24) << QSize(32, 32);
QList<QIcon::Mode> modes;
modes << QIcon::Normal << QIcon::Active << QIcon::Selected << QIcon::Disabled;
foreach (const QSize &size, requiredSizes) {
foreach (QIcon::Mode mode, modes) {
QPixmap pixoff = icon.pixmap(size, mode, QIcon::Off);
if (pixoff.height() > size.height())
pixoff = pixoff.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
newIcon.addPixmap(pixoff, mode, QIcon::Off);
QPixmap pixon = icon.pixmap(size, mode, QIcon::On);
if (pixon.height() > size.height())
pixon = pixoff.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
newIcon.addPixmap(pixon, mode, QIcon::On);
}
}
return newIcon;
}
#endif
QString GuiIconProvider::getIconPath(const QString &iconId)
{
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
if (m_useSystemTheme) {
QString path = QDir::temp().absoluteFilePath(iconId + ".png");
if (!QFile::exists(path)) {
const QIcon icon = QIcon::fromTheme(iconId);
if (!icon.isNull())
icon.pixmap(32).save(path);
else
path = IconProvider::getIconPath(iconId);
}
return path;
}
#endif
return IconProvider::getIconPath(iconId);
}
void GuiIconProvider::configure()
{
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
m_useSystemTheme = Preferences::instance()->useSystemIconTheme();
#endif
}

62
src/gui/guiiconprovider.h Normal file
View File

@@ -0,0 +1,62 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2011 Christophe Dumez <chris@qbittorrent.org>
*
* 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.
*/
#ifndef GUIICONPROVIDER_H
#define GUIICONPROVIDER_H
#include "core/iconprovider.h"
class QIcon;
class GuiIconProvider : public IconProvider
{
Q_DISABLE_COPY(GuiIconProvider)
Q_OBJECT
public:
static void initInstance();
static GuiIconProvider *instance();
QIcon getIcon(const QString &iconId);
QString getIconPath(const QString &iconId);
private slots:
void configure();
private:
explicit GuiIconProvider(QObject *parent = 0);
~GuiIconProvider();
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
QIcon generateDifferentSizes(const QIcon &icon);
bool m_useSystemTheme;
#endif
};
#endif // GUIICONPROVIDER_H

View File

@@ -35,7 +35,7 @@
#include <QRegExp>
#include <QAction>
#include "loglistwidget.h"
#include "iconprovider.h"
#include "guiiconprovider.h"
LogListWidget::LogListWidget(int max_lines, QWidget *parent) :
QListWidget(parent),
@@ -44,8 +44,8 @@ LogListWidget::LogListWidget(int max_lines, QWidget *parent) :
// Allow multiple selections
setSelectionMode(QAbstractItemView::ExtendedSelection);
// Context menu
QAction *copyAct = new QAction(IconProvider::instance()->getIcon("edit-copy"), tr("Copy"), this);
QAction *clearAct = new QAction(IconProvider::instance()->getIcon("edit-clear"), tr("Clear"), this);
QAction *copyAct = new QAction(GuiIconProvider::instance()->getIcon("edit-copy"), tr("Copy"), this);
QAction *clearAct = new QAction(GuiIconProvider::instance()->getIcon("edit-clear"), tr("Clear"), this);
connect(copyAct, SIGNAL(triggered()), SLOT(copySelection()));
connect(clearAct, SIGNAL(triggered()), SLOT(clearLog()));
addAction(copyAct);

View File

@@ -55,7 +55,9 @@
#include "addnewtorrentdialog.h"
#include "searchengine.h"
#include "rss_imp.h"
#include "qbtsession.h"
#include "core/bittorrent/session.h"
#include "core/bittorrent/sessionstatus.h"
#include "core/bittorrent/torrenthandle.h"
#include "about_imp.h"
#include "trackerlogin.h"
#include "options_imp.h"
@@ -63,7 +65,6 @@
#include "core/preferences.h"
#include "trackerlist.h"
#include "peerlistwidget.h"
#include "core/torrentpersistentdata.h"
#include "transferlistfilterswidget.h"
#include "propertieswidget.h"
#include "statusbar.h"
@@ -71,11 +72,9 @@
#include "torrentimportdlg.h"
#include "torrentmodel.h"
#include "executionlog.h"
#include "iconprovider.h"
#include "guiiconprovider.h"
#include "core/logger.h"
#ifndef DISABLE_GUI
#include "autoexpandabledialog.h"
#endif
#ifdef Q_OS_MAC
void qt_mac_set_dock_menu(QMenu *menu);
#endif
@@ -86,13 +85,10 @@ void qt_mac_set_dock_menu(QMenu *menu);
#endif
#include "powermanagement.h"
#ifdef Q_OS_WIN
#include "core/downloadthread.h"
#include "core/net/downloadmanager.h"
#include "core/net/downloadhandler.h"
#endif
#include <libtorrent/session.hpp>
using namespace libtorrent;
#define TIME_TRAY_BALLOON 5000
#define PREVENT_SUSPEND_INTERVAL 60000
@@ -128,32 +124,32 @@ MainWindow::MainWindow(QWidget *parent)
addToolbarContextMenu();
actionOpen->setIcon(IconProvider::instance()->getIcon("list-add"));
actionDownload_from_URL->setIcon(IconProvider::instance()->getIcon("insert-link"));
actionOpen->setIcon(GuiIconProvider::instance()->getIcon("list-add"));
actionDownload_from_URL->setIcon(GuiIconProvider::instance()->getIcon("insert-link"));
actionSet_upload_limit->setIcon(QIcon(QString::fromUtf8(":/icons/skin/seeding.png")));
actionSet_download_limit->setIcon(QIcon(QString::fromUtf8(":/icons/skin/download.png")));
actionSet_global_upload_limit->setIcon(QIcon(QString::fromUtf8(":/icons/skin/seeding.png")));
actionSet_global_download_limit->setIcon(QIcon(QString::fromUtf8(":/icons/skin/download.png")));
actionCreate_torrent->setIcon(IconProvider::instance()->getIcon("document-edit"));
actionAbout->setIcon(IconProvider::instance()->getIcon("help-about"));
actionStatistics->setIcon(IconProvider::instance()->getIcon("view-statistics"));
actionBugReport->setIcon(IconProvider::instance()->getIcon("tools-report-bug"));
actionDecreasePriority->setIcon(IconProvider::instance()->getIcon("go-down"));
actionBottomPriority->setIcon(IconProvider::instance()->getIcon("go-bottom"));
actionDelete->setIcon(IconProvider::instance()->getIcon("list-remove"));
actionDocumentation->setIcon(IconProvider::instance()->getIcon("help-contents"));
actionDonate_money->setIcon(IconProvider::instance()->getIcon("wallet-open"));
actionExit->setIcon(IconProvider::instance()->getIcon("application-exit"));
actionIncreasePriority->setIcon(IconProvider::instance()->getIcon("go-up"));
actionTopPriority->setIcon(IconProvider::instance()->getIcon("go-top"));
actionLock_qBittorrent->setIcon(IconProvider::instance()->getIcon("object-locked"));
actionOptions->setIcon(IconProvider::instance()->getIcon("preferences-system"));
actionPause->setIcon(IconProvider::instance()->getIcon("media-playback-pause"));
actionPause_All->setIcon(IconProvider::instance()->getIcon("media-playback-pause"));
actionStart->setIcon(IconProvider::instance()->getIcon("media-playback-start"));
actionStart_All->setIcon(IconProvider::instance()->getIcon("media-playback-start"));
action_Import_Torrent->setIcon(IconProvider::instance()->getIcon("document-import"));
menuAuto_Shutdown_on_downloads_completion->setIcon(IconProvider::instance()->getIcon("application-exit"));
actionCreate_torrent->setIcon(GuiIconProvider::instance()->getIcon("document-edit"));
actionAbout->setIcon(GuiIconProvider::instance()->getIcon("help-about"));
actionStatistics->setIcon(GuiIconProvider::instance()->getIcon("view-statistics"));
actionBugReport->setIcon(GuiIconProvider::instance()->getIcon("tools-report-bug"));
actionDecreasePriority->setIcon(GuiIconProvider::instance()->getIcon("go-down"));
actionBottomPriority->setIcon(GuiIconProvider::instance()->getIcon("go-bottom"));
actionDelete->setIcon(GuiIconProvider::instance()->getIcon("list-remove"));
actionDocumentation->setIcon(GuiIconProvider::instance()->getIcon("help-contents"));
actionDonate_money->setIcon(GuiIconProvider::instance()->getIcon("wallet-open"));
actionExit->setIcon(GuiIconProvider::instance()->getIcon("application-exit"));
actionIncreasePriority->setIcon(GuiIconProvider::instance()->getIcon("go-up"));
actionTopPriority->setIcon(GuiIconProvider::instance()->getIcon("go-top"));
actionLock_qBittorrent->setIcon(GuiIconProvider::instance()->getIcon("object-locked"));
actionOptions->setIcon(GuiIconProvider::instance()->getIcon("preferences-system"));
actionPause->setIcon(GuiIconProvider::instance()->getIcon("media-playback-pause"));
actionPause_All->setIcon(GuiIconProvider::instance()->getIcon("media-playback-pause"));
actionStart->setIcon(GuiIconProvider::instance()->getIcon("media-playback-start"));
actionStart_All->setIcon(GuiIconProvider::instance()->getIcon("media-playback-start"));
action_Import_Torrent->setIcon(GuiIconProvider::instance()->getIcon("document-import"));
menuAuto_Shutdown_on_downloads_completion->setIcon(GuiIconProvider::instance()->getIcon("application-exit"));
QMenu *startAllMenu = new QMenu(this);
startAllMenu->addAction(actionStart_All);
@@ -169,14 +165,13 @@ MainWindow::MainWindow(QWidget *parent)
actionLock_qBittorrent->setMenu(lockMenu);
// Creating Bittorrent session
connect(QBtSession::instance(), SIGNAL(fullDiskError(QTorrentHandle, QString)), this, SLOT(fullDiskError(QTorrentHandle, QString)));
connect(QBtSession::instance(), SIGNAL(finishedTorrent(QTorrentHandle)), this, SLOT(finishedTorrent(QTorrentHandle)));
connect(QBtSession::instance(), SIGNAL(trackerAuthenticationRequired(QTorrentHandle)), this, SLOT(trackerAuthenticationRequired(QTorrentHandle)));
connect(QBtSession::instance(), SIGNAL(newDownloadedTorrent(QString, QString)), this, SLOT(processDownloadedFiles(QString, QString)));
connect(QBtSession::instance(), SIGNAL(newMagnetLink(QString)), this, SLOT(processNewMagnetLink(QString)));
connect(QBtSession::instance(), SIGNAL(downloadFromUrlFailure(QString, QString)), this, SLOT(handleDownloadFromUrlFailure(QString, QString)));
connect(QBtSession::instance(), SIGNAL(alternativeSpeedsModeChanged(bool)), this, SLOT(updateAltSpeedsBtn(bool)));
connect(QBtSession::instance(), SIGNAL(recursiveTorrentDownloadPossible(QTorrentHandle)), this, SLOT(askRecursiveTorrentDownloadConfirmation(QTorrentHandle)));
connect(BitTorrent::Session::instance(), SIGNAL(fullDiskError(BitTorrent::TorrentHandle *const, QString)), this, SLOT(fullDiskError(BitTorrent::TorrentHandle *const, QString)));
connect(BitTorrent::Session::instance(), SIGNAL(addTorrentFailed(const QString &)), this, SLOT(addTorrentFailed(const QString &)));
connect(BitTorrent::Session::instance(), SIGNAL(torrentFinished(BitTorrent::TorrentHandle *const)), this, SLOT(finishedTorrent(BitTorrent::TorrentHandle *const)));
connect(BitTorrent::Session::instance(), SIGNAL(trackerAuthenticationRequired(BitTorrent::TorrentHandle *const)), this, SLOT(trackerAuthenticationRequired(BitTorrent::TorrentHandle *const)));
connect(BitTorrent::Session::instance(), SIGNAL(downloadFromUrlFailed(QString, QString)), this, SLOT(handleDownloadFromUrlFailure(QString, QString)));
connect(BitTorrent::Session::instance(), SIGNAL(speedLimitModeChanged(bool)), this, SLOT(updateAltSpeedsBtn(bool)));
connect(BitTorrent::Session::instance(), SIGNAL(recursiveTorrentDownloadPossible(BitTorrent::TorrentHandle *const)), this, SLOT(askRecursiveTorrentDownloadConfirmation(BitTorrent::TorrentHandle *const)));
qDebug("create tabWidget");
tabs = new HidableTabWidget(this);
@@ -200,7 +195,7 @@ MainWindow::MainWindow(QWidget *parent)
toolBar->insertWidget(searchFilterAct, spacer);
// Transfer List tab
transferList = new TransferListWidget(hSplitter, this, QBtSession::instance());
transferList = new TransferListWidget(hSplitter, this);
properties = new PropertiesWidget(hSplitter, this, transferList);
transferListFilters = new TransferListFiltersWidget(vSplitter, transferList);
hSplitter->addWidget(transferList);
@@ -209,20 +204,18 @@ MainWindow::MainWindow(QWidget *parent)
vSplitter->addWidget(hSplitter);
vSplitter->setCollapsible(0, true);
vSplitter->setCollapsible(1, false);
tabs->addTab(vSplitter, IconProvider::instance()->getIcon("folder-remote"), tr("Transfers"));
tabs->addTab(vSplitter, GuiIconProvider::instance()->getIcon("folder-remote"), tr("Transfers"));
connect(search_filter, SIGNAL(textChanged(QString)), transferList, SLOT(applyNameFilter(QString)));
connect(hSplitter, SIGNAL(splitterMoved(int, int)), this, SLOT(writeSettings()));
connect(vSplitter, SIGNAL(splitterMoved(int, int)), this, SLOT(writeSettings()));
connect(properties, SIGNAL(trackersAdded(const QStringList &, const QString &)), transferListFilters, SLOT(addTrackers(const QStringList &, const QString &)));
connect(properties, SIGNAL(trackersRemoved(const QStringList &, const QString &)), transferListFilters, SLOT(removeTrackers(const QStringList &, const QString &)));
connect(properties, SIGNAL(trackerlessChange(bool, const QString &)), transferListFilters, SLOT(changeTrackerless(bool, const QString &)));
connect(QBtSession::instance(), SIGNAL(trackersAdded(const QStringList &, const QString &)), transferListFilters, SLOT(addTrackers(const QStringList &, const QString &)));
connect(QBtSession::instance(), SIGNAL(trackerlessChange(bool, const QString &)), transferListFilters, SLOT(changeTrackerless(bool, const QString &)));
connect(QBtSession::instance(), SIGNAL(reloadTrackersAndUrlSeeds(const QTorrentHandle &)), properties, SLOT(loadTrackers(const QTorrentHandle &)));
connect(QBtSession::instance(), SIGNAL(trackerSuccess(const QString &, const QString &)), transferListFilters, SIGNAL(trackerSuccess(const QString &, const QString &)));
connect(QBtSession::instance(), SIGNAL(trackerError(const QString &, const QString &)), transferListFilters, SIGNAL(trackerError(const QString &, const QString &)));
connect(QBtSession::instance(), SIGNAL(trackerWarning(const QString &, const QString &)), transferListFilters, SIGNAL(trackerWarning(const QString &, const QString &)));
connect(BitTorrent::Session::instance(), SIGNAL(trackersChanged(BitTorrent::TorrentHandle *const)), properties, SLOT(loadTrackers(BitTorrent::TorrentHandle *const)));
connect(BitTorrent::Session::instance(), SIGNAL(trackersAdded(BitTorrent::TorrentHandle *const, const QList<BitTorrent::TrackerEntry> &)), transferListFilters, SLOT(addTrackers(BitTorrent::TorrentHandle *const, const QList<BitTorrent::TrackerEntry> &)));
connect(BitTorrent::Session::instance(), SIGNAL(trackersRemoved(BitTorrent::TorrentHandle *const, const QList<BitTorrent::TrackerEntry> &)), transferListFilters, SLOT(removeTrackers(BitTorrent::TorrentHandle *const, const QList<BitTorrent::TrackerEntry> &)));
connect(BitTorrent::Session::instance(), SIGNAL(trackerlessStateChanged(BitTorrent::TorrentHandle *const, bool)), transferListFilters, SLOT(changeTrackerless(BitTorrent::TorrentHandle *const, bool)));
connect(BitTorrent::Session::instance(), SIGNAL(trackerSuccess(BitTorrent::TorrentHandle *const, const QString &)), transferListFilters, SLOT(trackerSuccess(BitTorrent::TorrentHandle *const, const QString &)));
connect(BitTorrent::Session::instance(), SIGNAL(trackerError(BitTorrent::TorrentHandle *const, const QString &)), transferListFilters, SLOT(trackerError(BitTorrent::TorrentHandle *const, const QString &)));
connect(BitTorrent::Session::instance(), SIGNAL(trackerWarning(BitTorrent::TorrentHandle *const, const QString &)), transferListFilters, SLOT(trackerWarning(BitTorrent::TorrentHandle *const, const QString &)));
vboxLayout->addWidget(tabs);
@@ -231,9 +224,9 @@ MainWindow::MainWindow(QWidget *parent)
// Transfer list slots
connect(actionStart, SIGNAL(triggered()), transferList, SLOT(startSelectedTorrents()));
connect(actionStart_All, SIGNAL(triggered()), QBtSession::instance(), SLOT(resumeAllTorrents()));
connect(actionStart_All, SIGNAL(triggered()), transferList, SLOT(resumeAllTorrents()));
connect(actionPause, SIGNAL(triggered()), transferList, SLOT(pauseSelectedTorrents()));
connect(actionPause_All, SIGNAL(triggered()), QBtSession::instance(), SLOT(pauseAllTorrents()));
connect(actionPause_All, SIGNAL(triggered()), transferList, SLOT(pauseAllTorrents()));
connect(actionDelete, SIGNAL(triggered()), transferList, SLOT(deleteSelectedTorrents()));
connect(actionTopPriority, SIGNAL(triggered()), transferList, SLOT(topPrioSelectedTorrents()));
connect(actionIncreasePriority, SIGNAL(triggered()), transferList, SLOT(increasePrioSelectedTorrents()));
@@ -258,10 +251,8 @@ MainWindow::MainWindow(QWidget *parent)
// Configure BT session according to options
loadPreferences(false);
// Start connection checking timer
guiUpdater = new QTimer(this);
connect(guiUpdater, SIGNAL(timeout()), this, SLOT(updateGUI()));
guiUpdater->start(2000);
connect(BitTorrent::Session::instance(), SIGNAL(torrentsUpdated()), this, SLOT(updateGUI()));
// Accept drag 'n drops
setAcceptDrops(true);
createKeyboardShortcuts();
@@ -516,7 +507,7 @@ void MainWindow::displayRSSTab(bool enable)
if (!rssWidget) {
rssWidget = new RSSImp(tabs);
int index_tab = tabs->addTab(rssWidget, tr("RSS"));
tabs->setTabIcon(index_tab, IconProvider::instance()->getIcon("application-rss+xml"));
tabs->setTabIcon(index_tab, GuiIconProvider::instance()->getIcon("application-rss+xml"));
}
}
else if (rssWidget) {
@@ -532,7 +523,7 @@ void MainWindow::displaySearchTab(bool enable)
// RSS tab
if (!searchEngine) {
searchEngine = new SearchEngine(this);
tabs->insertTab(1, searchEngine, IconProvider::instance()->getIcon("edit-find"), tr("Search"));
tabs->insertTab(1, searchEngine, GuiIconProvider::instance()->getIcon("edit-find"), tr("Search"));
}
}
else if (searchEngine) {
@@ -595,7 +586,6 @@ void MainWindow::cleanup()
writeSettings();
delete executable_watcher;
guiUpdater->stop();
if (systrayCreator)
systrayCreator->stop();
if (preventTimer)
@@ -643,18 +633,21 @@ void MainWindow::balloonClicked()
activateWindow();
}
// called when a torrent has finished
void MainWindow::finishedTorrent(const QTorrentHandle& h) const
void MainWindow::addTorrentFailed(const QString &error) const
{
if (TorrentPersistentData::instance()->isSeed(h.hash()))
showNotificationBaloon(tr("Download completion"), tr("%1 has finished downloading.", "e.g: xxx.avi has finished downloading.").arg(h.name()));
showNotificationBaloon(tr("Error"), tr("Failed to add torrent: %1").arg(error));
}
// called when a torrent has finished
void MainWindow::finishedTorrent(BitTorrent::TorrentHandle *const torrent) const
{
showNotificationBaloon(tr("Download completion"), tr("%1 has finished downloading.", "e.g: xxx.avi has finished downloading.").arg(torrent->name()));
}
// Notification when disk is full
void MainWindow::fullDiskError(const QTorrentHandle& h, QString msg) const
void MainWindow::fullDiskError(BitTorrent::TorrentHandle *const torrent, QString msg) const
{
if (!h.is_valid()) return;
showNotificationBaloon(tr("I/O Error", "i.e: Input/Output Error"), tr("An I/O error occurred for torrent %1.\n Reason: %2", "e.g: An error occurred for torrent xxx.avi.\n Reason: disk is full.").arg(h.name()).arg(msg));
showNotificationBaloon(tr("I/O Error", "i.e: Input/Output Error"), tr("An I/O error occurred for torrent %1.\n Reason: %2", "e.g: An error occurred for torrent xxx.avi.\n Reason: disk is full.").arg(torrent->name()).arg(msg));
}
void MainWindow::createKeyboardShortcuts()
@@ -709,28 +702,21 @@ void MainWindow::displayRSSTab() const
// End of keyboard shortcuts slots
void MainWindow::askRecursiveTorrentDownloadConfirmation(const QTorrentHandle &h)
void MainWindow::askRecursiveTorrentDownloadConfirmation(BitTorrent::TorrentHandle *const torrent)
{
Preferences* const pref = Preferences::instance();
if (pref->recursiveDownloadDisabled()) return;
// Get Torrent name
QString torrent_name;
try {
torrent_name = h.name();
} catch(invalid_handle&) {
return;
}
QString torrent_name = torrent->name();
QMessageBox confirmBox(QMessageBox::Question, tr("Recursive download confirmation"), tr("The torrent %1 contains torrent files, do you want to proceed with their download?").arg(torrent_name));
QPushButton *yes = confirmBox.addButton(tr("Yes"), QMessageBox::YesRole);
/*QPushButton *no = */ confirmBox.addButton(tr("No"), QMessageBox::NoRole);
QPushButton *never = confirmBox.addButton(tr("Never"), QMessageBox::NoRole);
confirmBox.exec();
if (confirmBox.clickedButton() == 0) return;
if (confirmBox.clickedButton() == yes) {
QBtSession::instance()->recursiveTorrentDownload(h);
return;
}
if (confirmBox.clickedButton() == never)
if (confirmBox.clickedButton() == yes)
BitTorrent::Session::instance()->recursiveTorrentDownload(torrent->hash());
else if (confirmBox.clickedButton() == never)
pref->disableRecursiveDownload();
}
@@ -744,11 +730,11 @@ void MainWindow::on_actionSet_global_upload_limit_triggered()
{
qDebug("actionSet_global_upload_limit_triggered");
bool ok;
int cur_limit = QBtSession::instance()->getSession()->settings().upload_rate_limit;
int cur_limit = BitTorrent::Session::instance()->uploadRateLimit();
const long new_limit = SpeedLimitDialog::askSpeedLimit(&ok, tr("Global Upload Speed Limit"), cur_limit);
if (ok) {
qDebug("Setting global upload rate limit to %.1fKb/s", new_limit / 1024.);
QBtSession::instance()->setUploadRateLimit(new_limit);
BitTorrent::Session::instance()->setUploadRateLimit(new_limit);
if (new_limit <= 0)
Preferences::instance()->setGlobalUploadLimit(-1);
else
@@ -760,11 +746,11 @@ void MainWindow::on_actionSet_global_download_limit_triggered()
{
qDebug("actionSet_global_download_limit_triggered");
bool ok;
int cur_limit = QBtSession::instance()->getSession()->settings().download_rate_limit;
int cur_limit = BitTorrent::Session::instance()->downloadRateLimit();
const long new_limit = SpeedLimitDialog::askSpeedLimit(&ok, tr("Global Download Speed Limit"), cur_limit);
if (ok) {
qDebug("Setting global download rate limit to %.1fKb/s", new_limit / 1024.);
QBtSession::instance()->setDownloadRateLimit(new_limit);
BitTorrent::Session::instance()->setDownloadRateLimit(new_limit);
if (new_limit <= 0)
Preferences::instance()->setGlobalDownloadLimit(-1);
else
@@ -904,7 +890,7 @@ void MainWindow::closeEvent(QCloseEvent *e)
return;
}
if (pref->confirmOnExit() && QBtSession::instance()->hasActiveTorrents()) {
if (pref->confirmOnExit() && BitTorrent::Session::instance()->hasActiveTorrents()) {
if (e->spontaneous() || force_exit) {
if (!isVisible())
show();
@@ -941,13 +927,10 @@ void MainWindow::closeEvent(QCloseEvent *e)
// Display window to create a torrent
void MainWindow::on_actionCreate_torrent_triggered()
{
if (createTorrentDlg) {
if (createTorrentDlg)
createTorrentDlg->setFocus();
}
else {
else
createTorrentDlg = new TorrentCreatorDlg(this);
connect(createTorrentDlg, SIGNAL(torrent_to_seed(QString)), this, SLOT(addTorrent(QString)));
}
}
bool MainWindow::event(QEvent * e)
@@ -1015,33 +998,15 @@ void MainWindow::dropEvent(QDropEvent *event)
else {
files = event->mimeData()->text().split(QString::fromUtf8("\n"));
}
// Add file to download list
Preferences* const pref = Preferences::instance();
const bool useTorrentAdditionDialog = pref->useAdditionDialog();
const bool useTorrentAdditionDialog = Preferences::instance()->useAdditionDialog();
foreach (QString file, files) {
qDebug("Dropped file %s on download list", qPrintable(file));
if (misc::isUrl(file)) {
QBtSession::instance()->downloadFromUrl(file);
continue;
}
// Bitcomet or Magnet link
if (file.startsWith("bc://bt/", Qt::CaseInsensitive)) {
qDebug("Converting bc link to magnet link");
file = misc::bcLinkToMagnet(file);
}
if (file.startsWith("magnet:", Qt::CaseInsensitive)) {
if (useTorrentAdditionDialog)
AddNewTorrentDialog::showMagnet(file, this);
else
QBtSession::instance()->addMagnetUri(file);
}
else {
// Local file
if (useTorrentAdditionDialog)
AddNewTorrentDialog::showTorrent(file, QString(), this);
else
QBtSession::instance()->addTorrent(file);
}
if (useTorrentAdditionDialog)
AddNewTorrentDialog::show(file, this);
else
BitTorrent::Session::instance()->addTorrent(file);
}
}
@@ -1067,22 +1032,22 @@ void MainWindow::on_actionOpen_triggered()
Preferences* const pref = Preferences::instance();
// Open File Open Dialog
// Note: it is possible to select more than one file
const QStringList pathsList = QFileDialog::getOpenFileNames(0,
tr("Open Torrent Files"), pref->getMainLastDir(),
tr("Torrent Files") + QString::fromUtf8(" (*.torrent)"));
if (!pathsList.empty()) {
const uint listSize = pathsList.size();
for (uint i = 0; i<listSize; ++i) {
if (pref->useAdditionDialog())
AddNewTorrentDialog::showTorrent(pathsList.at(i), QString(), this);
else
QBtSession::instance()->addTorrent(pathsList.at(i));
}
// Save last dir to remember it
QStringList top_dir = fsutils::fromNativePath(pathsList.at(0)).split("/");
top_dir.removeLast();
pref->setMainLastDir(fsutils::fromNativePath(top_dir.join("/")));
const QStringList pathsList =
QFileDialog::getOpenFileNames(0, tr("Open Torrent Files"), pref->getMainLastDir(),
tr("Torrent Files") + QString::fromUtf8(" (*.torrent)"));
const bool useTorrentAdditionDialog = Preferences::instance()->useAdditionDialog();
foreach (QString file, pathsList) {
qDebug("Dropped file %s on download list", qPrintable(file));
if (useTorrentAdditionDialog)
AddNewTorrentDialog::show(file, this);
else
BitTorrent::Session::instance()->addTorrent(file);
}
// Save last dir to remember it
QStringList top_dir = fsutils::fromNativePath(pathsList.at(0)).split("/");
top_dir.removeLast();
pref->setMainLastDir(fsutils::fromNativePath(top_dir.join("/")));
}
void MainWindow::activate()
@@ -1094,29 +1059,6 @@ void MainWindow::activate()
}
}
void MainWindow::addTorrent(QString path)
{
QBtSession::instance()->addTorrent(path);
}
void MainWindow::processDownloadedFiles(QString path, QString url)
{
Preferences* const pref = Preferences::instance();
if (pref->useAdditionDialog())
AddNewTorrentDialog::showTorrent(path, url, this);
else
QBtSession::instance()->addTorrent(path, false, url);
}
void MainWindow::processNewMagnetLink(const QString& link)
{
Preferences* const pref = Preferences::instance();
if (pref->useAdditionDialog())
AddNewTorrentDialog::showMagnet(link, this);
else
QBtSession::instance()->addMagnetUri(link);
}
void MainWindow::optionsSaved()
{
loadPreferences();
@@ -1175,8 +1117,6 @@ void MainWindow::loadPreferences(bool configure_session)
m_pwr->setActivityState(false);
}
const uint new_refreshInterval = pref->getRefreshInterval();
transferList->setRefreshInterval(new_refreshInterval);
transferList->setAlternatingRowColors(pref->useAlternatingRowColors());
properties->getFilesList()->setAlternatingRowColors(pref->useAlternatingRowColors());
properties->getTrackerList()->setAlternatingRowColors(pref->useAlternatingRowColors());
@@ -1209,11 +1149,6 @@ void MainWindow::loadPreferences(bool configure_session)
// Torrent properties
properties->reloadPreferences();
// Icon provider
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
IconProvider::instance()->useSystemIconTheme(pref->useSystemIconTheme());
#endif
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
if (pref->isUpdateCheckEnabled())
checkProgramUpdate();
@@ -1224,7 +1159,7 @@ void MainWindow::loadPreferences(bool configure_session)
qDebug("GUI settings loaded");
}
void MainWindow::addUnauthenticatedTracker(const QPair<QTorrentHandle,QString> &tracker)
void MainWindow::addUnauthenticatedTracker(const QPair<BitTorrent::TorrentHandle *const, QString> &tracker)
{
// Trackers whose authentication was cancelled
if (unauthenticated_trackers.indexOf(tracker) < 0)
@@ -1232,16 +1167,18 @@ void MainWindow::addUnauthenticatedTracker(const QPair<QTorrentHandle,QString> &
}
// Called when a tracker requires authentication
void MainWindow::trackerAuthenticationRequired(const QTorrentHandle& h)
void MainWindow::trackerAuthenticationRequired(BitTorrent::TorrentHandle *const torrent)
{
if (unauthenticated_trackers.indexOf(QPair<QTorrentHandle,QString>(h, h.current_tracker())) < 0)
if (unauthenticated_trackers.indexOf(QPair<BitTorrent::TorrentHandle *const, QString>(torrent, torrent->currentTracker())) < 0)
// Tracker login
new trackerLogin(this, h);
new trackerLogin(this, torrent);
}
// Check connection status and display right icon
void MainWindow::updateGUI()
{
BitTorrent::SessionStatus status = BitTorrent::Session::instance()->status();
// update global informations
if (systrayIcon) {
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
@@ -1249,21 +1186,21 @@ void MainWindow::updateGUI()
html += "qBittorrent";
html += "</div>";
html += "<div style='vertical-align: baseline; height: 18px;'>";
html += "<img src=':/icons/skin/download.png'/>&nbsp;" + tr("DL speed: %1", "e.g: Download speed: 10 KiB/s").arg(misc::friendlyUnit(QBtSession::instance()->getPayloadDownloadRate(), true));
html += "<img src=':/icons/skin/download.png'/>&nbsp;" + tr("DL speed: %1", "e.g: Download speed: 10 KiB/s").arg(misc::friendlyUnit(status.payloadDownloadRate(), true));
html += "</div>";
html += "<div style='vertical-align: baseline; height: 18px;'>";
html += "<img src=':/icons/skin/seeding.png'/>&nbsp;" + tr("UP speed: %1", "e.g: Upload speed: 10 KiB/s").arg(misc::friendlyUnit(QBtSession::instance()->getPayloadUploadRate(), true));
html += "<img src=':/icons/skin/seeding.png'/>&nbsp;" + tr("UP speed: %1", "e.g: Upload speed: 10 KiB/s").arg(misc::friendlyUnit(status.payloadUploadRate(), true));
html += "</div>";
#else
// OSes such as Windows do not support html here
QString html = tr("DL speed: %1", "e.g: Download speed: 10 KiB/s").arg(misc::friendlyUnit(QBtSession::instance()->getPayloadDownloadRate(), true));
QString html = tr("DL speed: %1", "e.g: Download speed: 10 KiB/s").arg(misc::friendlyUnit(status.payloadDownloadRate(), true));
html += "\n";
html += tr("UP speed: %1", "e.g: Upload speed: 10 KiB/s").arg(misc::friendlyUnit(QBtSession::instance()->getPayloadUploadRate(), true));
html += tr("UP speed: %1", "e.g: Upload speed: 10 KiB/s").arg(misc::friendlyUnit(status.payloadUploadRate(), true));
#endif
systrayIcon->setToolTip(html); // tray icon
}
if (displaySpeedInTitle)
setWindowTitle(tr("[D: %1, U: %2] qBittorrent %3", "D = Download; U = Upload; %3 is qBittorrent version").arg(misc::friendlyUnit(QBtSession::instance()->getPayloadDownloadRate(), true)).arg(misc::friendlyUnit(QBtSession::instance()->getPayloadUploadRate(), true)).arg(QString::fromUtf8(VERSION)));
setWindowTitle(tr("[D: %1, U: %2] qBittorrent %3", "D = Download; U = Upload; %3 is qBittorrent version").arg(misc::friendlyUnit(status.payloadDownloadRate(), true)).arg(misc::friendlyUnit(status.payloadUploadRate(), true)).arg(QString::fromUtf8(VERSION)));
}
void MainWindow::showNotificationBaloon(QString title, QString msg) const
@@ -1302,26 +1239,16 @@ void MainWindow::showNotificationBaloon(QString title, QString msg) const
void MainWindow::downloadFromURLList(const QStringList& url_list)
{
Preferences* const pref = Preferences::instance();
const bool useTorrentAdditionDialog = pref->useAdditionDialog();
const bool useTorrentAdditionDialog = Preferences::instance()->useAdditionDialog();
foreach (QString url, url_list) {
if (url.startsWith("bc://bt/", Qt::CaseInsensitive)) {
qDebug("Converting bc link to magnet link");
url = misc::bcLinkToMagnet(url);
}
if ((url.size() == 40 && !url.contains(QRegExp("[^0-9A-Fa-f]")))
|| (url.size() == 32 && !url.contains(QRegExp("[^2-7A-Za-z]"))))
url = "magnet:?xt=urn:btih:" + url;
if (url.startsWith("magnet:", Qt::CaseInsensitive)) {
if (useTorrentAdditionDialog)
AddNewTorrentDialog::showMagnet(url, this);
else
QBtSession::instance()->addMagnetUri(url);
}
else if (url.startsWith("http://", Qt::CaseInsensitive) || url.startsWith("https://", Qt::CaseInsensitive)
|| url.startsWith("ftp://", Qt::CaseInsensitive)) {
QBtSession::instance()->downloadFromUrl(url);
}
if (useTorrentAdditionDialog)
AddNewTorrentDialog::show(url, this);
else
BitTorrent::Session::instance()->addTorrent(url);
}
}
@@ -1549,7 +1476,7 @@ void MainWindow::on_actionExecution_Logs_triggered(bool checked)
Q_ASSERT(!m_executionLog);
m_executionLog = new ExecutionLog(tabs);
int index_tab = tabs->addTab(m_executionLog, tr("Execution Log"));
tabs->setTabIcon(index_tab, IconProvider::instance()->getIcon("view-calendar-journal"));
tabs->setTabIcon(index_tab, GuiIconProvider::instance()->getIcon("view-calendar-journal"));
}
else if (m_executionLog) {
delete m_executionLog;
@@ -1583,7 +1510,7 @@ void MainWindow::on_actionAutoShutdown_system_toggled(bool enabled)
void MainWindow::checkForActiveTorrents()
{
m_pwr->setActivityState(transferList->getSourceModel()->inhibitSystem());
m_pwr->setActivityState(BitTorrent::Session::instance()->hasActiveTorrents());
}
QIcon MainWindow::getSystrayIcon() const
@@ -1650,21 +1577,20 @@ void MainWindow::installPython()
{
setCursor(QCursor(Qt::WaitCursor));
// Download python
DownloadThread *pydownloader = new DownloadThread(this);
connect(pydownloader, SIGNAL(downloadFinished(QString,QString)), this, SLOT(pythonDownloadSuccess(QString,QString)));
connect(pydownloader, SIGNAL(downloadFailure(QString,QString)), this, SLOT(pythonDownloadFailure(QString,QString)));
pydownloader->downloadUrl("http://python.org/ftp/python/2.7.3/python-2.7.3.msi");
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl("http://python.org/ftp/python/2.7.3/python-2.7.3.msi");
connect(handler, SIGNAL(downloadFinished(QString, QString)), this, SLOT(pythonDownloadSuccess(QString, QString)));
connect(handler, SIGNAL(downloadFailed(QString, QString)), this, SLOT(pythonDownloadFailure(QString, QString)));
}
void MainWindow::pythonDownloadSuccess(QString url, QString file_path)
void MainWindow::pythonDownloadSuccess(const QString &url, const QString &filePath)
{
Q_UNUSED(url)
setCursor(QCursor(Qt::ArrowCursor));
Q_UNUSED(url);
QFile::rename(file_path, file_path + ".msi");
QFile::rename(filePath, filePath + ".msi");
QProcess installer;
qDebug("Launching Python installer in passive mode...");
installer.start("msiexec.exe /passive /i " + fsutils::toNativePath(file_path) + ".msi");
installer.start("msiexec.exe /passive /i " + fsutils::toNativePath(filePath) + ".msi");
// Wait for setup to complete
installer.waitForFinished();
@@ -1672,21 +1598,19 @@ void MainWindow::pythonDownloadSuccess(QString url, QString file_path)
qDebug("Installer stderr: %s", installer.readAllStandardError().data());
qDebug("Setup should be complete!");
// Delete temp file
fsutils::forceRemove(file_path);
fsutils::forceRemove(filePath);
// Reload search engine
has_python = addPythonPathToEnv();
if (has_python) {
actionSearch_engine->setChecked(true);
displaySearchTab(true);
}
sender()->deleteLater();
}
void MainWindow::pythonDownloadFailure(QString url, QString error)
void MainWindow::pythonDownloadFailure(const QString &url, const QString &error)
{
Q_UNUSED(url);
Q_UNUSED(url)
setCursor(QCursor(Qt::ArrowCursor));
QMessageBox::warning(this, tr("Download error"), tr("Python setup could not be downloaded, reason: %1.\nPlease install it manually.").arg(error));
sender()->deleteLater();
}
#endif

View File

@@ -35,10 +35,8 @@
#include <QSystemTrayIcon>
#include <QPointer>
#include "ui_mainwindow.h"
#include "qtorrenthandle.h"
#include "statsdialog.h"
class QBtSession;
class downloadFromURL;
class SearchEngine;
class RSSImp;
@@ -64,6 +62,11 @@ class QTabWidget;
class QTimer;
QT_END_NAMESPACE
namespace BitTorrent
{
class TorrentHandle;
}
class MainWindow: public QMainWindow, private Ui::MainWindow
{
Q_OBJECT
@@ -79,7 +82,7 @@ public:
PropertiesWidget *getProperties() const { return properties; }
public slots:
void trackerAuthenticationRequired(const QTorrentHandle& h);
void trackerAuthenticationRequired(BitTorrent::TorrentHandle *const torrent);
void setTabText(int index, QString text) const;
void showNotificationBaloon(QString title, QString msg) const;
void downloadFromURLList(const QStringList& urls);
@@ -101,7 +104,7 @@ protected slots:
void readSettings();
void on_actionExit_triggered();
void createTrayIcon();
void fullDiskError(const QTorrentHandle& h, QString msg) const;
void fullDiskError(BitTorrent::TorrentHandle *const torrent, QString msg) const;
void handleDownloadFromUrlFailure(QString, QString) const;
void createSystrayDelayed();
void tab_changed(int);
@@ -125,12 +128,10 @@ protected slots:
void on_actionOpen_triggered();
void updateGUI();
void loadPreferences(bool configure_session = true);
void addTorrent(QString path);
void addUnauthenticatedTracker(const QPair<QTorrentHandle,QString> &tracker);
void processDownloadedFiles(QString path, QString url);
void processNewMagnetLink(const QString& link);
void finishedTorrent(const QTorrentHandle& h) const;
void askRecursiveTorrentDownloadConfirmation(const QTorrentHandle &h);
void addUnauthenticatedTracker(const QPair<BitTorrent::TorrentHandle *const, QString> &tracker);
void addTorrentFailed(const QString &error) const;
void finishedTorrent(BitTorrent::TorrentHandle *const torrent) const;
void askRecursiveTorrentDownloadConfirmation(BitTorrent::TorrentHandle *const torrent);
// Options slots
void on_actionOptions_triggered();
void optionsSaved();
@@ -156,18 +157,17 @@ private:
void installPython();
private slots:
void pythonDownloadSuccess(QString url, QString file_path);
void pythonDownloadFailure(QString url, QString error);
void pythonDownloadSuccess(const QString &url, const QString &filePath);
void pythonDownloadFailure(const QString &url, const QString &error);
#endif
void addToolbarContextMenu();
private:
QFileSystemWatcher *executable_watcher;
// Bittorrent
QList<QPair<QTorrentHandle,QString> > unauthenticated_trackers; // Still needed?
QList<QPair<BitTorrent::TorrentHandle *const, QString> > unauthenticated_trackers; // Still needed?
// GUI related
bool m_posInitialized;
QTimer *guiUpdater;
QTabWidget *tabs;
StatusBar *status_bar;
QPointer<options_imp> options;

View File

@@ -45,9 +45,9 @@
#include "core/preferences.h"
#include "core/fs_utils.h"
#include "advancedsettings.h"
#include "core/scannedfoldersmodel.h"
#include "qbtsession.h"
#include "iconprovider.h"
#include "core/scanfoldersmodel.h"
#include "core/bittorrent/session.h"
#include "guiiconprovider.h"
#include "core/net/dnsupdater.h"
#ifndef QT_NO_OPENSSL
@@ -55,8 +55,6 @@
#include <QSslCertificate>
#endif
using namespace libtorrent;
// Constructor
options_imp::options_imp(QWidget *parent):
QDialog(parent), m_refreshingIpFilter(false) {
@@ -65,18 +63,18 @@ options_imp::options_imp(QWidget *parent):
setAttribute(Qt::WA_DeleteOnClose);
setModal(true);
// Icons
tabSelection->item(TAB_UI)->setIcon(IconProvider::instance()->getIcon("preferences-desktop"));
tabSelection->item(TAB_BITTORRENT)->setIcon(IconProvider::instance()->getIcon("preferences-system-network"));
tabSelection->item(TAB_CONNECTION)->setIcon(IconProvider::instance()->getIcon("network-wired"));
tabSelection->item(TAB_DOWNLOADS)->setIcon(IconProvider::instance()->getIcon("download"));
tabSelection->item(TAB_SPEED)->setIcon(IconProvider::instance()->getIcon("chronometer"));
tabSelection->item(TAB_UI)->setIcon(GuiIconProvider::instance()->getIcon("preferences-desktop"));
tabSelection->item(TAB_BITTORRENT)->setIcon(GuiIconProvider::instance()->getIcon("preferences-system-network"));
tabSelection->item(TAB_CONNECTION)->setIcon(GuiIconProvider::instance()->getIcon("network-wired"));
tabSelection->item(TAB_DOWNLOADS)->setIcon(GuiIconProvider::instance()->getIcon("download"));
tabSelection->item(TAB_SPEED)->setIcon(GuiIconProvider::instance()->getIcon("chronometer"));
#ifndef DISABLE_WEBUI
tabSelection->item(TAB_WEBUI)->setIcon(IconProvider::instance()->getIcon("network-server"));
tabSelection->item(TAB_WEBUI)->setIcon(GuiIconProvider::instance()->getIcon("network-server"));
#else
tabSelection->item(TAB_WEBUI)->setHidden(true);
#endif
tabSelection->item(TAB_ADVANCED)->setIcon(IconProvider::instance()->getIcon("preferences-other"));
IpFilterRefreshBtn->setIcon(IconProvider::instance()->getIcon("view-refresh"));
tabSelection->item(TAB_ADVANCED)->setIcon(GuiIconProvider::instance()->getIcon("preferences-other"));
IpFilterRefreshBtn->setIcon(GuiIconProvider::instance()->getIcon("view-refresh"));
hsplitter->setCollapsible(0, false);
hsplitter->setCollapsible(1, false);
@@ -494,7 +492,7 @@ void options_imp::saveOptions() {
advancedSettings->saveAdvancedSettings();
// Assume that user changed multiple settings
// so it's best to save immediately
pref->save();
pref->apply();
}
bool options_imp::isFilteringEnabled() const {
@@ -1250,9 +1248,9 @@ void options_imp::on_IpFilterRefreshBtn_clicked() {
pref->setFilteringEnabled(true);
pref->setFilter(getFilter());
// Force refresh
connect(QBtSession::instance(), SIGNAL(ipFilterParsed(bool, int)), SLOT(handleIPFilterParsed(bool, int)));
connect(BitTorrent::Session::instance(), SIGNAL(ipFilterParsed(bool, int)), SLOT(handleIPFilterParsed(bool, int)));
setCursor(QCursor(Qt::WaitCursor));
QBtSession::instance()->enableIPFilter(getFilter(), true);
BitTorrent::Session::instance()->enableIPFilter(getFilter(), true);
}
void options_imp::handleIPFilterParsed(bool error, int ruleCount)
@@ -1264,7 +1262,7 @@ void options_imp::handleIPFilterParsed(bool error, int ruleCount)
QMessageBox::information(this, tr("Successfully refreshed"), tr("Successfully parsed the provided IP filter: %1 rules were applied.", "%1 is a number").arg(ruleCount));
}
m_refreshingIpFilter = false;
disconnect(QBtSession::instance(), SIGNAL(ipFilterParsed(bool, int)), this, SLOT(handleIPFilterParsed(bool, int)));
disconnect(BitTorrent::Session::instance(), SIGNAL(ipFilterParsed(bool, int)), this, SLOT(handleIPFilterParsed(bool, int)));
}
QString options_imp::languageToLocalizedString(const QLocale &locale)

View File

@@ -33,16 +33,16 @@
#include <QMessageBox>
#include <QFile>
#include <libtorrent/version.hpp>
#include <libtorrent/session.hpp>
#include "core/misc.h"
#include "previewlistdelegate.h"
#include "previewselect.h"
#include "core/fs_utils.h"
#include "core/preferences.h"
PreviewSelect::PreviewSelect(QWidget* parent, QTorrentHandle h): QDialog(parent), h(h) {
PreviewSelect::PreviewSelect(QWidget* parent, BitTorrent::TorrentHandle *const torrent)
: QDialog(parent)
, m_torrent(torrent)
{
setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
Preferences* const pref = Preferences::instance();
@@ -58,11 +58,10 @@ PreviewSelect::PreviewSelect(QWidget* parent, QTorrentHandle h): QDialog(parent)
previewList->header()->resizeSection(0, 200);
previewList->setAlternatingRowColors(pref->useAlternatingRowColors());
// Fill list in
std::vector<libtorrent::size_type> fp;
h.file_progress(fp);
unsigned int nbFiles = h.num_files();
for (unsigned int i=0; i<nbFiles; ++i) {
QString fileName = h.filename_at(i);
QVector<qreal> fp = torrent->filesProgress();
uint nbFiles = torrent->filesCount();
for (uint i = 0; i < nbFiles; ++i) {
QString fileName = torrent->fileName(i);
if (fileName.endsWith(".!qB"))
fileName.chop(4);
QString extension = fsutils::fileExtension(fileName).toUpper();
@@ -70,8 +69,8 @@ PreviewSelect::PreviewSelect(QWidget* parent, QTorrentHandle h): QDialog(parent)
int row = previewListModel->rowCount();
previewListModel->insertRow(row);
previewListModel->setData(previewListModel->index(row, NAME), QVariant(fileName));
previewListModel->setData(previewListModel->index(row, SIZE), QVariant((qlonglong)h.filesize_at(i)));
previewListModel->setData(previewListModel->index(row, PROGRESS), QVariant((double)fp[i]/h.filesize_at(i)));
previewListModel->setData(previewListModel->index(row, SIZE), QVariant(torrent->fileSize(i)));
previewListModel->setData(previewListModel->index(row, PROGRESS), QVariant(fp[i]));
previewListModel->setData(previewListModel->index(row, FILE_INDEX), QVariant(i));
}
}
@@ -105,9 +104,9 @@ void PreviewSelect::on_previewButton_clicked() {
QModelIndexList selectedIndexes = previewList->selectionModel()->selectedRows(FILE_INDEX);
if (selectedIndexes.size() == 0) return;
// Flush data
h.flush_cache();
m_torrent->flushCache();
QStringList absolute_paths(h.absolute_files_path());
QStringList absolute_paths(m_torrent->absoluteFilePaths());
//only one file should be selected
QString path = absolute_paths.at(selectedIndexes.at(0).data().toInt());
// File

View File

@@ -34,7 +34,7 @@
#include <QDialog>
#include <QList>
#include "ui_preview.h"
#include "qtorrenthandle.h"
#include "core/bittorrent/torrenthandle.h"
class PreviewListDelegate;
@@ -49,7 +49,7 @@ public:
enum PreviewColumn { NAME, SIZE, PROGRESS, FILE_INDEX, NB_COLUMNS };
public:
PreviewSelect(QWidget* parent, QTorrentHandle h);
PreviewSelect(QWidget* parent, BitTorrent::TorrentHandle *const torrent);
~PreviewSelect();
signals:
@@ -62,8 +62,7 @@ protected slots:
private:
QStandardItemModel *previewListModel;
PreviewListDelegate *listDelegate;
QTorrentHandle h;
BitTorrent::TorrentHandle *const m_torrent;
};
#endif

View File

@@ -28,28 +28,25 @@
* Contact : chris@qbittorrent.org
*/
#include <cmath>
#include "downloadedpiecesbar.h"
//#include <QDebug>
DownloadedPiecesBar::DownloadedPiecesBar(QWidget *parent): QWidget(parent)
{
setFixedHeight(BAR_HEIGHT);
bg_color = 0xffffff;
border_color = palette().color(QPalette::Dark).rgb();
piece_color = 0x0000ff;
piece_color_dl = 0x00d000;
m_bgColor = 0xffffff;
m_borderColor = palette().color(QPalette::Dark).rgb();
m_pieceColor = 0x0000ff;
m_dlPieceColor = 0x00d000;
updatePieceColors();
}
std::vector<float> DownloadedPiecesBar::bitfieldToFloatVector(const libtorrent::bitfield &vecin, int reqSize)
QVector<float> DownloadedPiecesBar::bitfieldToFloatVector(const QBitArray &vecin, int reqSize)
{
std::vector<float> result(reqSize, 0.0);
if (vecin.empty())
return result;
QVector<float> result(reqSize, 0.0);
if (vecin.isEmpty()) return result;
const float ratio = vecin.size() / (float)reqSize;
@@ -154,18 +151,18 @@ void DownloadedPiecesBar::updateImage()
// qDebug() << "updateImage";
QImage image2(width() - 2, 1, QImage::Format_RGB888);
if (pieces.empty()) {
if (m_pieces.isEmpty()) {
image2.fill(0xffffff);
image = image2;
m_image = image2;
update();
return;
}
std::vector<float> scaled_pieces = bitfieldToFloatVector(pieces, image2.width());
std::vector<float> scaled_pieces_dl = bitfieldToFloatVector(pieces_dl, image2.width());
QVector<float> scaled_pieces = bitfieldToFloatVector(m_pieces, image2.width());
QVector<float> scaled_pieces_dl = bitfieldToFloatVector(m_downloadedPieces, image2.width());
// filling image
for (unsigned int x = 0; x < scaled_pieces.size(); ++x)
for (int x = 0; x < scaled_pieces.size(); ++x)
{
float pieces2_val = scaled_pieces.at(x);
float pieces2_val_dl = scaled_pieces_dl.at(x);
@@ -174,23 +171,23 @@ void DownloadedPiecesBar::updateImage()
float fill_ratio = pieces2_val + pieces2_val_dl;
float ratio = pieces2_val_dl / fill_ratio;
int mixedColor = mixTwoColors(piece_color, piece_color_dl, ratio);
mixedColor = mixTwoColors(bg_color, mixedColor, fill_ratio);
int mixedColor = mixTwoColors(m_pieceColor, m_dlPieceColor, ratio);
mixedColor = mixTwoColors(m_bgColor, mixedColor, fill_ratio);
image2.setPixel(x, 0, mixedColor);
}
else
{
image2.setPixel(x, 0, piece_colors[pieces2_val * 255]);
image2.setPixel(x, 0, m_pieceColors[pieces2_val * 255]);
}
}
image = image2;
m_image = image2;
}
void DownloadedPiecesBar::setProgress(const libtorrent::bitfield &bf, const libtorrent::bitfield &bf_dl)
void DownloadedPiecesBar::setProgress(const QBitArray &pieces, const QBitArray &downloadedPieces)
{
pieces = libtorrent::bitfield(bf);
pieces_dl = libtorrent::bitfield(bf_dl);
m_pieces = pieces;
m_downloadedPieces = downloadedPieces;
updateImage();
update();
@@ -198,16 +195,16 @@ void DownloadedPiecesBar::setProgress(const libtorrent::bitfield &bf, const libt
void DownloadedPiecesBar::updatePieceColors()
{
piece_colors = std::vector<int>(256);
m_pieceColors = QVector<int>(256);
for (int i = 0; i < 256; ++i) {
float ratio = (i / 255.0);
piece_colors[i] = mixTwoColors(bg_color, piece_color, ratio);
m_pieceColors[i] = mixTwoColors(m_bgColor, m_pieceColor, ratio);
}
}
void DownloadedPiecesBar::clear()
{
image = QImage();
m_image = QImage();
update();
}
@@ -215,30 +212,30 @@ void DownloadedPiecesBar::paintEvent(QPaintEvent *)
{
QPainter painter(this);
QRect imageRect(1, 1, width() - 2, height() - 2);
if (image.isNull())
if (m_image.isNull())
{
painter.setBrush(Qt::white);
painter.drawRect(imageRect);
}
else
{
if (image.width() != imageRect.width())
if (m_image.width() != imageRect.width())
updateImage();
painter.drawImage(imageRect, image);
painter.drawImage(imageRect, m_image);
}
QPainterPath border;
border.addRect(0, 0, width() - 1, height() - 1);
painter.setPen(border_color);
painter.setPen(m_borderColor);
painter.drawPath(border);
}
void DownloadedPiecesBar::setColors(int background, int border, int complete, int incomplete)
{
bg_color = background;
border_color = border;
piece_color = complete;
piece_color_dl = incomplete;
m_bgColor = background;
m_borderColor = border;
m_pieceColor = complete;
m_dlPieceColor = incomplete;
updatePieceColors();
updateImage();

View File

@@ -34,8 +34,8 @@
#include <QWidget>
#include <QPainter>
#include <QImage>
#include <cmath>
#include <libtorrent/bitfield.hpp>
#include <QBitArray>
#include <QVector>
#define BAR_HEIGHT 18
@@ -44,28 +44,28 @@ class DownloadedPiecesBar: public QWidget {
Q_DISABLE_COPY(DownloadedPiecesBar)
private:
QImage image;
QImage m_image;
// I used values, bacause it should be possible to change colors in runtime
// background color
int bg_color;
int m_bgColor;
// border color
int border_color;
int m_borderColor;
// complete piece color
int piece_color;
int m_pieceColor;
// incomplete piece color
int piece_color_dl;
int m_dlPieceColor;
// buffered 256 levels gradient from bg_color to piece_color
std::vector<int> piece_colors;
QVector<int> m_pieceColors;
// last used bitfields, uses to better resize redraw
// TODO: make a diff pieces to new pieces and update only changed pixels, speedup when update > 20x faster
libtorrent::bitfield pieces;
libtorrent::bitfield pieces_dl;
QBitArray m_pieces;
QBitArray m_downloadedPieces;
// scale bitfield vector to float vector
std::vector<float> bitfieldToFloatVector(const libtorrent::bitfield &vecin, int reqSize);
QVector<float> bitfieldToFloatVector(const QBitArray &vecin, int reqSize);
// mix two colors by light model, ratio <0, 1>
int mixTwoColors(int &rgb1, int &rgb2, float ratio);
// draw new image and replace actual image
@@ -74,7 +74,7 @@ private:
public:
DownloadedPiecesBar(QWidget *parent);
void setProgress(const libtorrent::bitfield &bf, const libtorrent::bitfield &bf_dl);
void setProgress(const QBitArray &m_pieces, const QBitArray &downloadedPieces);
void updatePieceColors();
void clear();

View File

@@ -1,5 +1,5 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
@@ -34,72 +34,62 @@
#include <QDialog>
#include <QRegExp>
#include <QMessageBox>
#include <QHostAddress>
#include "core/bittorrent/peerinfo.h"
#include "ui_peer.h"
#include <libtorrent/socket.hpp>
#include <libtorrent/address.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
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();
PeerAdditionDlg(QWidget *parent=0)
: QDialog(parent)
{
setupUi(this);
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
connect(buttonBox, SIGNAL(accepted()), this, SLOT(validateInput()));
}
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());
~PeerAdditionDlg()
{
}
QHostAddress getAddress() const
{
return QHostAddress(lineIP->text());
}
ushort getPort() const
{
return spinPort->value();
}
static BitTorrent::PeerAddress askForPeerAddress()
{
BitTorrent::PeerAddress addr;
PeerAdditionDlg dlg;
if (dlg.exec() == QDialog::Accepted) {
addr.ip = dlg.getAddress();
if (addr.ip.isNull())
qDebug("Unable to parse the provided IP.");
else
qDebug("Provided IP is correct");
addr.port = dlg.getPort();
}
return addr;
}
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();
void validateInput() {
if (getAddress().isNull())
QMessageBox::warning(this, tr("Invalid IP"), tr("The IP you provided is invalid."), QMessageBox::Ok);
else
accept();
}
}
};
#endif // PEERADDITION_H

View File

@@ -37,19 +37,17 @@
#include "geoipmanager.h"
#include "peeraddition.h"
#include "speedlimitdlg.h"
#include "iconprovider.h"
#include "qtorrenthandle.h"
#include "guiiconprovider.h"
#include "core/bittorrent/torrenthandle.h"
#include "core/bittorrent/peerinfo.h"
#include "core/logger.h"
#include <QStandardItemModel>
#include <QSortFilterProxyModel>
#include <QSet>
#include <QHeaderView>
#include <QMenu>
#include <QClipboard>
#include <vector>
#include <libtorrent/peer_info.hpp>
using namespace libtorrent;
PeerListWidget::PeerListWidget(PropertiesWidget *parent):
QTreeView(parent), m_properties(parent), m_displayFlags(false)
@@ -149,8 +147,9 @@ void PeerListWidget::showPeerListMenu(const QPoint&)
{
QMenu menu;
bool empty_menu = true;
QTorrentHandle h = m_properties->getCurrentTorrent();
if (!h.is_valid()) return;
BitTorrent::TorrentHandle *const torrent = m_properties->getCurrentTorrent();
if (!torrent) return;
QModelIndexList selectedIndexes = selectionModel()->selectedRows();
QStringList selectedPeerIPs;
QStringList selectedPeerIPPort;
@@ -163,55 +162,34 @@ void PeerListWidget::showPeerListMenu(const QPoint&)
}
// 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..."));
if (!torrent->isQueued() && !torrent->isChecking()) {
addPeerAct = menu.addAction(GuiIconProvider::instance()->getIcon("user-group-new"), tr("Add a new peer..."));
empty_menu = false;
}
// Per Peer Speed limiting actions
#if LIBTORRENT_VERSION_NUM < 10000
QAction *upLimitAct = 0;
QAction *dlLimitAct = 0;
#endif
QAction *banAct = 0;
QAction *copyPeerAct = 0;
if (!selectedPeerIPs.isEmpty()) {
copyPeerAct = menu.addAction(IconProvider::instance()->getIcon("edit-copy"), tr("Copy selected"));
copyPeerAct = menu.addAction(GuiIconProvider::instance()->getIcon("edit-copy"), tr("Copy selected"));
menu.addSeparator();
#if LIBTORRENT_VERSION_NUM < 10000
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();
#endif
banAct = menu.addAction(IconProvider::instance()->getIcon("user-group-delete"), tr("Ban peer permanently"));
banAct = menu.addAction(GuiIconProvider::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) {
boost::asio::ip::tcp::endpoint ep = PeerAdditionDlg::askForPeerEndpoint();
if (ep != boost::asio::ip::tcp::endpoint()) {
try {
h.connect_peer(ep);
BitTorrent::PeerAddress addr = PeerAdditionDlg::askForPeerAddress();
if (!addr.ip.isNull()) {
if (torrent->connectPeer(addr))
QMessageBox::information(0, tr("Peer addition"), tr("The peer was added to this torrent."));
} catch(std::exception) {
else
QMessageBox::critical(0, tr("Peer addition"), tr("The peer could not be added to this torrent."));
}
} else {
}
else {
qDebug("No peer was added");
}
return;
}
#if LIBTORRENT_VERSION_NUM < 10000
if (act == upLimitAct) {
limitUpRateSelectedPeers(selectedPeerIPs);
return;
}
if (act == dlLimitAct) {
limitDlRateSelectedPeers(selectedPeerIPs);
return;
}
#endif
if (act == banAct) {
banSelectedPeers(selectedPeerIPs);
return;
@@ -237,84 +215,16 @@ void PeerListWidget::banSelectedPeers(const QStringList& peer_ips)
foreach (const QString &ip, peer_ips) {
qDebug("Banning peer %s...", ip.toLocal8Bit().data());
Logger::instance()->addMessage(tr("Manually banning peer %1...").arg(ip));
QBtSession::instance()->banIP(ip);
BitTorrent::Session::instance()->banIP(ip);
}
// Refresh list
loadPeers(m_properties->getCurrentTorrent());
}
#if LIBTORRENT_VERSION_NUM < 10000
void PeerListWidget::limitUpRateSelectedPeers(const QStringList& peer_ips)
{
if (peer_ips.empty())
return;
QTorrentHandle h = m_properties->getCurrentTorrent();
if (!h.is_valid())
return;
bool ok = false;
int cur_limit = -1;
boost::asio::ip::tcp::endpoint first_ep = m_peerEndpoints.value(peer_ips.first(),
boost::asio::ip::tcp::endpoint());
if (first_ep != boost::asio::ip::tcp::endpoint())
cur_limit = h.get_peer_upload_limit(first_ep);
long limit = SpeedLimitDialog::askSpeedLimit(&ok,
tr("Upload rate limiting"),
cur_limit,
Preferences::instance()->getGlobalUploadLimit()*1024.);
if (!ok)
return;
foreach (const QString &ip, peer_ips) {
boost::asio::ip::tcp::endpoint ep = m_peerEndpoints.value(ip, boost::asio::ip::tcp::endpoint());
if (ep != boost::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(const QStringList& peer_ips)
{
QTorrentHandle h = m_properties->getCurrentTorrent();
if (!h.is_valid())
return;
bool ok = false;
int cur_limit = -1;
boost::asio::ip::tcp::endpoint first_ep = m_peerEndpoints.value(peer_ips.first(),
boost::asio::ip::tcp::endpoint());
if (first_ep != boost::asio::ip::tcp::endpoint())
cur_limit = h.get_peer_download_limit(first_ep);
long limit = SpeedLimitDialog::askSpeedLimit(&ok, tr("Download rate limiting"), cur_limit, Preferences::instance()->getGlobalDownloadLimit()*1024.);
if (!ok)
return;
foreach (const QString &ip, peer_ips) {
boost::asio::ip::tcp::endpoint ep = m_peerEndpoints.value(ip, boost::asio::ip::tcp::endpoint());
if (ep != boost::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...");
}
}
}
#endif
void PeerListWidget::clear() {
qDebug("clearing peer list");
m_peerItems.clear();
m_peerEndpoints.clear();
m_peerAddresses.clear();
m_missingFlags.clear();
int nbrows = m_listModel->rowCount();
if (nbrows > 0) {
@@ -331,34 +241,28 @@ void PeerListWidget::saveSettings() const {
Preferences::instance()->setPeerListState(header()->saveState());
}
void PeerListWidget::loadPeers(const QTorrentHandle &h, bool force_hostname_resolution) {
if (!h.is_valid())
return;
boost::system::error_code ec;
libtorrent::torrent_status status = h.status(torrent_handle::query_pieces);
std::vector<peer_info> peers;
h.get_peer_info(peers);
void PeerListWidget::loadPeers(BitTorrent::TorrentHandle *const torrent, bool force_hostname_resolution) {
if (!torrent) return;
QList<BitTorrent::PeerInfo> peers = torrent->peers();
QSet<QString> old_peers_set = m_peerItems.keys().toSet();
std::vector<peer_info>::const_iterator itr = peers.begin();
std::vector<peer_info>::const_iterator itrend = peers.end();
for ( ; itr != itrend; ++itr) {
peer_info peer = *itr;
std::string ip_str = peer.ip.address().to_string(ec);
if (ec || ip_str.empty())
continue;
QString peer_ip = misc::toQString(ip_str);
foreach (const BitTorrent::PeerInfo &peer, peers) {
BitTorrent::PeerAddress addr = peer.address();
if (addr.ip.isNull()) continue;
QString peer_ip = addr.ip.toString();
if (m_peerItems.contains(peer_ip)) {
// Update existing peer
updatePeer(peer_ip, status, peer);
updatePeer(peer_ip, torrent, peer);
old_peers_set.remove(peer_ip);
if (force_hostname_resolution && m_resolver) {
m_resolver->resolve(peer_ip);
}
} else {
// Add new peer
m_peerItems[peer_ip] = addPeer(peer_ip, status, peer);
m_peerEndpoints[peer_ip] = peer.ip;
m_peerItems[peer_ip] = addPeer(peer_ip, torrent, peer);
m_peerAddresses[peer_ip] = addr;
// Resolve peer host name is asked
if (m_resolver)
m_resolver->resolve(peer_ip);
@@ -369,70 +273,70 @@ void PeerListWidget::loadPeers(const QTorrentHandle &h, bool force_hostname_reso
while(it.hasNext()) {
const QString& ip = it.next();
m_missingFlags.remove(ip);
m_peerEndpoints.remove(ip);
m_peerAddresses.remove(ip);
QStandardItem *item = m_peerItems.take(ip);
m_listModel->removeRow(item->row());
}
}
QStandardItem* PeerListWidget::addPeer(const QString& ip, const libtorrent::torrent_status &status, const peer_info& peer) {
QStandardItem* PeerListWidget::addPeer(const QString& ip, BitTorrent::TorrentHandle *const torrent, const BitTorrent::PeerInfo &peer) {
int row = m_listModel->rowCount();
// Adding Peer to peer list
m_listModel->insertRow(row);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::IP), ip);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::IP), ip, Qt::ToolTipRole);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::PORT), peer.ip.port());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::PORT), peer.address().port);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::IP_HIDDEN), ip);
if (m_displayFlags) {
const QIcon ico = GeoIPManager::CountryISOCodeToIcon(peer.country);
const QIcon ico = GeoIPManager::CountryISOCodeToIcon(peer.country());
if (!ico.isNull()) {
m_listModel->setData(m_listModel->index(row, PeerListDelegate::COUNTRY), ico, Qt::DecorationRole);
const QString country_name = GeoIPManager::CountryISOCodeToName(peer.country);
const QString country_name = GeoIPManager::CountryISOCodeToName(peer.country());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::COUNTRY), country_name, Qt::ToolTipRole);
} else {
m_missingFlags.insert(ip);
}
}
m_listModel->setData(m_listModel->index(row, PeerListDelegate::CONNECTION), getConnectionString(peer));
m_listModel->setData(m_listModel->index(row, PeerListDelegate::CONNECTION), peer.connectionType());
QString flags, tooltip;
getFlags(peer, flags, tooltip);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), flags);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), tooltip, Qt::ToolTipRole);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::CLIENT), misc::toQStringU(peer.client));
m_listModel->setData(m_listModel->index(row, PeerListDelegate::PROGRESS), peer.progress);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::DOWN_SPEED), peer.payload_down_speed);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::UP_SPEED), peer.payload_up_speed);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::TOT_DOWN), (qulonglong)peer.total_download);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::TOT_UP), (qulonglong)peer.total_upload);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::RELEVANCE), getPeerRelevance(status, peer));
m_listModel->setData(m_listModel->index(row, PeerListDelegate::CLIENT), peer.client());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::PROGRESS), peer.progress());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::DOWN_SPEED), peer.payloadDownSpeed());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::UP_SPEED), peer.payloadUpSpeed());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::TOT_DOWN), peer.totalDownload());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::TOT_UP), peer.totalUpload());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::RELEVANCE), getPeerRelevance(torrent->pieces(), peer.pieces()));
return m_listModel->item(row, PeerListDelegate::IP);
}
void PeerListWidget::updatePeer(const QString& ip, const libtorrent::torrent_status &status, const peer_info& peer) {
void PeerListWidget::updatePeer(const QString &ip, BitTorrent::TorrentHandle *const torrent, const BitTorrent::PeerInfo &peer) {
QStandardItem *item = m_peerItems.value(ip);
int row = item->row();
if (m_displayFlags) {
const QIcon ico = GeoIPManager::CountryISOCodeToIcon(peer.country);
const QIcon ico = GeoIPManager::CountryISOCodeToIcon(peer.country());
if (!ico.isNull()) {
m_listModel->setData(m_listModel->index(row, PeerListDelegate::COUNTRY), ico, Qt::DecorationRole);
const QString country_name = GeoIPManager::CountryISOCodeToName(peer.country);
const QString country_name = GeoIPManager::CountryISOCodeToName(peer.country());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::COUNTRY), country_name, Qt::ToolTipRole);
m_missingFlags.remove(ip);
}
}
m_listModel->setData(m_listModel->index(row, PeerListDelegate::CONNECTION), getConnectionString(peer));
m_listModel->setData(m_listModel->index(row, PeerListDelegate::CONNECTION), peer.connectionType());
QString flags, tooltip;
getFlags(peer, flags, tooltip);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::PORT), peer.ip.port());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::PORT), peer.address().port);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), flags);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), tooltip, Qt::ToolTipRole);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::CLIENT), misc::toQStringU(peer.client));
m_listModel->setData(m_listModel->index(row, PeerListDelegate::PROGRESS), peer.progress);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::DOWN_SPEED), peer.payload_down_speed);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::UP_SPEED), peer.payload_up_speed);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::TOT_DOWN), (qulonglong)peer.total_download);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::TOT_UP), (qulonglong)peer.total_upload);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::RELEVANCE), getPeerRelevance(status, peer));
m_listModel->setData(m_listModel->index(row, PeerListDelegate::CLIENT), peer.client());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::PROGRESS), peer.progress());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::DOWN_SPEED), peer.payloadDownSpeed());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::UP_SPEED), peer.payloadUpSpeed());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::TOT_DOWN), peer.totalDownload());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::TOT_UP), peer.totalUpload());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::RELEVANCE), getPeerRelevance(torrent->pieces(), peer.pieces()));
}
void PeerListWidget::handleResolved(const QString &ip, const QString &hostname) {
@@ -453,34 +357,11 @@ void PeerListWidget::handleSortColumnChanged(int col)
}
}
QString PeerListWidget::getConnectionString(const peer_info& peer)
{
#if LIBTORRENT_VERSION_NUM < 10000
if (peer.connection_type & peer_info::bittorrent_utp) {
#else
if (peer.flags & peer_info::utp_socket) {
#endif
return QString::fromUtf8("μTP");
}
QString connection;
switch(peer.connection_type) {
case peer_info::http_seed:
case peer_info::web_seed:
connection = "Web";
break;
default:
connection = "BT";
break;
}
return connection;
}
void PeerListWidget::getFlags(const peer_info& peer, QString& flags, QString& tooltip)
void PeerListWidget::getFlags(const BitTorrent::PeerInfo &peer, QString& flags, QString& tooltip)
{
if (peer.flags & peer_info::interesting) {
if (peer.isInteresting()) {
//d = Your client wants to download, but peer doesn't want to send (interested and choked)
if (peer.flags & peer_info::remote_choked) {
if (peer.isRemoteChocked()) {
flags += "d ";
tooltip += tr("interested(local) and choked(peer)");
tooltip += ", ";
@@ -493,9 +374,9 @@ void PeerListWidget::getFlags(const peer_info& peer, QString& flags, QString& to
}
}
if (peer.flags & peer_info::remote_interested) {
if (peer.isRemoteInterested()) {
//u = Peer wants your client to upload, but your client doesn't want to (interested and choked)
if (peer.flags & peer_info::choked) {
if (peer.isChocked()) {
flags += "u ";
tooltip += tr("interested(peer) and choked(local)");
tooltip += ", ";
@@ -509,81 +390,78 @@ void PeerListWidget::getFlags(const peer_info& peer, QString& flags, QString& to
}
//O = Optimistic unchoke
if (peer.flags & peer_info::optimistic_unchoke) {
if (peer.optimisticUnchoke()) {
flags += "O ";
tooltip += tr("optimistic unchoke");
tooltip += ", ";
}
//S = Peer is snubbed
if (peer.flags & peer_info::snubbed) {
if (peer.isSnubbed()) {
flags += "S ";
tooltip += tr("peer snubbed");
tooltip += ", ";
}
//I = Peer is an incoming connection
if ((peer.flags & peer_info::local_connection) == 0 ) {
if (!peer.isLocalConnection()) {
flags += "I ";
tooltip += tr("incoming connection");
tooltip += ", ";
}
//K = Peer is unchoking your client, but your client is not interested
if (((peer.flags & peer_info::remote_choked) == 0) && ((peer.flags & peer_info::interesting) == 0)) {
if (!peer.isRemoteChocked() && !peer.isInteresting()) {
flags += "K ";
tooltip += tr("not interested(local) and unchoked(peer)");
tooltip += ", ";
}
//? = Your client unchoked the peer but the peer is not interested
if (((peer.flags & peer_info::choked) == 0) && ((peer.flags & peer_info::remote_interested) == 0)) {
if (!peer.isChocked() && !peer.isRemoteInterested()) {
flags += "? ";
tooltip += tr("not interested(peer) and unchoked(local)");
tooltip += ", ";
}
//X = Peer was included in peerlists obtained through Peer Exchange (PEX)
if (peer.source & peer_info::pex) {
if (peer.fromPeX()) {
flags += "X ";
tooltip += tr("peer from PEX");
tooltip += ", ";
}
//H = Peer was obtained through DHT
if (peer.source & peer_info::dht) {
if (peer.fromDHT()) {
flags += "H ";
tooltip += tr("peer from DHT");
tooltip += ", ";
}
//E = Peer is using Protocol Encryption (all traffic)
if (peer.flags & peer_info::rc4_encrypted) {
if (peer.isRC4Encrypted()) {
flags += "E ";
tooltip += tr("encrypted traffic");
tooltip += ", ";
}
//e = Peer is using Protocol Encryption (handshake)
if (peer.flags & peer_info::plaintext_encrypted) {
if (peer.isPlaintextEncrypted()) {
flags += "e ";
tooltip += tr("encrypted handshake");
tooltip += ", ";
}
//P = Peer is using uTorrent uTP
#if LIBTORRENT_VERSION_NUM < 10000
if (peer.connection_type & peer_info::bittorrent_utp) {
#else
if (peer.flags & peer_info::utp_socket) {
#endif
if (peer.useUTPSocket()) {
flags += "P ";
tooltip += QString::fromUtf8("μTP");
tooltip += ", ";
}
//L = Peer is local
if (peer.source & peer_info::lsd) {
if (peer.fromLSD()) {
flags += "L";
tooltip += tr("peer from LSD");
}
@@ -594,17 +472,15 @@ void PeerListWidget::getFlags(const peer_info& peer, QString& flags, QString& to
tooltip.chop(1);
}
double PeerListWidget::getPeerRelevance(const torrent_status& status, const libtorrent::peer_info &peer)
qreal PeerListWidget::getPeerRelevance(const QBitArray &allPieces, const QBitArray &peerPieces)
{
int localMissing = 0;
int remoteHaves = 0;
libtorrent::bitfield local = status.pieces;
libtorrent::bitfield remote = peer.pieces;
for (int i=0; i<local.size(); ++i) {
if (!local[i]) {
for (int i = 0; i < allPieces.size(); ++i) {
if (!allPieces[i]) {
++localMissing;
if (remote[i])
if (peerPieces[i])
++remoteHaves;
}
}
@@ -612,5 +488,5 @@ double PeerListWidget::getPeerRelevance(const torrent_status& status, const libt
if (localMissing == 0)
return 0.0;
return (double)remoteHaves/localMissing;
return static_cast<qreal>(remoteHaves) / localMissing;
}

View File

@@ -35,7 +35,6 @@
#include <QHash>
#include <QPointer>
#include <QSet>
#include <libtorrent/version.hpp>
namespace Net
{
@@ -45,7 +44,6 @@ namespace Net
class PeerListDelegate;
class PeerListSortModel;
class PropertiesWidget;
class QTorrentHandle;
QT_BEGIN_NAMESPACE
class QSortFilterProxyModel;
@@ -53,18 +51,14 @@ class QStandardItem;
class QStandardItemModel;
QT_END_NAMESPACE
namespace libtorrent
namespace BitTorrent
{
struct peer_info;
struct torrent_status;
}
#include <boost/version.hpp>
#if BOOST_VERSION < 103500
#include <libtorrent/asio/ip/tcp.hpp>
#else
#include <boost/asio/ip/tcp.hpp>
#endif
class TorrentHandle;
class PeerInfo;
struct PeerAddress;
}
class PeerListWidget : public QTreeView {
Q_OBJECT
@@ -74,9 +68,9 @@ public:
~PeerListWidget();
public slots:
void loadPeers(const QTorrentHandle &h, bool force_hostname_resolution = false);
QStandardItem* addPeer(const QString& ip, const libtorrent::torrent_status &status, const libtorrent::peer_info& peer);
void updatePeer(const QString& ip, const libtorrent::torrent_status &status, const libtorrent::peer_info& peer);
void loadPeers(BitTorrent::TorrentHandle *const torrent, bool force_hostname_resolution = false);
QStandardItem *addPeer(const QString &ip, BitTorrent::TorrentHandle *const torrent, const BitTorrent::PeerInfo &peer);
void updatePeer(const QString &ip, BitTorrent::TorrentHandle *const torrent, const BitTorrent::PeerInfo &peer);
void handleResolved(const QString &ip, const QString &hostname);
void updatePeerHostNameResolutionState();
void updatePeerCountryResolutionState();
@@ -86,26 +80,19 @@ protected slots:
void loadSettings();
void saveSettings() const;
void showPeerListMenu(const QPoint&);
#if LIBTORRENT_VERSION_NUM < 10000
void limitUpRateSelectedPeers(const QStringList& peer_ips);
void limitDlRateSelectedPeers(const QStringList& peer_ips);
#endif
void banSelectedPeers(const QStringList& peer_ips);
void handleSortColumnChanged(int col);
private:
static QString getConnectionString(const libtorrent::peer_info &peer);
static void getFlags(const libtorrent::peer_info& peer, QString& flags, QString& tooltip);
double getPeerRelevance(const libtorrent::torrent_status &status, const libtorrent::peer_info &peer);
static void getFlags(const BitTorrent::PeerInfo &peer, QString &flags, QString &tooltip);
qreal getPeerRelevance(const QBitArray &allPieces, const QBitArray &peerPieces);
private:
QStandardItemModel *m_listModel;
PeerListDelegate *m_listDelegate;
PeerListSortModel *m_proxyModel;
QHash<QString, QStandardItem*> m_peerItems;
QHash<QString, boost::asio::ip::tcp::endpoint> m_peerEndpoints;
QHash<QString, BitTorrent::PeerAddress> m_peerAddresses;
QSet<QString> m_missingFlags;
QPointer<Net::ReverseResolution> m_resolver;
PropertiesWidget *m_properties;

View File

@@ -28,28 +28,25 @@
* Contact : chris@qbittorrent.org
*/
#include <cmath>
#include "pieceavailabilitybar.h"
//#include <QDebug>
PieceAvailabilityBar::PieceAvailabilityBar(QWidget *parent) :
QWidget(parent)
{
setFixedHeight(BAR_HEIGHT);
bg_color = 0xffffff;
border_color = palette().color(QPalette::Dark).rgb();
piece_color = 0x0000ff;
m_bgColor = 0xffffff;
m_borderColor = palette().color(QPalette::Dark).rgb();
m_pieceColor = 0x0000ff;
updatePieceColors();
}
std::vector<float> PieceAvailabilityBar::intToFloatVector(const std::vector<int> &vecin, int reqSize)
QVector<float> PieceAvailabilityBar::intToFloatVector(const QVector<int> &vecin, int reqSize)
{
std::vector<float> result(reqSize, 0.0);
if (vecin.empty())
return result;
QVector<float> result(reqSize, 0.0);
if (vecin.isEmpty()) return result;
const float ratio = vecin.size() / (float)reqSize;
@@ -162,27 +159,27 @@ void PieceAvailabilityBar::updateImage()
// qDebug() << "updateImageAv";
QImage image2(width() - 2, 1, QImage::Format_RGB888);
if (pieces.empty()) {
if (m_pieces.empty()) {
image2.fill(0xffffff);
image = image2;
m_image = image2;
update();
return;
}
std::vector<float> scaled_pieces = intToFloatVector(pieces, image2.width());
QVector<float> scaled_pieces = intToFloatVector(m_pieces, image2.width());
// filling image
for (unsigned int x = 0; x < scaled_pieces.size(); ++x)
for (int x = 0; x < scaled_pieces.size(); ++x)
{
float pieces2_val = scaled_pieces.at(x);
image2.setPixel(x, 0, piece_colors[pieces2_val * 255]);
image2.setPixel(x, 0, m_pieceColors[pieces2_val * 255]);
}
image = image2;
m_image = image2;
}
void PieceAvailabilityBar::setAvailability(const std::vector<int>& avail)
void PieceAvailabilityBar::setAvailability(const QVector<int> &avail)
{
pieces = std::vector<int>(avail);
m_pieces = avail;
updateImage();
update();
@@ -190,16 +187,16 @@ void PieceAvailabilityBar::setAvailability(const std::vector<int>& avail)
void PieceAvailabilityBar::updatePieceColors()
{
piece_colors = std::vector<int>(256);
m_pieceColors = QVector<int>(256);
for (int i = 0; i < 256; ++i) {
float ratio = (i / 255.0);
piece_colors[i] = mixTwoColors(bg_color, piece_color, ratio);
m_pieceColors[i] = mixTwoColors(m_bgColor, m_pieceColor, ratio);
}
}
void PieceAvailabilityBar::clear()
{
image = QImage();
m_image = QImage();
update();
}
@@ -207,29 +204,29 @@ void PieceAvailabilityBar::paintEvent(QPaintEvent *)
{
QPainter painter(this);
QRect imageRect(1, 1, width() - 2, height() - 2);
if (image.isNull())
if (m_image.isNull())
{
painter.setBrush(Qt::white);
painter.drawRect(imageRect);
}
else
{
if (image.width() != imageRect.width())
if (m_image.width() != imageRect.width())
updateImage();
painter.drawImage(imageRect, image);
painter.drawImage(imageRect, m_image);
}
QPainterPath border;
border.addRect(0, 0, width() - 1, height() - 1);
painter.setPen(border_color);
painter.setPen(m_borderColor);
painter.drawPath(border);
}
void PieceAvailabilityBar::setColors(int background, int border, int available)
{
bg_color = background;
border_color = border;
piece_color = available;
m_bgColor = background;
m_borderColor = border;
m_pieceColor = available;
updatePieceColors();
updateImage();

View File

@@ -34,8 +34,6 @@
#include <QWidget>
#include <QPainter>
#include <QImage>
#include <cmath>
#include <algorithm>
#define BAR_HEIGHT 18
@@ -44,25 +42,25 @@ class PieceAvailabilityBar: public QWidget {
Q_DISABLE_COPY(PieceAvailabilityBar)
private:
QImage image;
QImage m_image;
// I used values, bacause it should be possible to change colors in runtime
// background color
int bg_color;
int m_bgColor;
// border color
int border_color;
int m_borderColor;
// complete piece color
int piece_color;
int m_pieceColor;
// buffered 256 levels gradient from bg_color to piece_color
std::vector<int> piece_colors;
QVector<int> m_pieceColors;
// last used int vector, uses to better resize redraw
// TODO: make a diff pieces to new pieces and update only changed pixels, speedup when update > 20x faster
std::vector<int> pieces;
QVector<int> m_pieces;
// scale int vector to float vector
std::vector<float> intToFloatVector(const std::vector<int> &vecin, int reqSize);
QVector<float> intToFloatVector(const QVector<int> &vecin, int reqSize);
// mix two colors by light model, ratio <0, 1>
int mixTwoColors(int &rgb1, int &rgb2, float ratio);
@@ -72,7 +70,7 @@ private:
public:
PieceAvailabilityBar(QWidget *parent);
void setAvailability(const std::vector<int>& avail);
void setAvailability(const QVector<int> &avail);
void updatePieceColors();
void clear();

View File

@@ -40,11 +40,11 @@
#include <QMenu>
#include <QFileDialog>
#include <QDesktopServices>
#include <libtorrent/version.hpp>
#include <QBitArray>
#include "propertieswidget.h"
#include "transferlistwidget.h"
#include "core/torrentpersistentdata.h"
#include "qbtsession.h"
#include "core/bittorrent/session.h"
#include "proplistdelegate.h"
#include "torrentcontentfiltermodel.h"
#include "torrentcontentmodel.h"
@@ -55,20 +55,18 @@
#include "pieceavailabilitybar.h"
#include "core/preferences.h"
#include "proptabbar.h"
#include "iconprovider.h"
#include "guiiconprovider.h"
#include "lineedit.h"
#include "core/fs_utils.h"
#include "autoexpandabledialog.h"
using namespace libtorrent;
PropertiesWidget::PropertiesWidget(QWidget *parent, MainWindow* main_window, TransferListWidget *transferList):
QWidget(parent), transferList(transferList), main_window(main_window) {
QWidget(parent), transferList(transferList), main_window(main_window), m_torrent(0) {
setupUi(this);
// Icons
trackerUpButton->setIcon(IconProvider::instance()->getIcon("go-up"));
trackerDownButton->setIcon(IconProvider::instance()->getIcon("go-down"));
trackerUpButton->setIcon(GuiIconProvider::instance()->getIcon("go-up"));
trackerDownButton->setIcon(GuiIconProvider::instance()->getIcon("go-down"));
state = VISIBLE;
@@ -92,11 +90,11 @@ PropertiesWidget::PropertiesWidget(QWidget *parent, MainWindow* main_window, Tra
connect(filesList, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(openDoubleClickedFile(const QModelIndex &)));
connect(PropListModel, SIGNAL(filteredFilesChanged()), this, SLOT(filteredFilesChanged()));
connect(listWebSeeds, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayWebSeedListMenu(const QPoint&)));
connect(transferList, SIGNAL(currentTorrentChanged(QTorrentHandle)), this, SLOT(loadTorrentInfos(QTorrentHandle)));
connect(transferList, SIGNAL(currentTorrentChanged(BitTorrent::TorrentHandle *const)), this, SLOT(loadTorrentInfos(BitTorrent::TorrentHandle *const)));
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)));
connect(BitTorrent::Session::instance(), SIGNAL(torrentSavePathChanged(BitTorrent::TorrentHandle *const)), this, SLOT(updateSavePath(BitTorrent::TorrentHandle *const)));
connect(BitTorrent::Session::instance(), SIGNAL(torrentMetadataLoaded(BitTorrent::TorrentHandle *const)), this, SLOT(updateTorrentInfos(BitTorrent::TorrentHandle *const)));
connect(filesList->header(), SIGNAL(sectionMoved(int, int, int)), this, SLOT(saveSettings()));
connect(filesList->header(), SIGNAL(sectionResized(int, int, int)), this, SLOT(saveSettings()));
connect(filesList->header(), SIGNAL(sortIndicatorChanged(int, Qt::SortOrder)), this, SLOT(saveSettings()));
@@ -111,9 +109,6 @@ PropertiesWidget::PropertiesWidget(QWidget *parent, MainWindow* main_window, Tra
trackerList = new TrackerList(this);
connect(trackerUpButton, SIGNAL(clicked()), trackerList, SLOT(moveSelectionUp()));
connect(trackerDownButton, SIGNAL(clicked()), trackerList, SLOT(moveSelectionDown()));
connect(trackerList, SIGNAL(trackersAdded(const QStringList &, const QString &)), this, SIGNAL(trackersAdded(const QStringList &, const QString &)));
connect(trackerList, SIGNAL(trackersRemoved(const QStringList &, const QString &)), this, SIGNAL(trackersRemoved(const QStringList &, const QString &)));
connect(trackerList, SIGNAL(trackerlessChange(bool, const QString &)), this, SIGNAL(trackerlessChange(bool, const QString &)));
horizontalLayout_trackers->insertWidget(0, trackerList);
connect(trackerList->header(), SIGNAL(sectionMoved(int, int, int)), trackerList, SLOT(saveSettings()));
connect(trackerList->header(), SIGNAL(sectionResized(int, int, int)), trackerList, SLOT(saveSettings()));
@@ -230,61 +225,56 @@ void PropertiesWidget::clear() {
showPiecesDownloaded(false);
}
QTorrentHandle PropertiesWidget::getCurrentTorrent() const {
return h;
BitTorrent::TorrentHandle *PropertiesWidget::getCurrentTorrent() const
{
return m_torrent;
}
void PropertiesWidget::updateSavePath(const QTorrentHandle& _h) {
if (h.is_valid() && h == _h) {
save_path->setText(fsutils::toNativePath(h.save_path_parsed()));
void PropertiesWidget::updateSavePath(BitTorrent::TorrentHandle *const torrent)
{
if (m_torrent == torrent) {
save_path->setText(m_torrent->savePathParsed());
}
}
void PropertiesWidget::loadTrackers(const QTorrentHandle &handle)
void PropertiesWidget::loadTrackers(BitTorrent::TorrentHandle *const torrent)
{
if (handle == h)
if (torrent == m_torrent)
trackerList->loadTrackers();
}
void PropertiesWidget::updateTorrentInfos(const QTorrentHandle& _h) {
if (h.is_valid() && h == _h) {
loadTorrentInfos(h);
}
void PropertiesWidget::updateTorrentInfos(BitTorrent::TorrentHandle *const torrent)
{
if (m_torrent == torrent)
loadTorrentInfos(m_torrent);
}
void PropertiesWidget::loadTorrentInfos(const QTorrentHandle& _h)
void PropertiesWidget::loadTorrentInfos(BitTorrent::TorrentHandle *const torrent)
{
clear();
h = _h;
if (!h.is_valid())
return;
m_torrent = torrent;
if (!m_torrent) return;
try {
// Save path
updateSavePath(h);
updateSavePath(m_torrent);
// Hash
hash_lbl->setText(h.hash());
hash_lbl->setText(m_torrent->hash());
PropListModel->model()->clear();
if (h.has_metadata()) {
if (m_torrent->hasMetadata()) {
// Creation date
lbl_creationDate->setText(h.creation_date());
lbl_creationDate->setText(m_torrent->creationDate().toString());
// Piece size
pieceSize_lbl->setText(misc::friendlyUnit(h.piece_length()));
pieceSize_lbl->setText(misc::friendlyUnit(m_torrent->pieceLength()));
// Comment
comment_text->setHtml(misc::parseHtmlLinks(h.comment()));
comment_text->setHtml(misc::parseHtmlLinks(m_torrent->comment()));
// URL seeds
loadUrlSeeds();
// List files in torrent
#if LIBTORRENT_VERSION_NUM < 10000
PropListModel->model()->setupModelData(h.get_torrent_info());
#else
PropListModel->model()->setupModelData(*h.torrent_file());
#endif
PropListModel->model()->setupModelData(m_torrent->info());
filesList->setExpanded(PropListModel->index(0, 0), true);
// Load file priorities
PropListModel->model()->updateFilesPriorities(h.file_priorities());
PropListModel->model()->updateFilesPriorities(m_torrent->filePriorities());
}
} catch(const invalid_handle& e) { }
// Load dynamic data
loadDynamicData();
}
@@ -338,55 +328,44 @@ void PropertiesWidget::reloadPreferences() {
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 {
if (!m_torrent || (main_window->getCurrentTabWidget() != transferList) || (state != VISIBLE)) return;
// Transfer infos
if (stackedProperties->currentIndex() == PropTabBar::MAIN_TAB) {
libtorrent::torrent_status status = h.status(torrent_handle::query_accurate_download_counters
| torrent_handle::query_distributed_copies
| torrent_handle::query_pieces);
wasted->setText(misc::friendlyUnit(status.total_failed_bytes+status.total_redundant_bytes));
upTotal->setText(misc::friendlyUnit(status.all_time_upload) + " ("+misc::friendlyUnit(status.total_payload_upload)+" "+tr("this session")+")");
dlTotal->setText(misc::friendlyUnit(status.all_time_download) + " ("+misc::friendlyUnit(status.total_payload_download)+" "+tr("this session")+")");
lbl_uplimit->setText(h.upload_limit() <= 0 ? QString::fromUtf8("") : misc::friendlyUnit(h.upload_limit())+tr("/s", "/second (i.e. per second)"));
lbl_dllimit->setText(h.download_limit() <= 0 ? QString::fromUtf8("") : misc::friendlyUnit(h.download_limit())+tr("/s", "/second (i.e. per second)"));
QString elapsed_txt = misc::userFriendlyDuration(status.active_time);
if (h.is_seed(status)) {
elapsed_txt += " ("+tr("Seeded for %1", "e.g. Seeded for 3m10s").arg(misc::userFriendlyDuration(status.seeding_time))+")";
wasted->setText(misc::friendlyUnit(m_torrent->wastedSize()));
upTotal->setText(misc::friendlyUnit(m_torrent->totalUpload()) + " ("+misc::friendlyUnit(m_torrent->totalPayloadUpload())+" "+tr("this session")+")");
dlTotal->setText(misc::friendlyUnit(m_torrent->totalDownload()) + " ("+misc::friendlyUnit(m_torrent->totalPayloadDownload())+" "+tr("this session")+")");
lbl_uplimit->setText(m_torrent->uploadLimit() <= 0 ? QString::fromUtf8("") : misc::friendlyUnit(m_torrent->uploadLimit())+tr("/s", "/second (i.e. per second)"));
lbl_dllimit->setText(m_torrent->downloadLimit() <= 0 ? QString::fromUtf8("") : misc::friendlyUnit(m_torrent->downloadLimit())+tr("/s", "/second (i.e. per second)"));
QString elapsed_txt = misc::userFriendlyDuration(m_torrent->activeTime());
if (m_torrent->isSeed()) {
elapsed_txt += " ("+tr("Seeded for %1", "e.g. Seeded for 3m10s").arg(misc::userFriendlyDuration(m_torrent->seedingTime()))+")";
}
lbl_elapsed->setText(elapsed_txt);
if (status.connections_limit > 0)
lbl_connections->setText(QString::number(status.num_connections)+" ("+tr("%1 max", "e.g. 10 max").arg(QString::number(status.connections_limit))+")");
if (m_torrent->connectionsLimit() > 0)
lbl_connections->setText(QString::number(m_torrent->connectionsCount())+" ("+tr("%1 max", "e.g. 10 max").arg(QString::number(m_torrent->connectionsLimit()))+")");
else
lbl_connections->setText(QString::number(status.num_connections));
lbl_connections->setText(QString::number(m_torrent->connectionsLimit()));
// Update next announce time
reannounce_lbl->setText(misc::userFriendlyDuration(status.next_announce.total_seconds()));
reannounce_lbl->setText(misc::userFriendlyDuration(m_torrent->nextAnnounce()));
// Update ratio info
const qreal ratio = QBtSession::instance()->getRealRatio(status);
shareRatio->setText(ratio > QBtSession::MAX_RATIO ? QString::fromUtf8("") : misc::accurateDoubleToString(ratio, 2));
if (!h.is_seed(status) && status.has_metadata) {
const qreal ratio = m_torrent->realRatio();
shareRatio->setText(ratio > BitTorrent::TorrentHandle::MAX_RATIO ? QString::fromUtf8("") : misc::accurateDoubleToString(ratio, 2));
if (!m_torrent->isSeed() && m_torrent->hasMetadata()) {
showPiecesDownloaded(true);
// Downloaded pieces
#if LIBTORRENT_VERSION_NUM < 10000
bitfield bf(h.get_torrent_info().num_pieces(), 0);
#else
bitfield bf(h.torrent_file()->num_pieces(), 0);
#endif
h.downloading_pieces(bf);
downloaded_pieces->setProgress(status.pieces, bf);
downloaded_pieces->setProgress(m_torrent->pieces(), m_torrent->downloadingPieces());
// Pieces availability
if (!h.is_paused(status) && !h.is_queued(status) && !h.is_checking(status)) {
if (!m_torrent->isPaused() && !m_torrent->isQueued() && !m_torrent->isChecking()) {
showPiecesAvailability(true);
std::vector<int> avail;
h.piece_availability(avail);
pieces_availability->setAvailability(avail);
avail_average_lbl->setText(misc::accurateDoubleToString(status.distributed_copies, 3));
pieces_availability->setAvailability(m_torrent->pieceAvailability());
avail_average_lbl->setText(misc::accurateDoubleToString(m_torrent->distributedCopies(), 3));
} else {
showPiecesAvailability(false);
}
// Progress
qreal progress = h.progress(status)*100.;
qreal progress = m_torrent->progress() * 100.;
progress_lbl->setText(misc::accurateDoubleToString(progress, 1)+"%");
} else {
showPiecesAvailability(false);
@@ -401,20 +380,15 @@ void PropertiesWidget::loadDynamicData() {
}
if (stackedProperties->currentIndex() == PropTabBar::PEERS_TAB) {
// Load peers
peersList->loadPeers(h);
peersList->loadPeers(m_torrent);
return;
}
if (stackedProperties->currentIndex() == PropTabBar::FILES_TAB) {
libtorrent::torrent_status status = h.status(torrent_handle::query_accurate_download_counters
| torrent_handle::query_distributed_copies
| torrent_handle::query_pieces);
// Files progress
if (h.is_valid() && status.has_metadata) {
if (m_torrent->hasMetadata()) {
qDebug("Updating priorities in files tab");
filesList->setUpdatesEnabled(false);
std::vector<size_type> fp;
h.file_progress(fp);
PropListModel->model()->updateFilesProgress(fp);
PropListModel->model()->updateFilesProgress(m_torrent->filesProgress());
// XXX: We don't update file priorities regularly for performance
// reasons. This means that priorities will not be updated if
// set from the Web UI.
@@ -422,25 +396,22 @@ void PropertiesWidget::loadDynamicData() {
filesList->setUpdatesEnabled(true);
}
}
} catch(const invalid_handle& e) {
qWarning() << "Caught exception in PropertiesWidget::loadDynamicData(): " << misc::toQStringU(e.what());
}
}
void PropertiesWidget::loadUrlSeeds() {
listWebSeeds->clear();
qDebug("Loading URL seeds");
const QStringList hc_seeds = h.url_seeds();
const QList<QUrl> hc_seeds = m_torrent->urlSeeds();
// Add url seeds
foreach (const QString &hc_seed, hc_seeds) {
qDebug("Loading URL seed: %s", qPrintable(hc_seed));
new QListWidgetItem(hc_seed, listWebSeeds);
foreach (const QUrl &hc_seed, hc_seeds) {
qDebug("Loading URL seed: %s", qPrintable(hc_seed.toString()));
new QListWidgetItem(hc_seed.toString(), listWebSeeds);
}
}
void PropertiesWidget::openDoubleClickedFile(const QModelIndex &index) {
if (!index.isValid()) return;
if (!h.is_valid() || !h.has_metadata()) return;
if (!m_torrent || !m_torrent->hasMetadata()) return;
if (PropListModel->itemType(index) == TorrentContentModelItem::FileType)
openFile(index);
else
@@ -449,12 +420,12 @@ void PropertiesWidget::openDoubleClickedFile(const QModelIndex &index) {
void PropertiesWidget::openFile(const QModelIndex &index) {
int i = PropListModel->getFileIndex(index);
const QDir saveDir(h.save_path());
const QString filename = h.filepath_at(i);
const QDir saveDir(m_torrent->actualSavePath());
const QString filename = m_torrent->filePath(i);
const QString file_path = fsutils::expandPath(saveDir.absoluteFilePath(filename));
qDebug("Trying to open file at %s", qPrintable(file_path));
// Flush data
h.flush_cache();
m_torrent->flushCache();
if (QFile::exists(file_path)) {
if (file_path.startsWith("//"))
QDesktopServices::openUrl(fsutils::toNativePath("file:" + file_path));
@@ -484,24 +455,24 @@ void PropertiesWidget::openFolder(const QModelIndex &index, bool containing_fold
if (containing_folder)
path_items.removeLast();
#endif
const QDir saveDir(h.save_path());
const QDir saveDir(m_torrent->actualSavePath());
const QString relative_path = path_items.join("/");
absolute_path = fsutils::expandPath(saveDir.absoluteFilePath(relative_path));
}
else {
int i = PropListModel->getFileIndex(index);
const QDir saveDir(h.save_path());
const QString relative_path = h.filepath_at(i);
absolute_path = fsutils::expandPath(saveDir.absoluteFilePath(relative_path));
int i = PropListModel->getFileIndex(index);
const QDir saveDir(m_torrent->actualSavePath());
const QString relative_path = m_torrent->filePath(i);
absolute_path = fsutils::expandPath(saveDir.absoluteFilePath(relative_path));
#if !(defined(Q_OS_WIN) || (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)))
if (containing_folder)
absolute_path = fsutils::folderName(absolute_path);
if (containing_folder)
absolute_path = fsutils::folderName(absolute_path);
#endif
}
// Flush data
h.flush_cache();
m_torrent->flushCache();
if (!QFile::exists(absolute_path))
return;
qDebug("Trying to open folder at %s", qPrintable(absolute_path));
@@ -544,8 +515,8 @@ void PropertiesWidget::openFolder(const QModelIndex &index, bool containing_fold
}
void PropertiesWidget::displayFilesListMenu(const QPoint&) {
if (!h.is_valid())
return;
if (!m_torrent) return;
QModelIndexList selectedRows = filesList->selectionModel()->selectedRows(0);
if (selectedRows.empty())
return;
@@ -554,13 +525,13 @@ void PropertiesWidget::displayFilesListMenu(const QPoint&) {
QAction *actOpenContainingFolder = 0;
QAction *actRename = 0;
if (selectedRows.size() == 1) {
actOpen = myFilesLlistMenu.addAction(IconProvider::instance()->getIcon("folder-documents"), tr("Open"));
actOpenContainingFolder = myFilesLlistMenu.addAction(IconProvider::instance()->getIcon("inode-directory"), tr("Open Containing Folder"));
actRename = myFilesLlistMenu.addAction(IconProvider::instance()->getIcon("edit-rename"), tr("Rename..."));
actOpen = myFilesLlistMenu.addAction(GuiIconProvider::instance()->getIcon("folder-documents"), tr("Open"));
actOpenContainingFolder = myFilesLlistMenu.addAction(GuiIconProvider::instance()->getIcon("inode-directory"), tr("Open Containing Folder"));
actRename = myFilesLlistMenu.addAction(GuiIconProvider::instance()->getIcon("edit-rename"), tr("Rename..."));
myFilesLlistMenu.addSeparator();
}
QMenu subMenu;
if (!h.status(0x0).is_seeding) {
if (!m_torrent->isSeed()) {
subMenu.setTitle(tr("Priority"));
subMenu.addAction(actionNot_downloaded);
subMenu.addAction(actionNormal);
@@ -603,20 +574,20 @@ void PropertiesWidget::displayFilesListMenu(const QPoint&) {
}
void PropertiesWidget::displayWebSeedListMenu(const QPoint&) {
if (!h.is_valid())
return;
if (!m_torrent) return;
QMenu seedMenu;
QModelIndexList rows = listWebSeeds->selectionModel()->selectedRows();
QAction *actAdd = seedMenu.addAction(IconProvider::instance()->getIcon("list-add"), tr("New Web seed"));
QAction *actAdd = seedMenu.addAction(GuiIconProvider::instance()->getIcon("list-add"), tr("New Web seed"));
QAction *actDel = 0;
QAction *actCpy = 0;
QAction *actEdit = 0;
if (rows.size()) {
actDel = seedMenu.addAction(IconProvider::instance()->getIcon("list-remove"), tr("Remove Web seed"));
actDel = seedMenu.addAction(GuiIconProvider::instance()->getIcon("list-remove"), tr("Remove Web seed"));
seedMenu.addSeparator();
actCpy = seedMenu.addAction(IconProvider::instance()->getIcon("edit-copy"), tr("Copy Web seed URL"));
actEdit = seedMenu.addAction(IconProvider::instance()->getIcon("edit-rename"), tr("Edit Web seed URL"));
actCpy = seedMenu.addAction(GuiIconProvider::instance()->getIcon("edit-copy"), tr("Copy Web seed URL"));
actEdit = seedMenu.addAction(GuiIconProvider::instance()->getIcon("edit-rename"), tr("Edit Web seed URL"));
}
const QAction *act = seedMenu.exec(QCursor::pos());
@@ -654,8 +625,8 @@ void PropertiesWidget::renameSelectedFile() {
if (PropListModel->itemType(index) == TorrentContentModelItem::FileType) {
// 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);
if (!m_torrent || !m_torrent->hasMetadata()) return;
QString old_name = m_torrent->filePath(file_index);
if (old_name.endsWith(".!qB") && !new_name_last.endsWith(".!qB")) {
new_name_last += ".!qB";
}
@@ -669,12 +640,12 @@ void PropertiesWidget::renameSelectedFile() {
}
new_name = fsutils::expandPath(new_name);
// Check if that name is already used
for (int i=0; i<h.num_files(); ++i) {
for (int i = 0; i < m_torrent->filesCount(); ++i) {
if (i == file_index) continue;
#if defined(Q_OS_UNIX) || defined(Q_WS_QWS)
if (h.filepath_at(i).compare(new_name, Qt::CaseSensitive) == 0) {
if (m_torrent->filePath(i).compare(new_name, Qt::CaseSensitive) == 0) {
#else
if (h.filepath_at(i).compare(new_name, Qt::CaseInsensitive) == 0) {
if (m_torrent->filePath(i).compare(new_name, Qt::CaseInsensitive) == 0) {
#endif
// Display error message
QMessageBox::warning(this, tr("The file could not be renamed"),
@@ -683,11 +654,11 @@ void PropertiesWidget::renameSelectedFile() {
return;
}
}
const bool force_recheck = QFile::exists(h.save_path()+"/"+new_name);
const bool force_recheck = QFile::exists(m_torrent->actualSavePath() + "/" + new_name);
qDebug("Renaming %s to %s", qPrintable(old_name), qPrintable(new_name));
h.rename_file(file_index, new_name);
m_torrent->renameFile(file_index, new_name);
// Force recheck
if (force_recheck) h.force_recheck();
if (force_recheck) m_torrent->forceRecheck();
// Rename if torrent files model too
if (new_name_last.endsWith(".!qB"))
new_name_last.chop(4);
@@ -707,9 +678,9 @@ void PropertiesWidget::renameSelectedFile() {
QString new_path = path_items.join("/");
if (!new_path.endsWith("/")) new_path += "/";
// Check for overwriting
const int num_files = h.num_files();
const int num_files = m_torrent->filesCount();
for (int i=0; i<num_files; ++i) {
const QString current_name = h.filepath_at(i);
const QString current_name = m_torrent->filePath(i);
#if defined(Q_OS_UNIX) || defined(Q_WS_QWS)
if (current_name.startsWith(new_path, Qt::CaseSensitive)) {
#else
@@ -724,23 +695,23 @@ void PropertiesWidget::renameSelectedFile() {
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);
const QString current_name = m_torrent->filePath(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))
if (!force_recheck && QDir(m_torrent->actualSavePath()).exists(new_name))
force_recheck = true;
new_name = fsutils::expandPath(new_name);
qDebug("Rename %s to %s", qPrintable(current_name), qPrintable(new_name));
h.rename_file(i, new_name);
m_torrent->renameFile(i, new_name);
}
}
// Force recheck
if (force_recheck) h.force_recheck();
if (force_recheck) m_torrent->forceRecheck();
// 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);
const QDir old_folder(m_torrent->actualSavePath() + "/" + 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)
@@ -765,28 +736,23 @@ void PropertiesWidget::askWebSeed() {
QMessageBox::Ok);
return;
}
if (h.is_valid())
h.add_url_seed(url_seed);
if (m_torrent)
m_torrent->addUrlSeeds(QList<QUrl>() << url_seed);
// Refresh the seeds list
loadUrlSeeds();
}
void PropertiesWidget::deleteSelectedUrlSeeds() {
const QList<QListWidgetItem *> selectedItems = listWebSeeds->selectedItems();
if (selectedItems.isEmpty())
return;
bool change = false;
foreach (const QListWidgetItem *item, selectedItems) {
QString url_seed = item->text();
try {
h.remove_url_seed(url_seed);
change = true;
} catch (invalid_handle&) {}
}
if (change) {
// Refresh list
loadUrlSeeds();
}
if (selectedItems.isEmpty()) return;
QList<QUrl> urlSeeds;
foreach (const QListWidgetItem *item, selectedItems)
urlSeeds << item->text();
m_torrent->removeUrlSeeds(urlSeeds);
// Refresh list
loadUrlSeeds();
}
void PropertiesWidget::copySelectedWebSeedsToClipboard() const {
@@ -822,31 +788,28 @@ void PropertiesWidget::editWebSeed() {
return;
}
try {
h.remove_url_seed(old_seed);
h.add_url_seed(new_seed);
loadUrlSeeds();
} catch (invalid_handle&) {}
m_torrent->removeUrlSeeds(QList<QUrl>() << old_seed);
m_torrent->addUrlSeeds(QList<QUrl>() << new_seed);
loadUrlSeeds();
}
bool PropertiesWidget::applyPriorities() {
qDebug("Saving files priorities");
const std::vector<int> priorities = PropListModel->model()->getFilesPriorities();
const QVector<int> priorities = PropListModel->model()->getFilePriorities();
// Save first/last piece first option state
bool first_last_piece_first = h.first_last_piece_first();
bool first_last_piece_first = m_torrent->hasFirstLastPiecePriority();
// Prioritize the files
qDebug("prioritize files: %d", priorities[0]);
h.prioritize_files(priorities);
m_torrent->prioritizeFiles(priorities);
// Restore first/last piece first option if necessary
if (first_last_piece_first)
h.prioritize_first_last_piece(true);
m_torrent->setFirstLastPiecePriority(true);
return true;
}
void PropertiesWidget::filteredFilesChanged() {
if (h.is_valid()) {
if (m_torrent)
applyPriorities();
}
}
void PropertiesWidget::filterText(const QString& filter) {

View File

@@ -34,7 +34,7 @@
#include <QShortcut>
#include <QWidget>
#include "ui_propertieswidget.h"
#include "qtorrenthandle.h"
#include "core/bittorrent/torrenthandle.h"
class TransferListWidget;
@@ -64,23 +64,18 @@ public:
public:
PropertiesWidget(QWidget *parent, MainWindow* main_window, TransferListWidget *transferList);
~PropertiesWidget();
QTorrentHandle getCurrentTorrent() const;
BitTorrent::TorrentHandle *getCurrentTorrent() const;
TrackerList* getTrackerList() const { return trackerList; }
PeerListWidget* getPeerList() const { return peersList; }
QTreeView* getFilesList() const { return filesList; }
signals:
void trackersAdded(const QStringList &trackers, const QString &hash);
void trackersRemoved(const QStringList &trackers, const QString &hash);
void trackerlessChange(bool trackerless, const QString &hash);
protected:
QPushButton* getButtonFromIndex(int index);
bool applyPriorities();
protected slots:
void loadTorrentInfos(const QTorrentHandle &h);
void updateTorrentInfos(const QTorrentHandle &h);
void loadTorrentInfos(BitTorrent::TorrentHandle *const torrent);
void updateTorrentInfos(BitTorrent::TorrentHandle *const torrent);
void loadUrlSeeds();
void askWebSeed();
void deleteSelectedUrlSeeds();
@@ -101,8 +96,8 @@ public slots:
void saveSettings();
void reloadPreferences();
void openDoubleClickedFile(const QModelIndex &);
void updateSavePath(const QTorrentHandle& h);
void loadTrackers(const QTorrentHandle &handle);
void updateSavePath(BitTorrent::TorrentHandle *const torrent);
void loadTrackers(BitTorrent::TorrentHandle *const torrent);
private:
void openFile(const QModelIndex &index);
@@ -111,7 +106,7 @@ private:
private:
TransferListWidget *transferList;
MainWindow *main_window;
QTorrentHandle h;
BitTorrent::TorrentHandle *m_torrent;
QTimer *refreshTimer;
SlideState state;
TorrentContentFilterModel *PropListModel;

View File

@@ -154,8 +154,8 @@ public:
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */, const QModelIndex &index) const {
if (index.column() != PRIORITY) return 0;
if (properties) {
QTorrentHandle h = properties->getCurrentTorrent();
if (!h.is_valid() || !h.has_metadata() || h.status(0x0).is_seeding)
BitTorrent::TorrentHandle *const torrent = properties->getCurrentTorrent();
if (!torrent || !torrent->hasMetadata() || torrent->isSeed())
return 0;
}
if (index.data().toInt() <= 0) {

View File

@@ -34,7 +34,7 @@
#include <QKeySequence>
#include "proptabbar.h"
#include "iconprovider.h"
#include "guiiconprovider.h"
PropTabBar::PropTabBar(QWidget *parent) :
QHBoxLayout(parent), m_currentIndex(-1)
@@ -42,24 +42,24 @@ PropTabBar::PropTabBar(QWidget *parent) :
setSpacing(2);
m_btnGroup = new QButtonGroup(this);
// General tab
QPushButton *main_infos_button = new QPushButton(IconProvider::instance()->getIcon("document-properties"), tr("General"), parent);
QPushButton *main_infos_button = new QPushButton(GuiIconProvider::instance()->getIcon("document-properties"), tr("General"), parent);
main_infos_button->setShortcut(QKeySequence(QString::fromUtf8("Alt+P")));
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);
QPushButton *trackers_button = new QPushButton(GuiIconProvider::instance()->getIcon("network-server"), tr("Trackers"), parent);
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);
QPushButton *peers_button = new QPushButton(GuiIconProvider::instance()->getIcon("edit-find-user"), tr("Peers"), parent);
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);
QPushButton *urlseeds_button = new QPushButton(GuiIconProvider::instance()->getIcon("network-server"), tr("HTTP Sources"), parent);
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);
QPushButton *files_button = new QPushButton(GuiIconProvider::instance()->getIcon("inode-directory"), tr("Content"), parent);
addWidget(files_button);
m_btnGroup->addButton(files_button, FILES_TAB);
// Spacer

View File

@@ -36,19 +36,18 @@
#include <QColor>
#include <QDebug>
#include <QUrl>
#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 "guiiconprovider.h"
#include "core/bittorrent/session.h"
#include "core/bittorrent/torrenthandle.h"
#include "core/bittorrent/peerinfo.h"
#include "core/bittorrent/trackerentry.h"
#include "core/preferences.h"
#include "core/misc.h"
#include "autoexpandabledialog.h"
using namespace libtorrent;
TrackerList::TrackerList(PropertiesWidget *properties): QTreeWidget(), properties(properties) {
// Graphical settings
setRootIsDecorated(false);
@@ -108,8 +107,8 @@ void TrackerList::setRowColor(int row, QColor color) {
}
void TrackerList::moveSelectionUp() {
QTorrentHandle h = properties->getCurrentTorrent();
if (!h.is_valid()) {
BitTorrent::TorrentHandle *const torrent = properties->getCurrentTorrent();
if (!torrent) {
clear();
return;
}
@@ -131,23 +130,23 @@ void TrackerList::moveSelectionUp() {
}
setSelectionModel(selection);
// Update torrent trackers
std::vector<announce_entry> trackers;
for (int i=NB_STICKY_ITEM; i<topLevelItemCount(); ++i) {
QList<BitTorrent::TrackerEntry> 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);
BitTorrent::TrackerEntry e(tracker_url);
e.setTier(i - NB_STICKY_ITEM);
trackers.append(e);
}
h.replace_trackers(trackers);
torrent->replaceTrackers(trackers);
// Reannounce
if (!h.is_paused())
h.force_reannounce();
loadTrackers();
if (!torrent->isPaused())
torrent->forceReannounce();
}
void TrackerList::moveSelectionDown() {
QTorrentHandle h = properties->getCurrentTorrent();
if (!h.is_valid()) {
BitTorrent::TorrentHandle *const torrent = properties->getCurrentTorrent();
if (!torrent) {
clear();
return;
}
@@ -169,18 +168,18 @@ void TrackerList::moveSelectionDown() {
}
setSelectionModel(selection);
// Update torrent trackers
std::vector<announce_entry> trackers;
for (int i=NB_STICKY_ITEM; i<topLevelItemCount(); ++i) {
QList<BitTorrent::TrackerEntry> 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);
BitTorrent::TrackerEntry e(tracker_url);
e.setTier(i - NB_STICKY_ITEM);
trackers.append(e);
}
h.replace_trackers(trackers);
torrent->replaceTrackers(trackers);
// Reannounce
if (!h.is_paused())
h.force_reannounce();
loadTrackers();
if (!torrent->isPaused())
torrent->forceReannounce();
}
void TrackerList::clear() {
@@ -197,29 +196,29 @@ void TrackerList::clear() {
lsd_item->setText(COL_MSG, "");
}
void TrackerList::loadStickyItems(const QTorrentHandle &h) {
void TrackerList::loadStickyItems(BitTorrent::TorrentHandle *const torrent) {
QString working = tr("Working");
QString disabled = tr("Disabled");
// load DHT information
if (QBtSession::instance()->isDHTEnabled() && !h.priv())
if (BitTorrent::Session::instance()->isDHTEnabled() && !torrent->isPrivate())
dht_item->setText(COL_STATUS, working);
else
dht_item->setText(COL_STATUS, disabled);
// Load PeX Information
if (QBtSession::instance()->isPexEnabled() && !h.priv())
if (BitTorrent::Session::instance()->isPexEnabled() && !torrent->isPrivate())
pex_item->setText(COL_STATUS, working);
else
pex_item->setText(COL_STATUS, disabled);
// Load LSD Information
if (QBtSession::instance()->isLSDEnabled() && !h.priv())
if (BitTorrent::Session::instance()->isLSDEnabled() && !torrent->isPrivate())
lsd_item->setText(COL_STATUS, working);
else
lsd_item->setText(COL_STATUS, disabled);
if (h.priv()) {
if (torrent->isPrivate()) {
QString privateMsg = tr("This torrent is private");
dht_item->setText(COL_MSG, privateMsg);
pex_item->setText(COL_MSG, privateMsg);
@@ -229,16 +228,12 @@ 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 = peers.begin();
std::vector<peer_info>::iterator end = peers.end();
for ( ; it != end; ++it) {
if (it->source & peer_info::dht)
foreach (const BitTorrent::PeerInfo &peer, torrent->peers()) {
if (peer.fromDHT())
++nb_dht;
if (it->source & peer_info::lsd)
if (peer.fromLSD())
++nb_lsd;
if (it->source & peer_info::pex)
if (peer.fromPeX())
++nb_pex;
}
dht_item->setText(COL_PEERS, QString::number(nb_dht));
@@ -248,47 +243,47 @@ void TrackerList::loadStickyItems(const QTorrentHandle &h) {
void TrackerList::loadTrackers() {
// Load trackers from torrent handle
QTorrentHandle h = properties->getCurrentTorrent();
if (!h.is_valid()) return;
loadStickyItems(h);
BitTorrent::TorrentHandle *const torrent = properties->getCurrentTorrent();
if (!torrent) return;
loadStickyItems(torrent);
// Load actual trackers information
QHash<QString, TrackerInfos> trackers_data = QBtSession::instance()->getTrackersInfo(h.hash());
QHash<QString, BitTorrent::TrackerInfo> trackers_data = torrent->trackerInfos();
QStringList old_trackers_urls = tracker_items.keys();
const std::vector<announce_entry> trackers = h.trackers();
std::vector<announce_entry>::const_iterator it = trackers.begin();
std::vector<announce_entry>::const_iterator end = trackers.end();
for ( ; it != end; ++it) {
QString tracker_url = misc::toQString(it->url);
QTreeWidgetItem *item = tracker_items.value(tracker_url, 0);
foreach (const BitTorrent::TrackerEntry &entry, torrent->trackers()) {
QString trackerUrl = entry.url();
QTreeWidgetItem *item = tracker_items.value(trackerUrl, 0);
if (!item) {
item = new QTreeWidgetItem();
item->setText(COL_URL, tracker_url);
item->setText(COL_URL, trackerUrl);
addTopLevelItem(item);
tracker_items[tracker_url] = item;
tracker_items[trackerUrl] = item;
} else {
old_trackers_urls.removeOne(tracker_url);
old_trackers_urls.removeOne(trackerUrl);
}
item->setText(COL_TIER, QString::number(it->tier));
TrackerInfos data = trackers_data.value(tracker_url, TrackerInfos(tracker_url));
QString error_message = data.last_message.trimmed();
if (it->verified) {
item->setText(COL_STATUS, tr("Working"));
item->setText(COL_MSG, "");
} else {
if (it->updating && it->fails == 0) {
item->setText(COL_TIER, QString::number(entry.tier()));
BitTorrent::TrackerInfo data = trackers_data.value(trackerUrl);
QString error_message = data.lastMessage.trimmed();
switch (entry.status()) {
case BitTorrent::TrackerEntry::Working:
item->setText(COL_STATUS, tr("Working"));
item->setText(COL_MSG, "");
break;
case BitTorrent::TrackerEntry::Updating:
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, "");
}
}
break;
case BitTorrent::TrackerEntry::NotWorking:
item->setText(COL_STATUS, tr("Not working"));
item->setText(COL_MSG, error_message);
break;
case BitTorrent::TrackerEntry::NotContacted:
item->setText(COL_STATUS, tr("Not contacted yet"));
item->setText(COL_MSG, "");
break;
}
item->setText(COL_PEERS, QString::number(trackers_data.value(tracker_url, TrackerInfos(tracker_url)).num_peers));
item->setText(COL_PEERS, QString::number(trackers_data.value(trackerUrl).numPeers));
}
// Remove old trackers
foreach (const QString &tracker, old_trackers_urls) {
@@ -298,12 +293,13 @@ void TrackerList::loadTrackers() {
// Ask the user for new trackers and add them to the torrent
void TrackerList::askForTrackers() {
QTorrentHandle h = properties->getCurrentTorrent();
if (!h.is_valid()) return;
QString hash = h.hash();
QStringList trackers = TrackersAdditionDlg::askForTrackers(h);
QBtSession::instance()->addTrackersAndUrlSeeds(hash, trackers, QStringList());
loadTrackers();
BitTorrent::TorrentHandle *const torrent = properties->getCurrentTorrent();
if (!torrent) return;
QList<BitTorrent::TrackerEntry> trackers;
foreach (const QString &tracker, TrackersAdditionDlg::askForTrackers(torrent))
trackers << tracker;
torrent->addTrackers(trackers);
}
void TrackerList::copyTrackerUrl() {
@@ -320,14 +316,15 @@ void TrackerList::copyTrackerUrl() {
void TrackerList::deleteSelectedTrackers() {
QTorrentHandle h = properties->getCurrentTorrent();
if (!h.is_valid()) {
BitTorrent::TorrentHandle *const torrent = properties->getCurrentTorrent();
if (!torrent) {
clear();
return;
}
QString hash = h.hash();
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();
@@ -335,32 +332,26 @@ void TrackerList::deleteSelectedTrackers() {
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 = trackers.begin();
std::vector<announce_entry>::iterator itend = trackers.end();
for ( ; it != itend; ++it) {
if (!urls_to_remove.contains(misc::toQString((*it).url))) {
remaining_trackers.push_back(*it);
// Iterate of trackers and remove selected ones
QList<BitTorrent::TrackerEntry> remaining_trackers;
QList<BitTorrent::TrackerEntry> trackers = torrent->trackers();
foreach (const BitTorrent::TrackerEntry &entry, trackers) {
if (!urls_to_remove.contains(entry.url())) {
remaining_trackers.push_back(entry);
}
}
h.replace_trackers(remaining_trackers);
if (!urls_to_remove.empty())
emit trackersRemoved(urls_to_remove, hash);
if (remaining_trackers.empty())
emit trackerlessChange(true, hash);
if (!h.is_paused())
h.force_reannounce();
// Reload Trackers
loadTrackers();
torrent->replaceTrackers(remaining_trackers);
if (!torrent->isPaused())
torrent->forceReannounce();
}
void TrackerList::editSelectedTracker() {
try {
QTorrentHandle h = properties->getCurrentTorrent();
QString hash = h.hash();
BitTorrent::TorrentHandle *const torrent = properties->getCurrentTorrent();
if (!torrent) return;
QString hash = torrent->hash();
QList<QTreeWidgetItem *> selected_items = getSelectedTrackerItems();
if (selected_items.isEmpty())
@@ -381,91 +372,78 @@ void TrackerList::editSelectedTracker() {
if (new_tracker_url == tracker_url)
return;
std::vector<announce_entry> trackers = h.trackers();
std::vector<announce_entry>::iterator it = trackers.begin();
std::vector<announce_entry>::iterator itend = trackers.end();
QList<BitTorrent::TrackerEntry> trackers = torrent->trackers();
bool match = false;
for ( ; it != itend; ++it) {
if (new_tracker_url == QUrl(misc::toQString(it->url))) {
for (int i = 0; i < trackers.size(); ++i) {
BitTorrent::TrackerEntry &entry = trackers[i];
if (new_tracker_url == QUrl(entry.url())) {
QMessageBox::warning(this, tr("Tracker editing failed"), tr("The tracker URL already exists."));
return;
}
if (tracker_url == QUrl(misc::toQStringU(it->url)) && !match) {
announce_entry new_entry(new_tracker_url.toString().toUtf8().constData());
new_entry.tier = it->tier;
if (tracker_url == QUrl(entry.url()) && !match) {
BitTorrent::TrackerEntry new_entry(new_tracker_url.toString());
new_entry.setTier(entry.tier());
match = true;
*it = new_entry;
emit trackersRemoved(QStringList(tracker_url.toString()), hash);
emit trackersAdded(QStringList(new_tracker_url.toString()), hash);
entry = new_entry;
}
}
h.replace_trackers(trackers);
if (!h.is_paused()) {
h.force_reannounce();
h.force_dht_announce();
torrent->replaceTrackers(trackers);
if (!torrent->isPaused()) {
torrent->forceReannounce();
torrent->forceDHTAnnounce();
}
} catch(invalid_handle&) {
return;
}
loadTrackers();
}
#if LIBTORRENT_VERSION_NUM >= 10000
void TrackerList::reannounceSelected() {
try {
QTorrentHandle h = properties->getCurrentTorrent();
BitTorrent::TorrentHandle *const torrent = properties->getCurrentTorrent();
if (!torrent) return;
QList<QTreeWidgetItem *> selected_items = getSelectedTrackerItems();
if (selected_items.isEmpty())
return;
if (selected_items.isEmpty()) return;
std::vector<announce_entry> trackers = h.trackers();
for (size_t i = 0; i < trackers.size(); ++i) {
QList<BitTorrent::TrackerEntry> trackers = torrent->trackers();
for (int i = 0; i < trackers.size(); ++i) {
foreach (QTreeWidgetItem* w, selected_items) {
if (w->text(COL_URL) == misc::toQString(trackers[i].url)) {
h.force_reannounce(0, i);
if (w->text(COL_URL) == trackers[i].url()) {
torrent->forceReannounce(i);
break;
}
}
}
} catch(invalid_handle&) {
return;
}
loadTrackers();
loadTrackers();
}
#endif
void TrackerList::showTrackerListMenu(QPoint) {
QTorrentHandle h = properties->getCurrentTorrent();
if (!h.is_valid()) return;
BitTorrent::TorrentHandle *const torrent = properties->getCurrentTorrent();
if (!torrent) 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 *addAct = menu.addAction(GuiIconProvider::instance()->getIcon("list-add"), tr("Add a new tracker..."));
QAction *copyAct = 0;
QAction *delAct = 0;
QAction *editAct = 0;
if (!getSelectedTrackerItems().isEmpty()) {
delAct = menu.addAction(IconProvider::instance()->getIcon("list-remove"), tr("Remove tracker"));
copyAct = menu.addAction(IconProvider::instance()->getIcon("edit-copy"), tr("Copy tracker url"));
editAct = menu.addAction(IconProvider::instance()->getIcon("edit-rename"),tr("Edit selected tracker URL"));
delAct = menu.addAction(GuiIconProvider::instance()->getIcon("list-remove"), tr("Remove tracker"));
copyAct = menu.addAction(GuiIconProvider::instance()->getIcon("edit-copy"), tr("Copy tracker url"));
editAct = menu.addAction(GuiIconProvider::instance()->getIcon("edit-rename"),tr("Edit selected tracker URL"));
}
#if LIBTORRENT_VERSION_NUM >= 10000
QAction *reannounceSelAct = NULL;
#endif
QAction *reannounceAct = NULL;
if (!h.is_paused()) {
if (!torrent->isPaused()) {
#if LIBTORRENT_VERSION_NUM >= 10000
reannounceSelAct = menu.addAction(IconProvider::instance()->getIcon("view-refresh"), tr("Force reannounce to selected trackers"));
reannounceSelAct = menu.addAction(GuiIconProvider::instance()->getIcon("view-refresh"), tr("Force reannounce to selected trackers"));
#endif
menu.addSeparator();
reannounceAct = menu.addAction(IconProvider::instance()->getIcon("view-refresh"), tr("Force reannounce to all trackers"));
reannounceAct = menu.addAction(GuiIconProvider::instance()->getIcon("view-refresh"), tr("Force reannounce to all trackers"));
}
QAction *act = menu.exec(QCursor::pos());
if (act == 0) return;
@@ -488,7 +466,7 @@ void TrackerList::showTrackerListMenu(QPoint) {
}
#endif
if (act == reannounceAct) {
properties->getCurrentTorrent().force_reannounce();
properties->getCurrentTorrent()->forceReannounce();
return;
}
if (act == editAct) {

View File

@@ -37,12 +37,16 @@
#include <QClipboard>
#include <libtorrent/version.hpp>
#include "qtorrenthandle.h"
#include "propertieswidget.h"
enum TrackerListColumn {COL_TIER, COL_URL, COL_STATUS, COL_PEERS, COL_MSG};
#define NB_STICKY_ITEM 3
namespace BitTorrent
{
class TorrentHandle;
}
class TrackerList: public QTreeWidget {
Q_OBJECT
Q_DISABLE_COPY(TrackerList)
@@ -60,11 +64,6 @@ public:
TrackerList(PropertiesWidget *properties);
~TrackerList();
signals:
void trackersAdded(const QStringList &trackers, const QString &hash);
void trackersRemoved(const QStringList &trackers, const QString &hash);
void trackerlessChange(bool trackerless, const QString &hash);
protected:
QList<QTreeWidgetItem*> getSelectedTrackerItems() const;
@@ -75,7 +74,7 @@ public slots:
void moveSelectionDown();
void clear();
void loadStickyItems(const QTorrentHandle &h);
void loadStickyItems(BitTorrent::TorrentHandle *const torrent);
void loadTrackers();
void askForTrackers();
void copyTrackerUrl();

View File

@@ -36,24 +36,26 @@
#include <QMessageBox>
#include <QFile>
#include <QUrl>
#include "iconprovider.h"
#include "guiiconprovider.h"
#include "core/misc.h"
#include "ui_trackersadditiondlg.h"
#include "core/downloadthread.h"
#include "qtorrenthandle.h"
#include "core/net/downloadmanager.h"
#include "core/net/downloadhandler.h"
#include "core/bittorrent/trackerentry.h"
#include "core/bittorrent/torrenthandle.h"
#include "core/fs_utils.h"
class TrackersAdditionDlg : public QDialog, private Ui::TrackersAdditionDlg{
Q_OBJECT
private:
QTorrentHandle h;
BitTorrent::TorrentHandle *const m_torrent;
public:
TrackersAdditionDlg(QTorrentHandle h, QWidget *parent=0): QDialog(parent), h(h) {
TrackersAdditionDlg(BitTorrent::TorrentHandle *const torrent, QWidget *parent = 0): QDialog(parent), m_torrent(torrent) {
setupUi(this);
// Icons
uTorrentListButton->setIcon(IconProvider::instance()->getIcon("download"));
uTorrentListButton->setIcon(GuiIconProvider::instance()->getIcon("download"));
}
~TrackersAdditionDlg() {}
@@ -65,41 +67,33 @@ public:
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)));
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(QString("http://www.torrentz.com/announce_%1").arg(m_torrent->hash()));
connect(handler, SIGNAL(downloadFinished(QString, QString)), this, SLOT(parseUTorrentList(QString, QString)));
connect(handler, SIGNAL(downloadFailed(QString, QString)), this, 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) {
void parseUTorrentList(const QString &, const 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();
fsutils::forceRemove(path);
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();
std::vector<libtorrent::announce_entry>::iterator itrend = tor_trackers.end();
while(itr != itrend) {
existingTrackers << QUrl(misc::toQString(itr->url));
++itr;
}
// Load from torrent handle
QList<BitTorrent::TrackerEntry> existingTrackers = m_torrent->trackers();
// 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;
foreach (const QString &user_url, tmp) {
BitTorrent::TrackerEntry userTracker(user_url);
if (!existingTrackers.contains(userTracker))
existingTrackers << userTracker;
}
// Add new trackers to the list
if (!trackers_list->toPlainText().isEmpty() && !trackers_list->toPlainText().endsWith("\n"))
trackers_list->insertPlainText("\n");
@@ -107,8 +101,8 @@ public slots:
while (!list_file.atEnd()) {
const QByteArray line = list_file.readLine().trimmed();
if (line.isEmpty()) continue;
QUrl url(line);
if (!existingTrackers.contains(url)) {
BitTorrent::TrackerEntry newTracker(line);
if (!existingTrackers.contains(newTracker)) {
trackers_list->insertPlainText(line + "\n");
++nb;
}
@@ -123,22 +117,20 @@ public slots:
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) {
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) {
static QStringList askForTrackers(BitTorrent::TorrentHandle *const torrent) {
QStringList trackers;
TrackersAdditionDlg dlg(h);
TrackersAdditionDlg dlg(torrent);
if (dlg.exec() == QDialog::Accepted) {
return dlg.newTrackers();
}

View File

@@ -40,7 +40,7 @@
#include "core/preferences.h"
#include "rssmanager.h"
#include "rssfeed.h"
#include "iconprovider.h"
#include "guiiconprovider.h"
#include "autoexpandabledialog.h"
#include "core/fs_utils.h"
@@ -51,8 +51,8 @@ AutomatedRssDownloader::AutomatedRssDownloader(const QWeakPointer<RssManager>& m
{
ui->setupUi(this);
// Icons
ui->removeRuleBtn->setIcon(IconProvider::instance()->getIcon("list-remove"));
ui->addRuleBtn->setIcon(IconProvider::instance()->getIcon("list-add"));
ui->removeRuleBtn->setIcon(GuiIconProvider::instance()->getIcon("list-remove"));
ui->addRuleBtn->setIcon(GuiIconProvider::instance()->getIcon("list-add"));
// Ui Settings
ui->listRules->setSortingEnabled(true);
@@ -436,17 +436,17 @@ void AutomatedRssDownloader::displayRulesListMenu(const QPoint &pos)
{
Q_UNUSED(pos);
QMenu menu;
QAction *addAct = menu.addAction(IconProvider::instance()->getIcon("list-add"), tr("Add new rule..."));
QAction *addAct = menu.addAction(GuiIconProvider::instance()->getIcon("list-add"), tr("Add new rule..."));
QAction *delAct = 0;
QAction *renameAct = 0;
const QList<QListWidgetItem*> selection = ui->listRules->selectedItems();
if (!selection.isEmpty()) {
if (selection.count() == 1) {
delAct = menu.addAction(IconProvider::instance()->getIcon("list-remove"), tr("Delete rule"));
delAct = menu.addAction(GuiIconProvider::instance()->getIcon("list-remove"), tr("Delete rule"));
menu.addSeparator();
renameAct = menu.addAction(IconProvider::instance()->getIcon("edit-rename"), tr("Rename rule..."));
renameAct = menu.addAction(GuiIconProvider::instance()->getIcon("edit-rename"), tr("Rename rule..."));
} else {
delAct = menu.addAction(IconProvider::instance()->getIcon("list-remove"), tr("Delete selected rules"));
delAct = menu.addAction(GuiIconProvider::instance()->getIcon("list-remove"), tr("Delete selected rules"));
}
}
QAction *act = menu.exec(QCursor::pos());
@@ -557,7 +557,7 @@ void AutomatedRssDownloader::addFeedArticlesToTree(const RssFeedPtr& feed, const
QFont f = treeFeedItem->font(0);
f.setBold(true);
treeFeedItem->setFont(0, f);
treeFeedItem->setData(0, Qt::DecorationRole, IconProvider::instance()->getIcon("inode-directory"));
treeFeedItem->setData(0, Qt::DecorationRole, GuiIconProvider::instance()->getIcon("inode-directory"));
treeFeedItem->setData(0, Qt::UserRole, feed->url());
ui->treeMatchingArticles->addTopLevelItem(treeFeedItem);
}
@@ -606,7 +606,7 @@ void AutomatedRssDownloader::updateMustLineValidity()
ui->lbl_must_stat->setPixmap(QPixmap());
} else {
ui->lineContains->setStyleSheet("QLineEdit { color: #ff0000; }");
ui->lbl_must_stat->setPixmap(IconProvider::instance()->getIcon("task-attention").pixmap(16, 16));
ui->lbl_must_stat->setPixmap(GuiIconProvider::instance()->getIcon("task-attention").pixmap(16, 16));
}
}
@@ -631,7 +631,7 @@ void AutomatedRssDownloader::updateMustNotLineValidity()
ui->lbl_mustnot_stat->setPixmap(QPixmap());
} else {
ui->lineNotContains->setStyleSheet("QLineEdit { color: #ff0000; }");
ui->lbl_mustnot_stat->setPixmap(IconProvider::instance()->getIcon("task-attention").pixmap(16, 16));
ui->lbl_mustnot_stat->setPixmap(GuiIconProvider::instance()->getIcon("task-attention").pixmap(16, 16));
}
}

View File

@@ -30,7 +30,7 @@
#include "cookiesdlg.h"
#include "ui_cookiesdlg.h"
#include "iconprovider.h"
#include "guiiconprovider.h"
#include <QNetworkCookie>
@@ -42,8 +42,8 @@ CookiesDlg::CookiesDlg(QWidget *parent, const QList<QByteArray> &raw_cookies) :
{
ui->setupUi(this);
// Icons
ui->add_btn->setIcon(IconProvider::instance()->getIcon("list-add"));
ui->del_btn->setIcon(IconProvider::instance()->getIcon("list-remove"));
ui->add_btn->setIcon(GuiIconProvider::instance()->getIcon("list-add"));
ui->del_btn->setIcon(GuiIconProvider::instance()->getIcon("list-remove"));
ui->infos_lbl->setText(tr("Common keys for cookies are : '%1', '%2'.\nYou should get this information from your Web browser preferences.").arg("uid").arg("pass"));
foreach (const QByteArray &raw_cookie, raw_cookies) {

View File

@@ -31,7 +31,7 @@
#include "feedlistwidget.h"
#include "rssmanager.h"
#include "rssfeed.h"
#include "iconprovider.h"
#include "guiiconprovider.h"
FeedListWidget::FeedListWidget(QWidget *parent, const RssManagerPtr& rssmanager): QTreeWidget(parent), m_rssManager(rssmanager) {
setContextMenuPolicy(Qt::CustomContextMenu);
@@ -41,7 +41,7 @@ FeedListWidget::FeedListWidget(QWidget *parent, const RssManagerPtr& rssmanager)
headerItem()->setText(0, tr("RSS feeds"));
m_unreadStickyItem = new QTreeWidgetItem(this);
m_unreadStickyItem->setText(0, tr("Unread") + QString::fromUtf8(" (") + QString::number(rssmanager->unreadCount())+ QString(")"));
m_unreadStickyItem->setData(0,Qt::DecorationRole, IconProvider::instance()->getIcon("mail-folder-inbox"));
m_unreadStickyItem->setData(0,Qt::DecorationRole, GuiIconProvider::instance()->getIcon("mail-folder-inbox"));
itemAdded(m_unreadStickyItem, rssmanager);
connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), SLOT(updateCurrentFeed(QTreeWidgetItem*)));
setCurrentItem(m_unreadStickyItem);

View File

@@ -39,7 +39,8 @@
#include "rss_imp.h"
#include "feedlistwidget.h"
#include "qbtsession.h"
#include "core/bittorrent/session.h"
#include "core/net/downloadmanager.h"
#include "cookiesdlg.h"
#include "core/preferences.h"
#include "rsssettingsdlg.h"
@@ -49,8 +50,9 @@
#include "rssparser.h"
#include "rssfeed.h"
#include "automatedrssdownloader.h"
#include "iconprovider.h"
#include "guiiconprovider.h"
#include "autoexpandabledialog.h"
#include "addnewtorrentdialog.h"
namespace Article
{
@@ -140,6 +142,7 @@ void RSSImp::on_actionManage_cookies_triggered()
if (ok) {
qDebug() << "Settings cookies for host name: " << feed_hostname;
pref->setHostNameCookies(feed_hostname, raw_cookies);
Net::DownloadManager::instance()->setCookiesFromUrl(pref->getHostNameQNetworkCookies(feed_hostname), feed_hostname);
}
}
@@ -343,17 +346,10 @@ void RSSImp::downloadSelectedTorrents()
QString torrentLink = article->torrentUrl();
// Check if it is a magnet link
if (torrentLink.startsWith("magnet:", Qt::CaseInsensitive)) {
QBtSession::instance()->addMagnetInteractive(torrentLink);
}
else {
// Load possible cookies
QString feed_url = m_feedList->getItemID(m_feedList->selectedItems().first());
QString feed_hostname = QUrl::fromEncoded(feed_url.toUtf8()).host();
QList<QNetworkCookie> cookies = Preferences::instance()->getHostNameQNetworkCookies(feed_hostname);
qDebug("Loaded %d cookies for RSS item\n", cookies.size());
QBtSession::instance()->downloadFromUrl(torrentLink, cookies);
}
if (torrentLink.startsWith("magnet:", Qt::CaseInsensitive) && Preferences::instance()->useAdditionDialog())
AddNewTorrentDialog::show(torrentLink);
else
BitTorrent::Session::instance()->addTorrent(torrentLink);
}
}
@@ -700,22 +696,22 @@ RSSImp::RSSImp(QWidget *parent):
{
setupUi(this);
// Icons
actionCopy_feed_URL->setIcon(IconProvider::instance()->getIcon("edit-copy"));
actionDelete->setIcon(IconProvider::instance()->getIcon("edit-delete"));
actionDownload_torrent->setIcon(IconProvider::instance()->getIcon("download"));
actionManage_cookies->setIcon(IconProvider::instance()->getIcon("preferences-web-browser-cookies"));
actionMark_items_read->setIcon(IconProvider::instance()->getIcon("mail-mark-read"));
actionNew_folder->setIcon(IconProvider::instance()->getIcon("folder-new"));
actionNew_subscription->setIcon(IconProvider::instance()->getIcon("list-add"));
actionOpen_news_URL->setIcon(IconProvider::instance()->getIcon("application-x-mswinurl"));
actionRename->setIcon(IconProvider::instance()->getIcon("edit-rename"));
actionUpdate->setIcon(IconProvider::instance()->getIcon("view-refresh"));
actionUpdate_all_feeds->setIcon(IconProvider::instance()->getIcon("view-refresh"));
newFeedButton->setIcon(IconProvider::instance()->getIcon("list-add"));
markReadButton->setIcon(IconProvider::instance()->getIcon("mail-mark-read"));
updateAllButton->setIcon(IconProvider::instance()->getIcon("view-refresh"));
rssDownloaderBtn->setIcon(IconProvider::instance()->getIcon("download"));
settingsButton->setIcon(IconProvider::instance()->getIcon("preferences-system"));
actionCopy_feed_URL->setIcon(GuiIconProvider::instance()->getIcon("edit-copy"));
actionDelete->setIcon(GuiIconProvider::instance()->getIcon("edit-delete"));
actionDownload_torrent->setIcon(GuiIconProvider::instance()->getIcon("download"));
actionManage_cookies->setIcon(GuiIconProvider::instance()->getIcon("preferences-web-browser-cookies"));
actionMark_items_read->setIcon(GuiIconProvider::instance()->getIcon("mail-mark-read"));
actionNew_folder->setIcon(GuiIconProvider::instance()->getIcon("folder-new"));
actionNew_subscription->setIcon(GuiIconProvider::instance()->getIcon("list-add"));
actionOpen_news_URL->setIcon(GuiIconProvider::instance()->getIcon("application-x-mswinurl"));
actionRename->setIcon(GuiIconProvider::instance()->getIcon("edit-rename"));
actionUpdate->setIcon(GuiIconProvider::instance()->getIcon("view-refresh"));
actionUpdate_all_feeds->setIcon(GuiIconProvider::instance()->getIcon("view-refresh"));
newFeedButton->setIcon(GuiIconProvider::instance()->getIcon("list-add"));
markReadButton->setIcon(GuiIconProvider::instance()->getIcon("mail-mark-read"));
updateAllButton->setIcon(GuiIconProvider::instance()->getIcon("view-refresh"));
rssDownloaderBtn->setIcon(GuiIconProvider::instance()->getIcon("download"));
settingsButton->setIcon(GuiIconProvider::instance()->getIcon("preferences-system"));
m_feedList = new FeedListWidget(splitter_h, m_rssManager);
splitter_h->insertWidget(0, m_feedList);

View File

@@ -31,7 +31,7 @@
#include <QDebug>
#include "rssfeed.h"
#include "rssmanager.h"
#include "qbtsession.h"
#include "core/bittorrent/session.h"
#include "rssfolder.h"
#include "core/preferences.h"
#include "core/qinisettings.h"
@@ -39,7 +39,8 @@
#include "rssparser.h"
#include "core/misc.h"
#include "rssdownloadrulelist.h"
#include "core/downloadthread.h"
#include "core/net/downloadmanager.h"
#include "core/net/downloadhandler.h"
#include "core/fs_utils.h"
#include "core/logger.h"
@@ -60,15 +61,15 @@ RssFeed::RssFeed(RssManager* manager, RssFolder* parent, const QString& url):
{
qDebug() << Q_FUNC_INFO << m_url;
// Listen for new RSS downloads
connect(manager->rssDownloader(), SIGNAL(downloadFinished(QString,QString)), SLOT(handleFinishedDownload(QString,QString)));
connect(manager->rssDownloader(), SIGNAL(downloadFailure(QString,QString)), SLOT(handleDownloadFailure(QString,QString)));
connect(manager->rssParser(), SIGNAL(feedTitle(QString,QString)), SLOT(handleFeedTitle(QString,QString)));
connect(manager->rssParser(), SIGNAL(newArticle(QString,QVariantHash)), SLOT(handleNewArticle(QString,QVariantHash)));
connect(manager->rssParser(), SIGNAL(feedParsingFinished(QString,QString)), SLOT(handleFeedParsingFinished(QString,QString)));
// Download the RSS Feed icon
m_iconUrl = iconUrl();
manager->rssDownloader()->downloadUrl(m_iconUrl);
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(iconUrl());
connect(handler, SIGNAL(downloadFinished(QString, QString)), this, SLOT(handleFinishedDownload(QString, QString)));
connect(handler, SIGNAL(downloadFailed(QString, QString)), this, SLOT(handleDownloadFailure(QString, QString)));
m_iconUrl = handler->url();
// Load old RSS articles
loadItemsFromDisk();
@@ -159,12 +160,6 @@ void RssFeed::addArticle(const RssArticlePtr& article) {
}
}
QList<QNetworkCookie> RssFeed::feedCookies() const
{
QString feed_hostname = QUrl::fromEncoded(m_url.toUtf8()).host();
return Preferences::instance()->getHostNameQNetworkCookies(feed_hostname);
}
bool RssFeed::refresh()
{
if (m_loading) {
@@ -173,7 +168,10 @@ bool RssFeed::refresh()
}
m_loading = true;
// Download the RSS again
m_manager->rssDownloader()->downloadUrl(m_url, feedCookies());
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(m_url);
connect(handler, SIGNAL(downloadFinished(QString, QString)), this, SLOT(handleFinishedDownload(QString, QString)));
connect(handler, SIGNAL(downloadFailed(QString, QString)), this, SLOT(handleDownloadFailure(QString, QString)));
m_url = handler->url(); // sync URL encoding
return true;
}
@@ -307,7 +305,7 @@ QString RssFeed::iconUrl() const
}
// read and store the downloaded rss' informations
void RssFeed::handleFinishedDownload(const QString& url, const QString& filePath)
void RssFeed::handleFinishedDownload(const QString &url, const QString &filePath)
{
if (url == m_url) {
qDebug() << Q_FUNC_INFO << "Successfully downloaded RSS feed at" << url;
@@ -320,10 +318,9 @@ void RssFeed::handleFinishedDownload(const QString& url, const QString& filePath
}
}
void RssFeed::handleDownloadFailure(const QString& url, const QString& error)
void RssFeed::handleDownloadFailure(const QString &url, const QString &error)
{
if (url != m_url)
return;
if (url != m_url) return;
m_inErrorState = true;
m_loading = false;
@@ -369,12 +366,17 @@ void RssFeed::downloadArticleTorrentIfMatching(RssDownloadRuleList* rules, const
// Download the torrent
const QString& torrent_url = article->torrentUrl();
Logger::instance()->addMessage(tr("Automatically downloading %1 torrent from %2 RSS feed...").arg(article->title()).arg(displayName()));
connect(QBtSession::instance(), SIGNAL(newDownloadedTorrentFromRss(QString)), article.data(), SLOT(handleTorrentDownloadSuccess(const QString&)), Qt::UniqueConnection);
connect(BitTorrent::Session::instance(), SIGNAL(downloadFromUrlFinished(QString)), article.data(), SLOT(handleTorrentDownloadSuccess(const QString&)), Qt::UniqueConnection);
connect(article.data(), SIGNAL(articleWasRead()), SLOT(handleArticleStateChanged()), Qt::UniqueConnection);
if (torrent_url.startsWith("magnet:", Qt::CaseInsensitive))
QBtSession::instance()->addMagnetSkipAddDlg(torrent_url, matching_rule->savePath(), matching_rule->label(), matching_rule->addPaused());
else
QBtSession::instance()->downloadUrlAndSkipDialog(torrent_url, matching_rule->savePath(), matching_rule->label(), feedCookies(), matching_rule->addPaused());
BitTorrent::AddTorrentParams params;
params.savePath = matching_rule->savePath();
params.label = matching_rule->label();
if (matching_rule->addPaused() == RssDownloadRule::ALWAYS_PAUSED)
params.addPaused = TriStateBool::True;
else if (matching_rule->addPaused() == RssDownloadRule::NEVER_PAUSED)
params.addPaused = TriStateBool::False;
BitTorrent::Session::instance()->addTorrent(torrent_url, params);
}
void RssFeed::recheckRssItemsForDownload()
@@ -426,7 +428,8 @@ void RssFeed::handleFeedParsingFinished(const QString& feedUrl, const QString& e
saveItemsToDisk();
}
void RssFeed::handleArticleStateChanged() {
void RssFeed::handleArticleStateChanged()
{
m_manager->forwardFeedInfosChanged(m_url, displayName(), m_unreadCount);
}

View File

@@ -81,8 +81,8 @@ public:
void recheckRssItemsForDownload();
private slots:
void handleFinishedDownload(const QString& url, const QString &file_path);
void handleDownloadFailure(const QString &url, const QString& error);
void handleFinishedDownload(const QString &url, const QString &filePath);
void handleDownloadFailure(const QString &url, const QString &error);
void handleFeedTitle(const QString& feedUrl, const QString& title);
void handleNewArticle(const QString& feedUrl, const QVariantHash& article);
void handleFeedParsingFinished(const QString& feedUrl, const QString& error);
@@ -93,7 +93,6 @@ private:
void loadItemsFromDisk();
void addArticle(const RssArticlePtr& article);
void downloadArticleTorrentIfMatching(RssDownloadRuleList* rules, const RssArticlePtr& article);
QList<QNetworkCookie> feedCookies() const;
private:
RssManager* m_manager;

View File

@@ -30,10 +30,10 @@
#include <QDebug>
#include "iconprovider.h"
#include "guiiconprovider.h"
#include "rssfolder.h"
#include "rssarticle.h"
#include "qbtsession.h"
#include "core/bittorrent/session.h"
#include "rssmanager.h"
#include "rssfeed.h"
@@ -233,7 +233,7 @@ QString RssFolder::id() const
QIcon RssFolder::icon() const
{
return IconProvider::instance()->getIcon("inode-directory");
return GuiIconProvider::instance()->getIcon("inode-directory");
}
bool RssFolder::hasChild(const QString &childId) {

View File

@@ -31,17 +31,15 @@
#include <QDebug>
#include "rssmanager.h"
#include "core/preferences.h"
#include "qbtsession.h"
#include "core/bittorrent/session.h"
#include "rssfeed.h"
#include "rssarticle.h"
#include "rssdownloadrulelist.h"
#include "rssparser.h"
#include "core/downloadthread.h"
static const int MSECS_PER_MIN = 60000;
RssManager::RssManager():
m_rssDownloader(new DownloadThread(this)),
m_downloadRules(new RssDownloadRuleList),
m_rssParser(new RssParser(this))
{
@@ -60,11 +58,6 @@ RssManager::~RssManager()
qDebug("RSSManager deleted");
}
DownloadThread* RssManager::rssDownloader() const
{
return m_rssDownloader;
}
RssParser* RssManager::rssParser() const
{
return m_rssParser;

View File

@@ -36,7 +36,6 @@
#include "rssfolder.h"
class DownloadThread;
class RssDownloadRuleList;
class RssParser;
@@ -50,7 +49,6 @@ public:
RssManager();
virtual ~RssManager();
DownloadThread* rssDownloader() const;
RssParser* rssParser() const;
RssDownloadRuleList* downloadRules() const;
@@ -71,7 +69,6 @@ signals:
private:
QTimer m_refreshTimer;
uint m_refreshInterval;
DownloadThread* m_rssDownloader;
RssDownloadRuleList* m_downloadRules;
RssParser* m_rssParser;
};

View File

@@ -29,8 +29,8 @@
*/
#include "rssparser.h"
#include "core/downloadthread.h"
#include "core/fs_utils.h"
#include <QDebug>
#include <QFile>
#include <QRegExp>

View File

@@ -34,7 +34,7 @@
#include <QPushButton>
ShutdownConfirmDlg::ShutdownConfirmDlg(const shutDownAction &action)
ShutdownConfirmDlg::ShutdownConfirmDlg(const ShutDownAction &action)
: m_exitNow(0)
, m_timeout(15)
, m_action(action)
@@ -71,7 +71,7 @@ void ShutdownConfirmDlg::showEvent(QShowEvent *event)
m_timer.start();
}
bool ShutdownConfirmDlg::askForConfirmation(const shutDownAction &action)
bool ShutdownConfirmDlg::askForConfirmation(const ShutDownAction &action)
{
ShutdownConfirmDlg dlg(action);
dlg.exec();

View File

@@ -40,10 +40,10 @@ class ShutdownConfirmDlg : public QMessageBox
Q_OBJECT
public:
ShutdownConfirmDlg(const shutDownAction &action);
ShutdownConfirmDlg(const ShutDownAction &action);
bool shutdown() const;
static bool askForConfirmation(const shutDownAction &action);
static bool askForConfirmation(const ShutDownAction &action);
QAbstractButton *getExit_now() const;
void setExit_now(QAbstractButton *value);
@@ -62,7 +62,7 @@ private:
QAbstractButton *m_exitNow;
QTimer m_timer;
int m_timeout;
shutDownAction m_action;
ShutDownAction m_action;
};
#endif // SHUTDOWNCONFIRM_H

View File

@@ -35,7 +35,7 @@
#include <QList>
#include "ui_bandwidth_limit.h"
#include "core/misc.h"
#include "qbtsession.h"
#include "core/bittorrent/session.h"
class SpeedLimitDialog : public QDialog, private Ui_bandwidth_dlg {
Q_OBJECT

View File

@@ -32,14 +32,18 @@
#include "ui_statsdialog.h"
#include "core/misc.h"
#include <libtorrent/session.hpp>
#include <libtorrent/disk_io_thread.hpp>
#include "core/bittorrent/session.h"
#include "core/bittorrent/sessionstatus.h"
#include "core/bittorrent/cachestatus.h"
#include "core/bittorrent/torrenthandle.h"
StatsDialog::StatsDialog(QWidget *parent) : QDialog(parent), ui(new Ui::StatsDialog) {
StatsDialog::StatsDialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::StatsDialog)
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
connect(ui->buttonOK, SIGNAL(clicked()), SLOT(close()));
session = QBtSession::instance();
updateUI();
t = new QTimer(this);
t->setInterval(1500);
@@ -55,17 +59,16 @@ StatsDialog::~StatsDialog() {
}
void StatsDialog::updateUI() {
libtorrent::session* s = session->getSession();
libtorrent::cache_status cache = s->get_cache_status();
libtorrent::session_status ss = s->status();
BitTorrent::SessionStatus ss = BitTorrent::Session::instance()->status();
BitTorrent::CacheStatus cs = BitTorrent::Session::instance()->cacheStatus();
// Alltime DL/UL
quint64 atd = session->getAlltimeDL();
quint64 atu = session->getAlltimeUL();
quint64 atd = BitTorrent::Session::instance()->getAlltimeDL();
quint64 atu = BitTorrent::Session::instance()->getAlltimeUL();
ui->labelAlltimeDL->setText(misc::friendlyUnit(atd));
ui->labelAlltimeUL->setText(misc::friendlyUnit(atu));
// Total waste (this session)
ui->labelWaste->setText(misc::friendlyUnit(ss.total_redundant_bytes + ss.total_failed_bytes));
ui->labelWaste->setText(misc::friendlyUnit(ss.totalWasted()));
// Global ratio
ui->labelGlobalRatio->setText(
( atd > 0 && atu > 0 ) ?
@@ -73,39 +76,30 @@ void StatsDialog::updateUI() {
"-"
);
// Cache hits
ui->labelCacheHits->setText(
( cache.blocks_read > 0 && cache.blocks_read_hit > 0 ) ?
misc::accurateDoubleToString(100. * (qreal)cache.blocks_read_hit / (qreal)cache.blocks_read, 2) :
"-"
);
qreal readRatio = cs.readRatio();
ui->labelCacheHits->setText((readRatio >= 0) ? misc::accurateDoubleToString(100 * readRatio, 2) : "-");
// Buffers size
ui->labelTotalBuf->setText(misc::friendlyUnit(cache.total_used_buffers * 16 * 1024));
ui->labelTotalBuf->setText(misc::friendlyUnit(cs.totalUsedBuffers() * 16 * 1024));
// Disk overload (100%) equivalent
// From lt manual: disk_write_queue and disk_read_queue are the number of peers currently waiting on a disk write or disk read
// to complete before it receives or sends any more data on the socket. It'a a metric of how disk bound you are.
// num_peers is not reliable (adds up peers, which didn't even overcome tcp handshake)
const std::vector<libtorrent::torrent_handle> torrents = session->getTorrents();
std::vector<libtorrent::torrent_handle>::const_iterator iBegin = torrents.begin();
std::vector<libtorrent::torrent_handle>::const_iterator iEnd = torrents.end();
quint32 peers = 0;
for ( ; iBegin < iEnd ; ++iBegin)
peers += (*iBegin).status().num_peers;
ui->labelWriteStarve->setText(
( ss.disk_write_queue > 0 && peers > 0 ) ?
misc::accurateDoubleToString(100. * (qreal)ss.disk_write_queue / (qreal)peers, 2) + "%" :
QString("0\%")
);
ui->labelReadStarve->setText(
( ss.disk_read_queue > 0 && peers > 0 ) ?
misc::accurateDoubleToString(100. * (qreal)ss.disk_read_queue / (qreal)peers, 2) + "%" :
QString("0\%")
);
foreach (BitTorrent::TorrentHandle *const torrent, BitTorrent::Session::instance()->torrents())
peers += torrent->peersCount();
ui->labelWriteStarve->setText(QString("%1%").arg(((ss.diskWriteQueue() > 0) && (peers > 0))
? misc::accurateDoubleToString((100. * ss.diskWriteQueue()) / peers, 2)
: "0"));
ui->labelReadStarve->setText(QString("%1%").arg(((ss.diskReadQueue() > 0) && (peers > 0))
? misc::accurateDoubleToString((100. * ss.diskReadQueue()) / peers, 2)
: "0"));
// Disk queues
ui->labelQueuedJobs->setText(QString::number(cache.job_queue_length));
ui->labelJobsTime->setText(QString::number(cache.average_job_time));
ui->labelQueuedBytes->setText(misc::friendlyUnit(cache.queued_bytes));
ui->labelQueuedJobs->setText(QString::number(cs.jobQueueLength()));
ui->labelJobsTime->setText(QString::number(cs.averageJobTime()));
ui->labelQueuedBytes->setText(misc::friendlyUnit(cs.queuedBytes()));
// Total connected peers
ui->labelPeers->setText(QString::number(ss.num_peers));
ui->labelPeers->setText(QString::number(ss.peersCount()));
}

View File

@@ -33,7 +33,6 @@
#include <QDialog>
#include <QTimer>
#include "qbtsession.h"
namespace Ui {
class StatsDialog;
@@ -51,7 +50,6 @@ private slots:
private:
Ui::StatsDialog *ui;
QBtSession* session;
QTimer* t;
};

View File

@@ -33,21 +33,19 @@
#include <QFontMetrics>
#include <QDebug>
#include "qbtsession.h"
#include "core/bittorrent/session.h"
#include "core/bittorrent/sessionstatus.h"
#include "speedlimitdlg.h"
#include "iconprovider.h"
#include "guiiconprovider.h"
#include "core/preferences.h"
#include "core/misc.h"
#include "core/logger.h"
#include <libtorrent/session.hpp>
#include <libtorrent/session_status.hpp>
StatusBar::StatusBar(QStatusBar *bar)
: m_bar(bar)
{
Preferences* const pref = Preferences::instance();
connect(QBtSession::instance(), SIGNAL(alternativeSpeedsModeChanged(bool)), this, SLOT(updateAltSpeedsBtn(bool)));
connect(BitTorrent::Session::instance(), SIGNAL(speedLimitModeChanged(bool)), this, SLOT(updateAltSpeedsBtn(bool)));
container = new QWidget(bar);
layout = new QHBoxLayout(container);
layout->setContentsMargins(0,0,0,0);
@@ -159,12 +157,12 @@ void StatusBar::stopTimer() {
void StatusBar::refreshStatusBar() {
// Update connection status
const libtorrent::session_status sessionStatus = QBtSession::instance()->getSessionStatus();
if (!QBtSession::instance()->getSession()->is_listening()) {
const BitTorrent::SessionStatus sessionStatus = BitTorrent::Session::instance()->status();
if (!BitTorrent::Session::instance()->isListening()) {
connecStatusLblIcon->setIcon(QIcon(QString::fromUtf8(":/icons/skin/disconnected.png")));
connecStatusLblIcon->setToolTip(QString::fromUtf8("<b>")+tr("Connection Status:")+QString::fromUtf8("</b><br>")+tr("Offline. This usually means that qBittorrent failed to listen on the selected port for incoming connections."));
} else {
if (sessionStatus.has_incoming_connections) {
if (sessionStatus.hasIncomingConnections()) {
// Connection OK
connecStatusLblIcon->setIcon(QIcon(QString::fromUtf8(":/icons/skin/connected.png")));
connecStatusLblIcon->setToolTip(QString::fromUtf8("<b>")+tr("Connection Status:")+QString::fromUtf8("</b><br>")+tr("Online"));
@@ -174,22 +172,22 @@ void StatusBar::refreshStatusBar() {
}
}
// Update Number of DHT nodes
if (QBtSession::instance()->isDHTEnabled()) {
if (BitTorrent::Session::instance()->isDHTEnabled()) {
DHTLbl->setVisible(true);
//statusSep1->setVisible(true);
DHTLbl->setText(tr("DHT: %1 nodes").arg(QString::number(sessionStatus.dht_nodes)));
DHTLbl->setText(tr("DHT: %1 nodes").arg(QString::number(sessionStatus.dhtNodes())));
} else {
DHTLbl->setVisible(false);
//statusSep1->setVisible(false);
}
// Update speed labels
QString speedLbl = misc::friendlyUnit(sessionStatus.payload_download_rate, true)+" ("+misc::friendlyUnit(sessionStatus.total_payload_download)+")";
int speedLimit = QBtSession::instance()->getSession()->settings().download_rate_limit;
QString speedLbl = misc::friendlyUnit(sessionStatus.payloadDownloadRate(), true)+" ("+misc::friendlyUnit(sessionStatus.totalPayloadDownload())+")";
int speedLimit = BitTorrent::Session::instance()->downloadRateLimit();
if (speedLimit)
speedLbl = "["+misc::friendlyUnit(speedLimit, true)+"] " + speedLbl;
dlSpeedLbl->setText(speedLbl);
speedLimit = QBtSession::instance()->getSession()->settings().upload_rate_limit;
speedLbl = misc::friendlyUnit(sessionStatus.payload_upload_rate, true)+" ("+misc::friendlyUnit(sessionStatus.total_payload_upload)+")";
speedLimit = BitTorrent::Session::instance()->uploadRateLimit();
speedLbl = misc::friendlyUnit(sessionStatus.payloadUploadRate(), true)+" ("+misc::friendlyUnit(sessionStatus.totalPayloadUpload())+")";
if (speedLimit)
speedLbl = "["+misc::friendlyUnit(speedLimit, true)+"] " + speedLbl;
upSpeedLbl->setText(speedLbl);
@@ -214,26 +212,26 @@ void StatusBar::toggleAlternativeSpeeds() {
pref->setSchedulerEnabled(false);
m_bar->showMessage(tr("Manual change of rate limits mode. The scheduler is disabled."), 5000);
}
QBtSession::instance()->useAlternativeSpeedsLimit(!pref->isAltBandwidthEnabled());
BitTorrent::Session::instance()->changeSpeedLimitMode(!pref->isAltBandwidthEnabled());
}
void StatusBar::capDownloadSpeed() {
bool ok = false;
int cur_limit = QBtSession::instance()->getSession()->settings().download_rate_limit;
int cur_limit = BitTorrent::Session::instance()->downloadRateLimit();
long new_limit = SpeedLimitDialog::askSpeedLimit(&ok, tr("Global Download Speed Limit"), cur_limit);
if (ok) {
Preferences* const pref = Preferences::instance();
bool alt = pref->isAltBandwidthEnabled();
if (new_limit <= 0) {
qDebug("Setting global download rate limit to Unlimited");
QBtSession::instance()->setDownloadRateLimit(-1);
BitTorrent::Session::instance()->setDownloadRateLimit(-1);
if (!alt)
pref->setGlobalDownloadLimit(-1);
else
pref->setAltGlobalDownloadLimit(-1);
} else {
qDebug("Setting global download rate limit to %.1fKb/s", new_limit/1024.);
QBtSession::instance()->setDownloadRateLimit(new_limit);
BitTorrent::Session::instance()->setDownloadRateLimit(new_limit);
if (!alt)
pref->setGlobalDownloadLimit(new_limit/1024.);
else
@@ -245,21 +243,21 @@ void StatusBar::capDownloadSpeed() {
void StatusBar::capUploadSpeed() {
bool ok = false;
int cur_limit = QBtSession::instance()->getSession()->settings().upload_rate_limit;
int cur_limit = BitTorrent::Session::instance()->uploadRateLimit();
long new_limit = SpeedLimitDialog::askSpeedLimit(&ok, tr("Global Upload Speed Limit"), cur_limit);
if (ok) {
Preferences* const pref = Preferences::instance();
bool alt = pref->isAltBandwidthEnabled();
if (new_limit <= 0) {
qDebug("Setting global upload rate limit to Unlimited");
QBtSession::instance()->setUploadRateLimit(-1);
BitTorrent::Session::instance()->setUploadRateLimit(-1);
if (!alt)
Preferences::instance()->setGlobalUploadLimit(-1);
else
Preferences::instance()->setAltGlobalUploadLimit(-1);
} else {
qDebug("Setting global upload rate limit to %.1fKb/s", new_limit/1024.);
QBtSession::instance()->setUploadRateLimit(new_limit);
BitTorrent::Session::instance()->setUploadRateLimit(new_limit);
if (!alt)
Preferences::instance()->setGlobalUploadLimit(new_limit/1024.);
else

View File

@@ -28,23 +28,25 @@
* Contact : chris@qbittorrent.org
*/
#include "iconprovider.h"
#include <QDir>
#include <QIcon>
#include "guiiconprovider.h"
#include "core/misc.h"
#include "core/fs_utils.h"
#include "torrentcontentmodel.h"
#include "torrentcontentmodelitem.h"
#include "torrentcontentmodelfolder.h"
#include "torrentcontentmodelfile.h"
#include <QDir>
namespace {
QIcon get_directory_icon() {
static QIcon cached = IconProvider::instance()->getIcon("inode-directory");
static QIcon cached = GuiIconProvider::instance()->getIcon("inode-directory");
return cached;
}
QIcon get_file_icon() {
static QIcon cached = IconProvider::instance()->getIcon("text-plain");
static QIcon cached = GuiIconProvider::instance()->getIcon("text-plain");
return cached;
}
}
@@ -61,15 +63,14 @@ TorrentContentModel::~TorrentContentModel()
delete m_rootItem;
}
void TorrentContentModel::updateFilesProgress(const std::vector<libtorrent::size_type>& fp)
void TorrentContentModel::updateFilesProgress(const QVector<qreal> &fp)
{
Q_ASSERT(m_filesIndex.size() == (int)fp.size());
Q_ASSERT(m_filesIndex.size() == fp.size());
// XXX: Why is this necessary?
if (m_filesIndex.size() != (int)fp.size())
return;
if (m_filesIndex.size() != fp.size()) return;
emit layoutAboutToBeChanged();
for (uint i = 0; i < fp.size(); ++i) {
for (int i = 0; i < fp.size(); ++i) {
m_filesIndex[i]->setProgress(fp[i]);
}
// Update folders progress in the tree
@@ -77,7 +78,7 @@ void TorrentContentModel::updateFilesProgress(const std::vector<libtorrent::size
emit dataChanged(index(0,0), index(rowCount(), columnCount()));
}
void TorrentContentModel::updateFilesPriorities(const std::vector<int>& fprio)
void TorrentContentModel::updateFilesPriorities(const QVector<int> &fprio)
{
Q_ASSERT(m_filesIndex.size() == (int)fprio.size());
// XXX: Why is this necessary?
@@ -85,15 +86,15 @@ void TorrentContentModel::updateFilesPriorities(const std::vector<int>& fprio)
return;
emit layoutAboutToBeChanged();
for (uint i = 0; i < fprio.size(); ++i) {
for (int i = 0; i < fprio.size(); ++i) {
m_filesIndex[i]->setPriority(fprio[i]);
}
emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
}
std::vector<int> TorrentContentModel::getFilesPriorities() const
QVector<int> TorrentContentModel::getFilePriorities() const
{
std::vector<int> prio;
QVector<int> prio;
prio.reserve(m_filesIndex.size());
foreach (const TorrentContentModelFile* file, m_filesIndex) {
prio.push_back(file->priority());
@@ -280,23 +281,22 @@ void TorrentContentModel::clear()
endResetModel();
}
void TorrentContentModel::setupModelData(const libtorrent::torrent_info& t)
void TorrentContentModel::setupModelData(const BitTorrent::TorrentInfo &info)
{
qDebug("setup model data called");
if (t.num_files() == 0)
if (info.filesCount() == 0)
return;
emit layoutAboutToBeChanged();
// Initialize files_index array
qDebug("Torrent contains %d files", t.num_files());
m_filesIndex.reserve(t.num_files());
qDebug("Torrent contains %d files", info.filesCount());
m_filesIndex.reserve(info.filesCount());
TorrentContentModelFolder* current_parent;
// Iterate over files
for (int i = 0; i < t.num_files(); ++i) {
const libtorrent::file_entry& fentry = t.file_at(i);
for (int i = 0; i < info.filesCount(); ++i) {
current_parent = m_rootItem;
QString path = fsutils::fromNativePath(misc::toQStringU(fentry.path));
QString path = fsutils::fromNativePath(info.filePath(i));
// Iterate of parts of the path to create necessary folders
QStringList pathFolders = path.split("/", QString::SkipEmptyParts);
pathFolders.removeLast();
@@ -311,7 +311,7 @@ void TorrentContentModel::setupModelData(const libtorrent::torrent_info& t)
current_parent = new_parent;
}
// Actually create the file
TorrentContentModelFile* fileItem = new TorrentContentModelFile(fentry, current_parent, i);
TorrentContentModelFile* fileItem = new TorrentContentModelFile(info.fileName(i), info.fileSize(i), current_parent, i);
current_parent->appendChild(fileItem);
m_filesIndex.push_back(fileItem);
}

View File

@@ -36,8 +36,7 @@
#include <QVector>
#include <QVariant>
#include <libtorrent/torrent_info.hpp>
#include "core/bittorrent/torrentinfo.h"
#include "torrentcontentmodelitem.h"
class TorrentContentModelFile;
@@ -49,9 +48,9 @@ public:
TorrentContentModel(QObject *parent = 0);
~TorrentContentModel();
void updateFilesProgress(const std::vector<libtorrent::size_type>& fp);
void updateFilesPriorities(const std::vector<int> &fprio);
std::vector<int> getFilesPriorities() const;
void updateFilesProgress(const QVector<qreal> &fp);
void updateFilesPriorities(const QVector<int> &fprio);
QVector<int> getFilePriorities() const;
bool allFiltered() const;
virtual int columnCount(const QModelIndex &parent=QModelIndex()) const;
virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
@@ -64,7 +63,7 @@ public:
virtual QModelIndex parent(const QModelIndex& index) const;
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const;
void clear();
void setupModelData(const libtorrent::torrent_info& t);
void setupModelData(const BitTorrent::TorrentInfo &info);
signals:
void filteredFilesChanged();

View File

@@ -30,24 +30,21 @@
#include "torrentcontentmodelfile.h"
#include "torrentcontentmodelfolder.h"
#include "core/fs_utils.h"
#include "core/misc.h"
TorrentContentModelFile::TorrentContentModelFile(const libtorrent::file_entry& f,
TorrentContentModelFolder* parent,
int file_index)
TorrentContentModelFile::TorrentContentModelFile(const QString &fileName, qulonglong fileSize,
TorrentContentModelFolder* parent, int file_index)
: TorrentContentModelItem(parent)
, m_fileIndex(file_index)
{
Q_ASSERT(parent);
m_name = fsutils::fileName(misc::toQStringU(f.path.c_str()));
m_name = fileName;
// Do not display incomplete extensions
if (m_name.endsWith(".!qB"))
m_name.chop(4);
m_size = (qulonglong)f.size;
m_size = fileSize;
}
int TorrentContentModelFile::fileIndex() const
@@ -69,8 +66,8 @@ void TorrentContentModelFile::setPriority(int new_prio, bool update_parent)
m_parentItem->updatePriority();
}
void TorrentContentModelFile::setProgress(qulonglong done)
void TorrentContentModelFile::setProgress(qreal progress)
{
m_totalDone = done;
Q_ASSERT(m_totalDone <= m_size);
m_progress = progress;
Q_ASSERT(m_progress <= 1.);
}

View File

@@ -36,13 +36,12 @@
class TorrentContentModelFile : public TorrentContentModelItem
{
public:
TorrentContentModelFile(const libtorrent::file_entry& f,
TorrentContentModelFolder* parent,
int file_index);
TorrentContentModelFile(const QString &fileName, qulonglong fileSize,
TorrentContentModelFolder* parent, int file_index);
int fileIndex() const;
void setPriority(int new_prio, bool update_parent = true);
void setProgress(qulonglong done);
void setProgress(qreal progress);
ItemType itemType() const { return FileType; }
private:

View File

@@ -28,6 +28,7 @@
* Contact : chris@qbittorrent.org
*/
#include <QDebug>
#include "torrentcontentmodelfolder.h"
TorrentContentModelFolder::TorrentContentModelFolder(const QString& name, TorrentContentModelFolder* parent)
@@ -135,18 +136,20 @@ void TorrentContentModelFolder::setPriority(int new_prio, bool update_parent)
void TorrentContentModelFolder::recalculateProgress()
{
qulonglong totalDone = 0;
qreal progress = 0;
int count = 0;
foreach (TorrentContentModelItem* child, m_childItems) {
if (child->priority() != prio::IGNORED) {
if (child->itemType() == FolderType)
static_cast<TorrentContentModelFolder*>(child)->recalculateProgress();
totalDone += child->totalDone();
progress += child->progress();
++count;
}
}
if (!isRootItem()) {
m_totalDone = totalDone;
Q_ASSERT(m_totalDone <= m_size);
if (!isRootItem() && (count > 0)) {
m_progress = progress / count;
Q_ASSERT(m_progress <= 1.);
}
}

View File

@@ -38,7 +38,7 @@ TorrentContentModelItem::TorrentContentModelItem(TorrentContentModelFolder* pare
: m_parentItem(parent)
, m_size(0)
, m_priority(prio::NORMAL)
, m_totalDone(0)
, m_progress(0)
{
}
@@ -65,21 +65,14 @@ qulonglong TorrentContentModelItem::size() const
return m_size;
}
qulonglong TorrentContentModelItem::totalDone() const
qreal TorrentContentModelItem::progress() const
{
Q_ASSERT(!isRootItem());
return m_totalDone;
}
Q_ASSERT(!isRootItem());
if (m_priority == prio::IGNORED) return 0;
float TorrentContentModelItem::progress() const
{
Q_ASSERT(!isRootItem());
if (m_priority == prio::IGNORED)
return 0;
if (m_size > 0) return m_progress;
if (m_size > 0)
return m_totalDone / (double) m_size;
return 1;
return 1;
}
int TorrentContentModelItem::priority() const

View File

@@ -34,8 +34,6 @@
#include <QList>
#include <QVariant>
#include <libtorrent/torrent_info.hpp>
namespace prio {
enum FilePriority {IGNORED=0, NORMAL=1, HIGH=2, MAXIMUM=7, MIXED=-1};
}
@@ -58,9 +56,7 @@ public:
void setName(const QString& name);
qulonglong size() const;
qulonglong totalDone() const;
float progress() const;
qreal progress() const;
int priority() const;
virtual void setPriority(int new_prio, bool update_parent = true) = 0;
@@ -77,7 +73,7 @@ protected:
QString m_name;
qulonglong m_size;
int m_priority;
qulonglong m_totalDone;
qreal m_progress;
};
#endif // TORRENTCONTENTMODELITEM_H

View File

@@ -1,10 +0,0 @@
INCLUDEPATH += $$PWD
FORMS += $$PWD/createtorrent.ui
HEADERS += $$PWD/torrentcreatordlg.h \
$$PWD/torrentcreatorthread.h
SOURCES += $$PWD/torrentcreatordlg.cpp \
$$PWD/torrentcreatorthread.cpp

View File

@@ -32,41 +32,39 @@
#include <QFileDialog>
#include <QMessageBox>
#include "core/torrentpersistentdata.h"
#include "torrentcreatordlg.h"
#include "core/fs_utils.h"
#include "core/misc.h"
#include "core/preferences.h"
#include "torrentcreatorthread.h"
#include "iconprovider.h"
#include "qbtsession.h"
#include "guiiconprovider.h"
#include "core/bittorrent/session.h"
#include "core/bittorrent/torrentinfo.h"
#include "core/bittorrent/torrentcreatorthread.h"
const uint NB_PIECES_MIN = 1200;
const uint NB_PIECES_MAX = 2200;
using namespace libtorrent;
TorrentCreatorDlg::TorrentCreatorDlg(QWidget *parent): QDialog(parent), creatorThread(0) {
TorrentCreatorDlg::TorrentCreatorDlg(QWidget *parent): QDialog(parent), m_creatorThread(0) {
setupUi(this);
// Icons
addFile_button->setIcon(IconProvider::instance()->getIcon("document-new"));
addFolder_button->setIcon(IconProvider::instance()->getIcon("folder-new"));
createButton->setIcon(IconProvider::instance()->getIcon("document-save"));
cancelButton->setIcon(IconProvider::instance()->getIcon("dialog-cancel"));
addFile_button->setIcon(GuiIconProvider::instance()->getIcon("document-new"));
addFolder_button->setIcon(GuiIconProvider::instance()->getIcon("folder-new"));
createButton->setIcon(GuiIconProvider::instance()->getIcon("document-save"));
cancelButton->setIcon(GuiIconProvider::instance()->getIcon("dialog-cancel"));
setAttribute(Qt::WA_DeleteOnClose);
setModal(true);
showProgressBar(false);
loadTrackerList();
// Piece sizes
m_piece_sizes << 32 << 64 << 128 << 256 << 512 << 1024 << 2048 << 4096;
m_pieceSizes << 32 << 64 << 128 << 256 << 512 << 1024 << 2048 << 4096;
loadSettings();
show();
}
TorrentCreatorDlg::~TorrentCreatorDlg() {
if (creatorThread)
delete creatorThread;
if (m_creatorThread)
delete m_creatorThread;
}
void TorrentCreatorDlg::on_addFolder_button_clicked() {
@@ -96,7 +94,7 @@ void TorrentCreatorDlg::on_addFile_button_clicked() {
}
int TorrentCreatorDlg::getPieceSize() const {
return m_piece_sizes.at(comboPieceSize->currentIndex())*1024;
return m_pieceSizes.at(comboPieceSize->currentIndex())*1024;
}
// Main function that create a .torrent file
@@ -132,11 +130,11 @@ void TorrentCreatorDlg::on_createButton_clicked() {
QStringList url_seeds = URLSeeds_list->toPlainText().split("\n");
QString comment = txt_comment->toPlainText();
// Create the creator thread
creatorThread = new TorrentCreatorThread(this);
connect(creatorThread, SIGNAL(creationSuccess(QString, QString)), this, SLOT(handleCreationSuccess(QString, QString)));
connect(creatorThread, SIGNAL(creationFailure(QString)), this, SLOT(handleCreationFailure(QString)));
connect(creatorThread, SIGNAL(updateProgress(int)), this, SLOT(updateProgressBar(int)));
creatorThread->create(input, destination, trackers, url_seeds, comment, check_private->isChecked(), getPieceSize());
m_creatorThread = new BitTorrent::TorrentCreatorThread(this);
connect(m_creatorThread, SIGNAL(creationSuccess(QString, QString)), this, SLOT(handleCreationSuccess(QString, QString)));
connect(m_creatorThread, SIGNAL(creationFailure(QString)), this, SLOT(handleCreationFailure(QString)));
connect(m_creatorThread, SIGNAL(updateProgress(int)), this, SLOT(updateProgressBar(int)));
m_creatorThread->create(input, destination, trackers, url_seeds, comment, check_private->isChecked(), getPieceSize());
}
void TorrentCreatorDlg::handleCreationFailure(QString msg) {
@@ -152,33 +150,31 @@ void TorrentCreatorDlg::handleCreationSuccess(QString path, QString branch_path)
setCursor(QCursor(Qt::ArrowCursor));
if (checkStartSeeding->isChecked()) {
// Create save path temp data
boost::intrusive_ptr<torrent_info> t;
try {
t = new torrent_info(fsutils::toNativePath(path).toUtf8().data());
} catch(std::exception&) {
BitTorrent::TorrentInfo t = BitTorrent::TorrentInfo::loadFromFile(fsutils::toNativePath(path));
if (!t.isValid()) {
QMessageBox::critical(0, tr("Torrent creation"), tr("Created torrent file is invalid. It won't be added to download list."));
return;
}
QString hash = misc::toQString(t->info_hash());
QString save_path = branch_path;
TorrentTempData::setSavePath(hash, save_path);
// Enable seeding mode (do not recheck the files)
TorrentTempData::setSeedingMode(hash, true);
emit torrent_to_seed(path);
if (checkIgnoreShareLimits->isChecked())
QBtSession::instance()->setMaxRatioPerTorrent(hash, -1);
BitTorrent::AddTorrentParams params;
params.savePath = branch_path;
params.skipChecking = true;
params.ignoreShareRatio = checkIgnoreShareLimits->isChecked();
BitTorrent::Session::instance()->addTorrent(t, params);
}
QMessageBox::information(0, tr("Torrent creation"), tr("Torrent was created successfully:")+" "+fsutils::toNativePath(path));
close();
}
void TorrentCreatorDlg::on_cancelButton_clicked() {
// End torrent creation thread
if (creatorThread && creatorThread->isRunning()) {
creatorThread->abortCreation();
creatorThread->terminate();
if (m_creatorThread && m_creatorThread->isRunning()) {
m_creatorThread->abortCreation();
m_creatorThread->terminate();
// Wait for termination
creatorThread->wait();
m_creatorThread->wait();
}
// Close the dialog
close();
@@ -227,7 +223,7 @@ void TorrentCreatorDlg::updateOptimalPieceSize()
int i = 0;
qulonglong nb_pieces = 0;
do {
nb_pieces = (double)torrent_size/(m_piece_sizes.at(i)*1024.);
nb_pieces = (double)torrent_size/(m_pieceSizes.at(i)*1024.);
qDebug("nb_pieces=%lld with piece_size=%s", nb_pieces, qPrintable(comboPieceSize->itemText(i)));
if (nb_pieces <= NB_PIECES_MIN) {
if (i > 1)
@@ -239,7 +235,7 @@ void TorrentCreatorDlg::updateOptimalPieceSize()
break;
}
++i;
}while(i<(m_piece_sizes.size()-1));
}while(i<(m_pieceSizes.size()-1));
comboPieceSize->setCurrentIndex(i);
}

View File

@@ -33,7 +33,10 @@
#include "ui_createtorrent.h"
class TorrentCreatorThread;
namespace BitTorrent
{
class TorrentCreatorThread;
}
class TorrentCreatorDlg : public QDialog, private Ui::createTorrentDialog{
Q_OBJECT
@@ -43,9 +46,6 @@ public:
~TorrentCreatorDlg();
int getPieceSize() const;
signals:
void torrent_to_seed(QString path);
public slots:
void updateProgressBar(int progress);
void on_cancelButton_clicked();
@@ -71,8 +71,8 @@ private:
void loadSettings();
private:
TorrentCreatorThread *creatorThread;
QList<int> m_piece_sizes;
BitTorrent::TorrentCreatorThread *m_creatorThread;
QList<int> m_pieceSizes;
};
#endif

View File

@@ -35,22 +35,20 @@
#include "torrentimportdlg.h"
#include "ui_torrentimportdlg.h"
#include "core/preferences.h"
#include "qbtsession.h"
#include "core/torrentpersistentdata.h"
#include "iconprovider.h"
#include "core/bittorrent/infohash.h"
#include "core/bittorrent/session.h"
#include "guiiconprovider.h"
#include "core/fs_utils.h"
using namespace libtorrent;
TorrentImportDlg::TorrentImportDlg(QWidget *parent):
QDialog(parent),
ui(new Ui::TorrentImportDlg)
{
ui->setupUi(this);
// Icons
ui->lbl_info->setPixmap(IconProvider::instance()->getIcon("dialog-information").pixmap(ui->lbl_info->height()));
ui->lbl_info->setPixmap(GuiIconProvider::instance()->getIcon("dialog-information").pixmap(ui->lbl_info->height()));
ui->lbl_info->setFixedWidth(ui->lbl_info->height());
ui->importBtn->setIcon(IconProvider::instance()->getIcon("document-import"));
ui->importBtn->setIcon(GuiIconProvider::instance()->getIcon("document-import"));
// Libtorrent < 0.15 does not support skipping file checking
loadSettings();
}
@@ -74,13 +72,14 @@ void TorrentImportDlg::on_browseTorrentBtn_clicked()
void TorrentImportDlg::on_browseContentBtn_clicked()
{
const QString default_dir = Preferences::instance()->getTorImportLastContentDir();
bool multifile = t->num_files() > 1;
if (!multifile && (fsutils::fromNativePath(misc::toQStringU(t->file_at(0).path)).indexOf('/') != -1))
bool multifile = (m_torrentInfo.filesCount() > 1);
QString filePath = fsutils::fromNativePath(m_torrentInfo.filePath(0));
if (!multifile && (filePath.indexOf('/') != -1))
multifile = true;
if (!multifile) {
// Single file torrent
const QString file_name = fsutils::fileName(misc::toQStringU(t->file_at(0).path));
const QString file_name = fsutils::fileName(filePath);
qDebug("Torrent has only one file: %s", qPrintable(file_name));
QString extension = fsutils::fileExtension(file_name);
qDebug("File extension is : %s", qPrintable(extension));
@@ -100,7 +99,7 @@ void TorrentImportDlg::on_browseContentBtn_clicked()
ui->lineContent->setText(fsutils::toNativePath(m_contentPath));
// Check file size
const qint64 file_size = QFile(m_contentPath).size();
if (t->file_at(0).size == file_size) {
if (m_torrentInfo.fileSize(0) == file_size) {
qDebug("The file size matches, allowing fast seeding...");
ui->checkSkipCheck->setEnabled(true);
}
@@ -122,7 +121,7 @@ void TorrentImportDlg::on_browseContentBtn_clicked()
}
else {
// multiple files torrent
m_contentPath = QFileDialog::getExistingDirectory(this, tr("Please point to the location of the torrent: %1").arg(misc::toQStringU(t->name())),
m_contentPath = QFileDialog::getExistingDirectory(this, tr("Please point to the location of the torrent: %1").arg(m_torrentInfo.name()),
default_dir);
if (m_contentPath.isEmpty() || !QDir(m_contentPath).exists()) {
m_contentPath = QString::null;
@@ -136,13 +135,13 @@ void TorrentImportDlg::on_browseContentBtn_clicked()
QDir content_dir(m_contentPath);
content_dir.cdUp();
// Check file sizes
for (int i = 0; i<t->num_files(); ++i) {
const QString rel_path = misc::toQStringU(t->file_at(i).path);
if (QFile(fsutils::expandPath(content_dir.absoluteFilePath(rel_path))).size() != t->file_at(i).size) {
for (int i = 0; i < m_torrentInfo.filesCount(); ++i) {
const QString rel_path = m_torrentInfo.filePath(i);
if (QFile(fsutils::expandPath(content_dir.absoluteFilePath(rel_path))).size() != m_torrentInfo.fileSize(i)) {
qDebug("%s is %lld",
qPrintable(fsutils::expandPath(content_dir.absoluteFilePath(rel_path))), (long long int) QFile(fsutils::expandPath(content_dir.absoluteFilePath(rel_path))).size());
qDebug("%s is %lld",
qPrintable(rel_path), (long long int)t->file_at(i).size);
qPrintable(rel_path), (long long int)m_torrentInfo.fileSize(i));
size_mismatch = true;
break;
}
@@ -184,63 +183,57 @@ void TorrentImportDlg::importTorrent()
qDebug() << Q_FUNC_INFO << "ENTER";
TorrentImportDlg dlg;
if (dlg.exec()) {
BitTorrent::AddTorrentParams params;
qDebug() << "Loading the torrent file...";
boost::intrusive_ptr<libtorrent::torrent_info> t = dlg.torrent();
if (!t->is_valid())
return;
QString torrent_path = dlg.getTorrentPath();
QString content_path = dlg.getContentPath();
if (torrent_path.isEmpty() || content_path.isEmpty() || !QFile(torrent_path).exists()) {
qWarning() << "Incorrect input, aborting." << torrent_path << content_path;
BitTorrent::TorrentInfo torrentInfo = dlg.torrent();
if (!torrentInfo.isValid()) return;
QString torrentPath = dlg.getTorrentPath();
QString contentPath = dlg.getContentPath();
if (torrentPath.isEmpty() || contentPath.isEmpty() || !QFile(torrentPath).exists()) {
qWarning() << "Incorrect input, aborting." << torrentPath << contentPath;
return;
}
const QString hash = misc::toQString(t->info_hash());
const QString hash = torrentInfo.hash();
qDebug() << "Torrent hash is" << hash;
TorrentTempData::setSavePath(hash, content_path);
TorrentTempData::setSeedingMode(hash, dlg.skipFileChecking());
params.savePath = contentPath;
params.skipChecking = dlg.skipFileChecking();
params.disableTempPath = true;
qDebug("Adding the torrent to the session...");
QBtSession::instance()->addTorrent(torrent_path, false, QString(), false, true);
BitTorrent::Session::instance()->addTorrent(torrentInfo, params);
// Remember the last opened folder
Preferences* const pref = Preferences::instance();
pref->setMainLastDir(fsutils::fromNativePath(torrent_path));
pref->setTorImportLastContentDir(fsutils::fromNativePath(content_path));
pref->setMainLastDir(fsutils::fromNativePath(torrentPath));
pref->setTorImportLastContentDir(fsutils::fromNativePath(contentPath));
return;
}
qDebug() << Q_FUNC_INFO << "EXIT";
return;
}
void TorrentImportDlg::loadTorrent(const QString &torrent_path)
void TorrentImportDlg::loadTorrent(const QString &torrentPath)
{
// Load the torrent file
try {
std::vector<char> buffer;
lazy_entry entry;
libtorrent::error_code ec;
misc::loadBencodedFile(torrent_path, buffer, entry, ec);
t = new torrent_info(entry);
if (!t->is_valid() || t->num_files() == 0)
throw std::exception();
}
catch(std::exception&) {
m_torrentInfo = BitTorrent::TorrentInfo::loadFromFile(torrentPath);
if (!m_torrentInfo.isValid()) {
ui->browseContentBtn->setEnabled(false);
ui->lineTorrent->clear();
QMessageBox::warning(this, tr("Invalid torrent file"), tr("This is not a valid torrent file."));
return;
}
// Update display
ui->lineTorrent->setText(fsutils::toNativePath(torrent_path));
ui->browseContentBtn->setEnabled(true);
// Load the file names
initializeFilesPath();
else {
// Update display
ui->lineTorrent->setText(fsutils::toNativePath(torrentPath));
ui->browseContentBtn->setEnabled(true);
// Load the file names
initializeFilesPath();
}
}
void TorrentImportDlg::initializeFilesPath()
{
m_filesPath.clear();
// Loads files path in the torrent
for (int i = 0; i<t->num_files(); ++i)
m_filesPath << fsutils::fromNativePath(misc::toQStringU(t->file_at(i).path));
m_filesPath = m_torrentInfo.filePaths();
}
bool TorrentImportDlg::fileRenamed() const
@@ -249,9 +242,9 @@ bool TorrentImportDlg::fileRenamed() const
}
boost::intrusive_ptr<libtorrent::torrent_info> TorrentImportDlg::torrent() const
BitTorrent::TorrentInfo TorrentImportDlg::torrent() const
{
return t;
return m_torrentInfo;
}
bool TorrentImportDlg::skipFileChecking() const

View File

@@ -34,16 +34,12 @@
#include <QDialog>
#include <QStringList>
#include <libtorrent/torrent_info.hpp>
#include <libtorrent/version.hpp>
#include "core/bittorrent/torrentinfo.h"
QT_BEGIN_NAMESPACE
namespace Ui {
namespace Ui
{
class TorrentImportDlg;
}
QT_END_NAMESPACE
class QBtSession;
class TorrentImportDlg: public QDialog
{
@@ -52,22 +48,22 @@ class TorrentImportDlg: public QDialog
public:
explicit TorrentImportDlg(QWidget *parent = 0);
~TorrentImportDlg();
static void importTorrent();
QString getTorrentPath() const;
QString getContentPath() const;
bool fileRenamed() const;
boost::intrusive_ptr<libtorrent::torrent_info> torrent() const;
BitTorrent::TorrentInfo torrent() const;
bool skipFileChecking() const;
protected slots:
void loadTorrent(const QString &torrent_path);
void loadTorrent(const QString &torrentPath);
void initializeFilesPath();
private slots:
void on_browseTorrentBtn_clicked();
void on_browseContentBtn_clicked();
void on_importBtn_clicked();
protected:
@@ -79,7 +75,8 @@ private:
private:
Ui::TorrentImportDlg *ui;
boost::intrusive_ptr<libtorrent::torrent_info> t;
BitTorrent::TorrentInfo m_torrentInfo;
// NOTE: Where do we use it?
QStringList m_filesPath;
QString m_contentPath;
QString m_torrentPath;

View File

@@ -31,15 +31,12 @@
#include <QDebug>
#include <QApplication>
#include <QPalette>
#include <QIcon>
#include "torrentmodel.h"
#include "core/torrentpersistentdata.h"
#include "qbtsession.h"
#include "core/bittorrent/session.h"
#include "core/torrentfilter.h"
#include "core/fs_utils.h"
#include <libtorrent/session.hpp>
using namespace libtorrent;
#include "torrentmodel.h"
namespace {
QIcon get_paused_icon() {
@@ -96,110 +93,43 @@ bool isDarkTheme()
}
}
TorrentStatusReport::TorrentStatusReport()
: nb_downloading(0)
, nb_seeding(0)
, nb_completed(0)
, nb_active(0)
, nb_inactive(0)
, nb_paused(0)
TorrentModelItem::TorrentModelItem(BitTorrent::TorrentHandle *torrent)
: m_torrent(torrent)
{
}
TorrentModelItem::TorrentModelItem(const QTorrentHandle &h)
: m_torrent(h)
, m_lastStatus(h.status(torrent_handle::query_accurate_download_counters))
, m_addedTime(TorrentPersistentData::instance()->getAddedDate(h.hash()))
, m_label(TorrentPersistentData::instance()->getLabel(h.hash()))
, m_name(TorrentPersistentData::instance()->getName(h.hash()))
, m_hash(h.hash())
BitTorrent::TorrentState TorrentModelItem::state() const
{
if (m_name.isEmpty())
m_name = h.name();
// If name is empty show the hash. This happens when magnet isn't retrieved.
if (m_name.isEmpty())
m_name = h.hash();
return m_torrent->state();
}
void TorrentModelItem::refreshStatus(libtorrent::torrent_status const& status) {
m_lastStatus = status;
}
TorrentModelItem::State TorrentModelItem::state() const {
try {
// Pause or Queued
if (m_torrent.is_paused(m_lastStatus)) {
if (TorrentPersistentData::instance()->getHasMissingFiles(misc::toQString(m_lastStatus.info_hash)))
return STATE_PAUSED_MISSING;
else
return m_torrent.is_seed(m_lastStatus) ? STATE_PAUSED_UP : STATE_PAUSED_DL;
}
if (m_torrent.is_queued(m_lastStatus)
&& m_lastStatus.state != torrent_status::queued_for_checking
&& m_lastStatus.state != torrent_status::checking_resume_data
&& m_lastStatus.state != torrent_status::checking_files)
return m_torrent.is_seed(m_lastStatus) ? STATE_QUEUED_UP : STATE_QUEUED_DL;
// Other states
switch(m_lastStatus.state) {
case torrent_status::allocating:
return STATE_ALLOCATING;
case torrent_status::downloading_metadata:
return STATE_DOWNLOADING_META;
case torrent_status::downloading:
if (!m_torrent.is_forced(m_lastStatus))
return m_lastStatus.download_payload_rate > 0 ? STATE_DOWNLOADING : STATE_STALLED_DL;
else
return STATE_FORCED_DL;
case torrent_status::finished:
case torrent_status::seeding:
if (!m_torrent.is_forced(m_lastStatus))
return m_lastStatus.upload_payload_rate > 0 ? STATE_SEEDING : STATE_STALLED_UP;
else
return STATE_FORCED_UP;
case torrent_status::queued_for_checking:
return STATE_QUEUED_CHECK;
case torrent_status::checking_resume_data:
return STATE_QUEUED_FASTCHECK;
case torrent_status::checking_files:
return m_torrent.is_seed(m_lastStatus) ? STATE_CHECKING_UP : STATE_CHECKING_DL;
default:
return STATE_INVALID;
}
} catch(invalid_handle&) {
return STATE_INVALID;
}
}
QIcon TorrentModelItem::getIconByState(State state) {
QIcon TorrentModelItem::getIconByState(BitTorrent::TorrentState state)
{
switch (state) {
case STATE_DOWNLOADING:
case STATE_DOWNLOADING_META:
case STATE_FORCED_DL:
case BitTorrent::TorrentState::Downloading:
case BitTorrent::TorrentState::ForcedDownloading:
case BitTorrent::TorrentState::DownloadingMetadata:
return get_downloading_icon();
case STATE_ALLOCATING:
case STATE_STALLED_DL:
case BitTorrent::TorrentState::Allocating:
case BitTorrent::TorrentState::StalledDownloading:
return get_stalled_downloading_icon();
case STATE_STALLED_UP:
case BitTorrent::TorrentState::StalledUploading:
return get_stalled_uploading_icon();
case STATE_SEEDING:
case STATE_FORCED_UP:
case BitTorrent::TorrentState::Uploading:
case BitTorrent::TorrentState::ForcedUploading:
return get_uploading_icon();
case STATE_PAUSED_DL:
case BitTorrent::TorrentState::PausedDownloading:
return get_paused_icon();
case STATE_PAUSED_UP:
case BitTorrent::TorrentState::PausedUploading:
return get_completed_icon();
case STATE_QUEUED_DL:
case STATE_QUEUED_UP:
case BitTorrent::TorrentState::QueuedDownloading:
case BitTorrent::TorrentState::QueuedUploading:
return get_queued_icon();
case STATE_CHECKING_UP:
case STATE_CHECKING_DL:
case STATE_QUEUED_CHECK:
case STATE_QUEUED_FASTCHECK:
case BitTorrent::TorrentState::CheckingDownloading:
case BitTorrent::TorrentState::CheckingUploading:
return get_checking_icon();
case STATE_INVALID:
case STATE_PAUSED_MISSING:
case BitTorrent::TorrentState::Unknown:
case BitTorrent::TorrentState::Error:
return get_error_icon();
default:
Q_ASSERT(false);
@@ -207,43 +137,43 @@ QIcon TorrentModelItem::getIconByState(State state) {
}
}
QColor TorrentModelItem::getColorByState(State state) {
QColor TorrentModelItem::getColorByState(BitTorrent::TorrentState state)
{
bool dark = isDarkTheme();
switch (state) {
case STATE_DOWNLOADING:
case STATE_DOWNLOADING_META:
case STATE_FORCED_DL:
case BitTorrent::TorrentState::Downloading:
case BitTorrent::TorrentState::ForcedDownloading:
case BitTorrent::TorrentState::DownloadingMetadata:
return QColor(34, 139, 34); // Forest Green
case STATE_ALLOCATING:
case STATE_STALLED_DL:
case STATE_STALLED_UP:
case BitTorrent::TorrentState::Allocating:
case BitTorrent::TorrentState::StalledDownloading:
case BitTorrent::TorrentState::StalledUploading:
if (!dark)
return QColor(0, 0, 0); // Black
else
return QColor(255, 255, 255); // White
case STATE_SEEDING:
case STATE_FORCED_UP:
case BitTorrent::TorrentState::Uploading:
case BitTorrent::TorrentState::ForcedUploading:
if (!dark)
return QColor(65, 105, 225); // Royal Blue
else
return QColor(100, 149, 237); // Cornflower Blue
case STATE_PAUSED_DL:
case BitTorrent::TorrentState::PausedDownloading:
return QColor(250, 128, 114); // Salmon
case STATE_PAUSED_UP:
case BitTorrent::TorrentState::PausedUploading:
if (!dark)
return QColor(0, 0, 139); // Dark Blue
else
return QColor(65, 105, 225); // Royal Blue
case STATE_PAUSED_MISSING:
case BitTorrent::TorrentState::Error:
return QColor(255, 0, 0); // red
case STATE_QUEUED_DL:
case STATE_QUEUED_UP:
case STATE_CHECKING_UP:
case STATE_CHECKING_DL:
case STATE_QUEUED_CHECK:
case STATE_QUEUED_FASTCHECK:
case BitTorrent::TorrentState::QueuedDownloading:
case BitTorrent::TorrentState::QueuedUploading:
case BitTorrent::TorrentState::CheckingDownloading:
case BitTorrent::TorrentState::CheckingUploading:
return QColor(0, 128, 128); // Teal
case STATE_INVALID:
case BitTorrent::TorrentState::Unknown:
return QColor(255, 0, 0); // red
default:
Q_ASSERT(false);
@@ -255,18 +185,17 @@ bool TorrentModelItem::setData(int column, const QVariant &value, int role)
{
qDebug() << Q_FUNC_INFO << column << value;
if (role != Qt::DisplayRole) return false;
// Label, seed date and Name columns can be edited
switch(column) {
case TR_NAME:
m_name = value.toString();
TorrentPersistentData::instance()->saveName(m_torrent.hash(), m_name);
m_torrent->setName(value.toString());
return true;
case TR_LABEL: {
QString new_label = value.toString();
if (m_label != new_label) {
QString old_label = m_label;
m_label = new_label;
TorrentPersistentData::instance()->saveLabel(m_torrent.hash(), new_label);
if (m_torrent->label() != new_label) {
QString old_label = m_torrent->label();
m_torrent->setLabel(new_label);
emit labelChanged(old_label, new_label);
}
return true;
@@ -279,136 +208,118 @@ bool TorrentModelItem::setData(int column, const QVariant &value, int role)
QVariant TorrentModelItem::data(int column, int role) const
{
if (role == Qt::DecorationRole && column == TR_NAME) {
if ((role == Qt::DecorationRole) && (column == TR_NAME))
return getIconByState(state());
}
if (role == Qt::ForegroundRole) {
if (role == Qt::ForegroundRole)
return getColorByState(state());
}
if (role != Qt::DisplayRole && role != Qt::UserRole) return QVariant();
if ((role != Qt::DisplayRole) && (role != Qt::UserRole))
return QVariant();
switch(column) {
case TR_NAME:
return m_name.isEmpty() ? m_torrent.name() : m_name;
case TR_PRIORITY: {
int pos = m_torrent.queue_position(m_lastStatus);
if (pos > -1)
return pos - HiddenData::getSize();
else
return pos;
}
return m_torrent->name();
case TR_PRIORITY:
return m_torrent->queuePosition();
case TR_SIZE:
return m_lastStatus.has_metadata ? static_cast<qlonglong>(m_lastStatus.total_wanted) : -1;
return m_torrent->hasMetadata() ? m_torrent->wantedSize() : -1;
case TR_PROGRESS:
return m_torrent.progress(m_lastStatus);
return m_torrent->progress();
case TR_STATUS:
return state();
case TR_SEEDS: {
return (role == Qt::DisplayRole) ? m_lastStatus.num_seeds : m_lastStatus.num_complete;
}
case TR_PEERS: {
return (role == Qt::DisplayRole) ? (m_lastStatus.num_peers-m_lastStatus.num_seeds) : m_lastStatus.num_incomplete;
}
return static_cast<int>(m_torrent->state());
case TR_SEEDS:
return (role == Qt::DisplayRole) ? m_torrent->seedsCount() : m_torrent->completeCount();
case TR_PEERS:
return (role == Qt::DisplayRole) ? (m_torrent->peersCount() - m_torrent->seedsCount()) : m_torrent->incompleteCount();
case TR_DLSPEED:
return m_lastStatus.download_payload_rate;
return m_torrent->downloadPayloadRate();
case TR_UPSPEED:
return m_lastStatus.upload_payload_rate;
case TR_ETA: {
// XXX: Is this correct?
if (m_torrent.is_paused(m_lastStatus) || m_torrent.is_queued(m_lastStatus)) return MAX_ETA;
return QBtSession::instance()->getETA(m_hash, m_lastStatus);
}
return m_torrent->uploadPayloadRate();
case TR_ETA:
return m_torrent->eta();
case TR_RATIO:
return QBtSession::instance()->getRealRatio(m_lastStatus);
return m_torrent->realRatio();
case TR_LABEL:
return m_label;
return m_torrent->label();
case TR_ADD_DATE:
return m_addedTime;
return m_torrent->addedTime();
case TR_SEED_DATE:
return m_lastStatus.completed_time ? QDateTime::fromTime_t(m_lastStatus.completed_time) : QDateTime();
return m_torrent->completedTime();
case TR_TRACKER:
return misc::toQString(m_lastStatus.current_tracker);
return m_torrent->currentTracker();
case TR_DLLIMIT:
return m_torrent.download_limit();
return m_torrent->downloadLimit();
case TR_UPLIMIT:
return m_torrent.upload_limit();
return m_torrent->uploadLimit();
case TR_AMOUNT_DOWNLOADED:
return static_cast<qlonglong>(m_lastStatus.all_time_download);
return m_torrent->totalDownload();
case TR_AMOUNT_UPLOADED:
return static_cast<qlonglong>(m_lastStatus.all_time_upload);
return m_torrent->totalUpload();
case TR_AMOUNT_DOWNLOADED_SESSION:
return static_cast<qlonglong>(m_lastStatus.total_payload_download);
return m_torrent->totalPayloadDownload();
case TR_AMOUNT_UPLOADED_SESSION:
return static_cast<qlonglong>(m_lastStatus.total_payload_upload);
return m_torrent->totalPayloadUpload();
case TR_AMOUNT_LEFT:
return static_cast<qlonglong>(m_lastStatus.total_wanted - m_lastStatus.total_wanted_done);
return m_torrent->incompletedSize();
case TR_TIME_ELAPSED:
return (role == Qt::DisplayRole) ? m_lastStatus.active_time : m_lastStatus.seeding_time;
return (role == Qt::DisplayRole) ? m_torrent->activeTime() : m_torrent->seedingTime();
case TR_SAVE_PATH:
return fsutils::toNativePath(m_torrent.save_path_parsed());
return m_torrent->savePathParsed();
case TR_COMPLETED:
return static_cast<qlonglong>(m_lastStatus.total_wanted_done);
case TR_RATIO_LIMIT: {
QString hash = misc::toQString(m_lastStatus.info_hash);
return QBtSession::instance()->getMaxRatioPerTorrent(hash, NULL);
}
return m_torrent->completedSize();
case TR_RATIO_LIMIT:
return m_torrent->maxRatio();
case TR_SEEN_COMPLETE_DATE:
return m_lastStatus.last_seen_complete ? QDateTime::fromTime_t(m_lastStatus.last_seen_complete) : QDateTime();
return m_torrent->lastSeenComplete();
case TR_LAST_ACTIVITY:
if (m_torrent.is_paused(m_lastStatus) || m_torrent.is_checking(m_lastStatus))
if (m_torrent->isPaused() || m_torrent->isChecking())
return -1;
if (m_lastStatus.time_since_upload < m_lastStatus.time_since_download)
return m_lastStatus.time_since_upload;
if (m_torrent->timeSinceUpload() < m_torrent->timeSinceDownload())
return m_torrent->timeSinceUpload();
else
return m_lastStatus.time_since_download;
return m_torrent->timeSinceDownload();
case TR_TOTAL_SIZE:
return m_lastStatus.has_metadata ? static_cast<qlonglong>(m_torrent.total_size()) : -1;
return m_torrent->hasMetadata() ? m_torrent->totalSize() : -1;
default:
return QVariant();
}
}
QTorrentHandle TorrentModelItem::torrentHandle() const
BitTorrent::TorrentHandle *TorrentModelItem::torrentHandle() const
{
return m_torrent;
}
// TORRENT MODEL
TorrentModel::TorrentModel(QObject *parent) :
QAbstractListModel(parent), m_refreshInterval(2000)
TorrentModel::TorrentModel(QObject *parent)
: QAbstractListModel(parent)
{
}
void TorrentModel::populate() {
void TorrentModel::populate()
{
// Load the torrents
std::vector<torrent_handle> torrents = QBtSession::instance()->getSession()->get_torrents();
foreach (BitTorrent::TorrentHandle *const torrent, BitTorrent::Session::instance()->torrents())
addTorrent(torrent);
std::vector<torrent_handle>::const_iterator it = torrents.begin();
std::vector<torrent_handle>::const_iterator itend = torrents.end();
for ( ; it != itend; ++it) {
const QTorrentHandle h(*it);
if (HiddenData::hasData(h.hash()))
continue;
addTorrent(h);
}
// Refresh timer
connect(&m_refreshTimer, SIGNAL(timeout()), SLOT(forceModelRefresh()));
m_refreshTimer.start(m_refreshInterval);
// Listen for torrent changes
connect(QBtSession::instance(), SIGNAL(addedTorrent(QTorrentHandle)), SLOT(addTorrent(QTorrentHandle)));
connect(QBtSession::instance(), SIGNAL(torrentAboutToBeRemoved(QTorrentHandle)), SLOT(handleTorrentAboutToBeRemoved(QTorrentHandle)));
connect(QBtSession::instance(), SIGNAL(finishedTorrent(QTorrentHandle)), SLOT(handleFinishedTorrent(QTorrentHandle)));
connect(QBtSession::instance(), SIGNAL(metadataReceived(QTorrentHandle)), SLOT(handleTorrentUpdate(QTorrentHandle)));
connect(QBtSession::instance(), SIGNAL(resumedTorrent(QTorrentHandle)), SLOT(handleTorrentUpdate(QTorrentHandle)));
connect(QBtSession::instance(), SIGNAL(pausedTorrent(QTorrentHandle)), SLOT(handleTorrentUpdate(QTorrentHandle)));
connect(QBtSession::instance(), SIGNAL(torrentFinishedChecking(QTorrentHandle)), SLOT(handleTorrentUpdate(QTorrentHandle)));
connect(QBtSession::instance(), SIGNAL(stateUpdate(std::vector<libtorrent::torrent_status>)), SLOT(stateUpdated(std::vector<libtorrent::torrent_status>)));
connect(BitTorrent::Session::instance(), SIGNAL(torrentAdded(BitTorrent::TorrentHandle *const)), SLOT(addTorrent(BitTorrent::TorrentHandle *const)));
connect(BitTorrent::Session::instance(), SIGNAL(torrentAboutToBeRemoved(BitTorrent::TorrentHandle *const)), SLOT(handleTorrentAboutToBeRemoved(BitTorrent::TorrentHandle *const)));
connect(BitTorrent::Session::instance(), SIGNAL(torrentStatusUpdated(BitTorrent::TorrentHandle *const)), this, SLOT(handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const)));
connect(BitTorrent::Session::instance(), SIGNAL(torrentFinished(BitTorrent::TorrentHandle *const)), SLOT(handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const)));
connect(BitTorrent::Session::instance(), SIGNAL(torrentMetadataLoaded(BitTorrent::TorrentHandle *const)), SLOT(handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const)));
connect(BitTorrent::Session::instance(), SIGNAL(torrentResumed(BitTorrent::TorrentHandle *const)), SLOT(handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const)));
connect(BitTorrent::Session::instance(), SIGNAL(torrentPaused(BitTorrent::TorrentHandle *const)), SLOT(handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const)));
connect(BitTorrent::Session::instance(), SIGNAL(torrentFinishedChecking(BitTorrent::TorrentHandle *const)), SLOT(handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const)));
}
TorrentModel::~TorrentModel() {
qDebug() << Q_FUNC_INFO << "ENTER";
qDeleteAll(m_torrents);
m_torrents.clear();
qDeleteAll(m_items);
m_items.clear();
qDebug() << Q_FUNC_INFO << "EXIT";
}
@@ -485,49 +396,47 @@ QVariant TorrentModel::headerData(int section, Qt::Orientation orientation,
QVariant TorrentModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) return QVariant();
try {
if (index.row() >= 0 && index.row() < rowCount() && index.column() >= 0 && index.column() < columnCount())
return m_torrents[index.row()]->data(index.column(), role);
} catch(invalid_handle&) {}
if (index.row() >= 0 && index.row() < rowCount() && index.column() >= 0 && index.column() < columnCount())
return m_items[index.row()]->data(index.column(), role);
return QVariant();
}
bool TorrentModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
qDebug() << Q_FUNC_INFO << value;
if (!index.isValid() || role != Qt::DisplayRole) return false;
if (!index.isValid() || (role != Qt::DisplayRole)) return false;
qDebug("Index is valid and role is DisplayRole");
try {
if (index.row() >= 0 && index.row() < rowCount() && index.column() >= 0 && index.column() < columnCount()) {
bool change = m_torrents[index.row()]->setData(index.column(), value, role);
if (change)
notifyTorrentChanged(index.row());
return change;
}
} catch(invalid_handle&) {}
if ((index.row() >= 0) && (index.row() < rowCount()) && (index.column() >= 0) && (index.column() < columnCount())) {
bool change = m_items[index.row()]->setData(index.column(), value, role);
if (change)
notifyTorrentChanged(index.row());
return change;
}
return false;
}
int TorrentModel::torrentRow(const QString &hash) const
int TorrentModel::torrentRow(const BitTorrent::InfoHash &hash) const
{
int row = 0;
QList<TorrentModelItem*>::const_iterator it = m_torrents.constBegin();
QList<TorrentModelItem*>::const_iterator itend = m_torrents.constEnd();
for ( ; it != itend; ++it) {
if ((*it)->hash() == hash) return row;
foreach (TorrentModelItem *const item, m_items) {
if (item->hash() == hash) return row;
++row;
}
return -1;
}
void TorrentModel::addTorrent(const QTorrentHandle &h)
void TorrentModel::addTorrent(BitTorrent::TorrentHandle *const torrent)
{
if (torrentRow(h.hash()) < 0) {
beginInsertTorrent(m_torrents.size());
TorrentModelItem *item = new TorrentModelItem(h);
connect(item, SIGNAL(labelChanged(QString,QString)), SLOT(handleTorrentLabelChange(QString,QString)));
m_torrents << item;
if (torrentRow(torrent->hash()) < 0) {
beginInsertTorrent(m_items.size());
TorrentModelItem *item = new TorrentModelItem(torrent);
connect(item, SIGNAL(labelChanged(QString, QString)), SLOT(handleTorrentLabelChange(QString, QString)));
m_items << item;
emit torrentAdded(item);
endInsertTorrent();
}
@@ -553,95 +462,9 @@ void TorrentModel::endRemoveTorrent()
endRemoveRows();
}
void TorrentModel::handleTorrentUpdate(const QTorrentHandle &h)
{
const int row = torrentRow(h.hash());
if (row >= 0) {
// This line changes the torrent name when magnet is retrieved.
// When magnet link is added, "dn" parameter is used as name, but when metadata is retrieved
// we change the name with the retrieved torrent name.
m_torrents[row]->setData(TorrentModelItem::TR_NAME, h.name(), Qt::DisplayRole);
m_torrents[row]->refreshStatus(h.status(torrent_handle::query_accurate_download_counters));
notifyTorrentChanged(row);
}
}
void TorrentModel::handleFinishedTorrent(const QTorrentHandle& h)
{
const int row = torrentRow(h.hash());
if (row < 0)
return;
// Update completion date
m_torrents[row]->refreshStatus(h.status(torrent_handle::query_accurate_download_counters));
notifyTorrentChanged(row);
}
void TorrentModel::notifyTorrentChanged(int row)
{
emit dataChanged(index(row, 0), index(row, columnCount()-1));
}
void TorrentModel::setRefreshInterval(int refreshInterval)
{
if (m_refreshInterval != refreshInterval) {
m_refreshInterval = refreshInterval;
m_refreshTimer.stop();
m_refreshTimer.start(m_refreshInterval);
}
}
void TorrentModel::forceModelRefresh()
{
QBtSession::instance()->postTorrentUpdate();
}
TorrentStatusReport TorrentModel::getTorrentStatusReport() const
{
TorrentStatusReport report;
QList<TorrentModelItem*>::const_iterator it = m_torrents.constBegin();
QList<TorrentModelItem*>::const_iterator itend = m_torrents.constEnd();
for ( ; it != itend; ++it) {
switch((*it)->state()) {
case TorrentModelItem::STATE_DOWNLOADING:
case TorrentModelItem::STATE_FORCED_DL:
++report.nb_active;
++report.nb_downloading;
break;
case TorrentModelItem::STATE_DOWNLOADING_META:
++report.nb_downloading;
break;
case TorrentModelItem::STATE_PAUSED_DL:
case TorrentModelItem::STATE_PAUSED_MISSING:
++report.nb_paused;
case TorrentModelItem::STATE_STALLED_DL:
case TorrentModelItem::STATE_CHECKING_DL:
case TorrentModelItem::STATE_QUEUED_DL: {
++report.nb_inactive;
++report.nb_downloading;
break;
}
case TorrentModelItem::STATE_SEEDING:
case TorrentModelItem::STATE_FORCED_UP:
++report.nb_active;
++report.nb_seeding;
++report.nb_completed;
break;
case TorrentModelItem::STATE_STALLED_UP:
case TorrentModelItem::STATE_CHECKING_UP:
case TorrentModelItem::STATE_QUEUED_UP:
++report.nb_seeding;
case TorrentModelItem::STATE_PAUSED_UP:
++report.nb_completed;
++report.nb_inactive;
break;
default:
break;
}
}
return report;
emit dataChanged(index(row, 0), index(row, columnCount() - 1));
}
Qt::ItemFlags TorrentModel::flags(const QModelIndex &index) const
@@ -660,57 +483,34 @@ void TorrentModel::handleTorrentLabelChange(QString previous, QString current)
QString TorrentModel::torrentHash(int row) const
{
if (row >= 0 && row < rowCount())
return m_torrents.at(row)->hash();
return m_items.at(row)->hash();
return QString();
}
void TorrentModel::handleTorrentAboutToBeRemoved(const QTorrentHandle &h)
BitTorrent::TorrentHandle *TorrentModel::torrentHandle(const QModelIndex &index) const
{
const int row = torrentRow(h.hash());
if (index.isValid() && (index.row() >= 0) && (index.row() < rowCount()))
return m_items[index.row()]->torrentHandle();
return 0;
}
void TorrentModel::handleTorrentAboutToBeRemoved(BitTorrent::TorrentHandle *const torrent)
{
const int row = torrentRow(torrent->hash());
qDebug() << Q_FUNC_INFO << row;
if (row >= 0) {
emit torrentAboutToBeRemoved(m_torrents.at(row));
emit torrentAboutToBeRemoved(m_items.at(row));
beginRemoveTorrent(row);
delete m_torrents[row];
m_torrents.removeAt(row);
delete m_items.takeAt(row);
endRemoveTorrent();
}
}
void TorrentModel::stateUpdated(const std::vector<libtorrent::torrent_status> &statuses) {
typedef std::vector<libtorrent::torrent_status> statuses_t;
for (statuses_t::const_iterator i = statuses.begin(), end = statuses.end(); i != end; ++i) {
libtorrent::torrent_status const& status = *i;
const int row = torrentRow(misc::toQString(status.info_hash));
if (row >= 0) {
m_torrents[row]->refreshStatus(status);
notifyTorrentChanged(row);
}
}
emit modelRefreshed();
}
bool TorrentModel::inhibitSystem()
void TorrentModel::handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const torrent)
{
QList<TorrentModelItem*>::const_iterator it = m_torrents.constBegin();
QList<TorrentModelItem*>::const_iterator itend = m_torrents.constEnd();
for ( ; it != itend; ++it) {
switch((*it)->data(TorrentModelItem::TR_STATUS).toInt()) {
case TorrentModelItem::STATE_DOWNLOADING:
case TorrentModelItem::STATE_DOWNLOADING_META:
case TorrentModelItem::STATE_FORCED_DL:
case TorrentModelItem::STATE_STALLED_DL:
case TorrentModelItem::STATE_SEEDING:
case TorrentModelItem::STATE_FORCED_UP:
case TorrentModelItem::STATE_STALLED_UP:
return true;
default:
break;
}
}
return false;
const int row = torrentRow(torrent->hash());
if (row >= 0)
notifyTorrentChanged(row);
}

View File

@@ -33,53 +33,35 @@
#include <QAbstractListModel>
#include <QList>
#include <QDateTime>
#include <QIcon>
#include <QTimer>
#include "qtorrenthandle.h"
#include "core/bittorrent/torrenthandle.h"
struct TorrentStatusReport {
TorrentStatusReport();
uint nb_downloading;
uint nb_seeding;
uint nb_completed;
uint nb_active;
uint nb_inactive;
uint nb_paused;
};
class QIcon;
class TorrentModelItem : public QObject {
Q_OBJECT
public:
enum State {STATE_DOWNLOADING, STATE_DOWNLOADING_META, STATE_ALLOCATING, STATE_STALLED_DL, STATE_SEEDING, STATE_STALLED_UP, STATE_QUEUED_DL, STATE_QUEUED_UP, STATE_CHECKING_UP, STATE_CHECKING_DL, STATE_QUEUED_CHECK, STATE_QUEUED_FASTCHECK, STATE_PAUSED_DL, STATE_PAUSED_UP, STATE_PAUSED_MISSING, STATE_FORCED_DL, STATE_FORCED_UP, STATE_INVALID};
enum Column {TR_NAME, TR_PRIORITY, TR_SIZE, TR_TOTAL_SIZE, TR_PROGRESS, TR_STATUS, TR_SEEDS, TR_PEERS, TR_DLSPEED, TR_UPSPEED, TR_ETA, TR_RATIO, TR_LABEL, TR_ADD_DATE, TR_SEED_DATE, TR_TRACKER, TR_DLLIMIT, TR_UPLIMIT, TR_AMOUNT_DOWNLOADED, TR_AMOUNT_UPLOADED, TR_AMOUNT_LEFT, TR_TIME_ELAPSED, TR_SAVE_PATH, TR_COMPLETED, TR_RATIO_LIMIT, TR_SEEN_COMPLETE_DATE, TR_LAST_ACTIVITY, TR_AMOUNT_DOWNLOADED_SESSION, TR_AMOUNT_UPLOADED_SESSION, NB_COLUMNS};
public:
TorrentModelItem(const QTorrentHandle& h);
void refreshStatus(libtorrent::torrent_status const& status);
TorrentModelItem(BitTorrent::TorrentHandle *torrent);
inline int columnCount() const { return NB_COLUMNS; }
QVariant data(int column, int role = Qt::DisplayRole) const;
bool setData(int column, const QVariant &value, int role = Qt::DisplayRole);
inline QString const& hash() const { return m_hash; }
State state() const;
QTorrentHandle torrentHandle() const;
inline BitTorrent::InfoHash hash() const { return m_torrent->hash(); }
BitTorrent::TorrentState state() const;
BitTorrent::TorrentHandle *torrentHandle() const;
signals:
void labelChanged(QString previous, QString current);
private:
static QIcon getIconByState(State state);
static QColor getColorByState(State state);
static QIcon getIconByState(BitTorrent::TorrentState state);
static QColor getColorByState(BitTorrent::TorrentState state);
private:
QTorrentHandle m_torrent;
libtorrent::torrent_status m_lastStatus;
QDateTime m_addedTime;
QString m_label;
QString m_name;
QString m_hash; // Cached for safety reasons
BitTorrent::TorrentHandle *m_torrent;
};
class TorrentModel : public QAbstractListModel
@@ -90,34 +72,28 @@ class TorrentModel : public QAbstractListModel
public:
explicit TorrentModel(QObject *parent = 0);
~TorrentModel();
inline int rowCount(const QModelIndex& index = QModelIndex()) const { Q_UNUSED(index); return m_torrents.size(); }
inline int rowCount(const QModelIndex& index = QModelIndex()) const { Q_UNUSED(index); return m_items.size(); }
int columnCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return TorrentModelItem::NB_COLUMNS; }
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::DisplayRole);
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
int torrentRow(const QString &hash) const;
int torrentRow(const BitTorrent::InfoHash &hash) const;
QString torrentHash(int row) const;
void setRefreshInterval(int refreshInterval);
TorrentStatusReport getTorrentStatusReport() const;
BitTorrent::TorrentHandle *torrentHandle(const QModelIndex &index) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
void populate();
bool inhibitSystem();
signals:
void torrentAdded(TorrentModelItem *torrentItem);
void torrentAboutToBeRemoved(TorrentModelItem *torrentItem);
void torrentChangedLabel(TorrentModelItem *torrentItem, QString previous, QString current);
void modelRefreshed();
private slots:
void addTorrent(const QTorrentHandle& h);
void handleTorrentUpdate(const QTorrentHandle &h);
void handleFinishedTorrent(const QTorrentHandle& h);
void addTorrent(BitTorrent::TorrentHandle *const torrent);
void notifyTorrentChanged(int row);
void forceModelRefresh();
void handleTorrentLabelChange(QString previous, QString current);
void handleTorrentAboutToBeRemoved(const QTorrentHandle & h);
void stateUpdated(const std::vector<libtorrent::torrent_status> &statuses);
void handleTorrentAboutToBeRemoved(BitTorrent::TorrentHandle *const torrent);
void handleTorrentStatusUpdated(BitTorrent::TorrentHandle *const torrent);
private:
void beginInsertTorrent(int row);
@@ -126,9 +102,7 @@ private:
void endRemoveTorrent();
private:
QList<TorrentModelItem*> m_torrents;
int m_refreshInterval;
QTimer m_refreshTimer;
QList<TorrentModelItem*> m_items;
};
#endif // TORRENTMODEL_H

View File

@@ -28,17 +28,18 @@
* Contact : chris@qbittorrent.org
*/
#include "core/bittorrent/torrenthandle.h"
#include "trackerlogin.h"
trackerLogin::trackerLogin(QWidget *parent, QTorrentHandle h)
trackerLogin::trackerLogin(QWidget *parent, BitTorrent::TorrentHandle *const torrent)
: QDialog(parent)
, h(h)
, m_torrent(torrent)
{
setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
login_logo->setPixmap(QPixmap(QString::fromUtf8(":/icons/oxygen/encrypted.png")));
tracker_url->setText(h.current_tracker());
connect(this, SIGNAL(trackerLoginCancelled(QPair<QTorrentHandle,QString>)), parent, SLOT(addUnauthenticatedTracker(QPair<QTorrentHandle,QString>)));
tracker_url->setText(torrent->currentTracker());
connect(this, SIGNAL(trackerLoginCancelled(QPair<BitTorrent::TorrentHandle *const, QString>)), parent, SLOT(addUnauthenticatedTracker(QPair<BitTorrent::TorrentHandle *const, QString>)));
show();
}
@@ -46,12 +47,12 @@ trackerLogin::~trackerLogin() {}
void trackerLogin::on_loginButton_clicked() {
// login
h.set_tracker_login(lineUsername->text(), linePasswd->text());
m_torrent->setTrackerLogin(lineUsername->text(), linePasswd->text());
close();
}
void trackerLogin::on_cancelButton_clicked() {
// Emit a signal to GUI to stop asking for authentication
emit trackerLoginCancelled(QPair<QTorrentHandle,QString>(h, h.current_tracker()));
emit trackerLoginCancelled(QPair<BitTorrent::TorrentHandle *const, QString>(m_torrent, m_torrent->currentTracker()));
close();
}

View File

@@ -34,20 +34,24 @@
#include <QDialog>
#include "ui_login.h"
#include "qtorrenthandle.h"
namespace BitTorrent
{
class TorrentHandle;
}
class trackerLogin : public QDialog, private Ui::authentication{
Q_OBJECT
private:
QTorrentHandle h;
BitTorrent::TorrentHandle *const m_torrent;
public:
trackerLogin(QWidget *parent, QTorrentHandle h);
trackerLogin(QWidget *parent, BitTorrent::TorrentHandle *const torrent);
~trackerLogin();
signals:
void trackerLoginCancelled(QPair<QTorrentHandle,QString> tracker);
void trackerLoginCancelled(QPair<BitTorrent::TorrentHandle *const, QString> tracker);
public slots:
void on_loginButton_clicked();

View File

@@ -36,7 +36,8 @@
#include <QPainter>
#include "core/misc.h"
#include "torrentmodel.h"
#include "qbtsession.h"
#include "core/bittorrent/session.h"
#include "core/bittorrent/torrenthandle.h"
#ifdef Q_OS_WIN
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
@@ -90,49 +91,43 @@ void TransferListDelegate::paint(QPainter * painter, const QStyleOptionViewItem
const int state = index.data().toInt();
QString display;
switch(state) {
case TorrentModelItem::STATE_DOWNLOADING:
case BitTorrent::TorrentState::Downloading:
display = tr("Downloading");
break;
case TorrentModelItem::STATE_DOWNLOADING_META:
display = tr("Downloading metadata", "used when loading a magnet link");
break;
case TorrentModelItem::STATE_FORCED_DL:
display = tr("[F] Downloading", "used when the torrent is forced started. You probably shouldn't translate the F.");
break;
case TorrentModelItem::STATE_ALLOCATING:
display = tr("Allocating", "qBittorrent is allocating the files on disk");
break;
case TorrentModelItem::STATE_STALLED_DL:
case BitTorrent::TorrentState::StalledDownloading:
display = tr("Stalled", "Torrent is waiting for download to begin");
break;
case TorrentModelItem::STATE_SEEDING:
case TorrentModelItem::STATE_STALLED_UP:
case BitTorrent::TorrentState::DownloadingMetadata:
display = tr("Downloading metadata", "used when loading a magnet link");
break;
case BitTorrent::TorrentState::ForcedDownloading:
display = tr("[F] Downloading", "used when the torrent is forced started. You probably shouldn't translate the F.");
break;
case BitTorrent::TorrentState::Allocating:
display = tr("Allocating", "qBittorrent is allocating the files on disk");
break;
case BitTorrent::TorrentState::Uploading:
case BitTorrent::TorrentState::StalledUploading:
display = tr("Seeding", "Torrent is complete and in upload-only mode");
break;
case TorrentModelItem::STATE_FORCED_UP:
case BitTorrent::TorrentState::ForcedUploading:
display = tr("[F] Seeding", "used when the torrent is forced started. You probably shouldn't translate the F.");
break;
case TorrentModelItem::STATE_QUEUED_DL:
case TorrentModelItem::STATE_QUEUED_UP:
case BitTorrent::TorrentState::QueuedDownloading:
case BitTorrent::TorrentState::QueuedUploading:
display = tr("Queued", "i.e. torrent is queued");
break;
case TorrentModelItem::STATE_CHECKING_DL:
case TorrentModelItem::STATE_CHECKING_UP:
case BitTorrent::TorrentState::CheckingDownloading:
case BitTorrent::TorrentState::CheckingUploading:
display = tr("Checking", "Torrent local data is being checked");
break;
case TorrentModelItem::STATE_QUEUED_CHECK:
display = tr("Queued for checking", "i.e. torrent is queued for hash checking");
break;
case TorrentModelItem::STATE_QUEUED_FASTCHECK:
display = tr("Checking resume data", "used when loading the torrents from disk after qbt is launched. It checks the correctness of the .fastresume file. Normally it is completed in a fraction of a second, unless loading many many torrents.");
break;
case TorrentModelItem::STATE_PAUSED_DL:
case BitTorrent::TorrentState::PausedDownloading:
display = tr("Paused");
break;
case TorrentModelItem::STATE_PAUSED_UP:
case BitTorrent::TorrentState::PausedUploading:
display = tr("Completed");
break;
case TorrentModelItem::STATE_PAUSED_MISSING:
case BitTorrent::TorrentState::Error:
display = tr("Missing Files");
break;
default:
@@ -178,13 +173,13 @@ void TransferListDelegate::paint(QPainter * painter, const QStyleOptionViewItem
opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter;
const qreal ratio = index.data().toDouble();
QItemDelegate::drawDisplay(painter, opt, opt.rect,
(ratio == -1 || ratio > QBtSession::MAX_RATIO) ? QString::fromUtf8("") : misc::accurateDoubleToString(ratio, 2));
((ratio == -1) || (ratio > BitTorrent::TorrentHandle::MAX_RATIO)) ? QString::fromUtf8("") : misc::accurateDoubleToString(ratio, 2));
break;
}
case TorrentModelItem::TR_PRIORITY: {
const int priority = index.data().toInt();
opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter;
if (priority >= 0)
if (priority > 0)
QItemDelegate::paint(painter, opt, index);
else {
QItemDelegate::drawBackground(painter, opt, index);

View File

@@ -43,12 +43,15 @@
#include "transferlistwidget.h"
#include "core/preferences.h"
#include "torrentmodel.h"
#include "iconprovider.h"
#include "guiiconprovider.h"
#include "core/fs_utils.h"
#include "autoexpandabledialog.h"
#include "torrentfilterenum.h"
#include "core/torrentfilter.h"
#include "core/bittorrent/trackerentry.h"
#include "core/bittorrent/session.h"
#include "core/net/downloadmanager.h"
#include "core/net/downloadhandler.h"
#include "core/misc.h"
#include "core/downloadthread.h"
#include "core/logger.h"
FiltersBase::FiltersBase(QWidget *parent, TransferListWidget *transferList)
@@ -104,7 +107,7 @@ StatusFiltersWidget::StatusFiltersWidget(QWidget *parent, TransferListWidget *tr
// Height is fixed (sizeHint().height() is used)
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
setSpacing(0);
connect(transferList->getSourceModel(), SIGNAL(modelRefreshed()), SLOT(updateTorrentNumbers()));
connect(BitTorrent::Session::instance(), SIGNAL(torrentsUpdated(const BitTorrent::TorrentStatusReport &)), SLOT(updateTorrentNumbers(const BitTorrent::TorrentStatusReport &)));
// Add status filters
QListWidgetItem *all = new QListWidgetItem(this);
@@ -142,17 +145,16 @@ StatusFiltersWidget::~StatusFiltersWidget()
Preferences::instance()->setTransSelFilter(currentRow());
}
void StatusFiltersWidget::updateTorrentNumbers()
void StatusFiltersWidget::updateTorrentNumbers(const BitTorrent::TorrentStatusReport &report)
{
const TorrentStatusReport report = transferList->getSourceModel()->getTorrentStatusReport();
item(TorrentFilter::ALL)->setData(Qt::DisplayRole, QVariant(tr("All (%1)").arg(report.nb_active + report.nb_inactive)));
item(TorrentFilter::DOWNLOADING)->setData(Qt::DisplayRole, QVariant(tr("Downloading (%1)").arg(report.nb_downloading)));
item(TorrentFilter::SEEDING)->setData(Qt::DisplayRole, QVariant(tr("Seeding (%1)").arg(report.nb_seeding)));
item(TorrentFilter::COMPLETED)->setData(Qt::DisplayRole, QVariant(tr("Completed (%1)").arg(report.nb_completed)));
item(TorrentFilter::PAUSED)->setData(Qt::DisplayRole, QVariant(tr("Paused (%1)").arg(report.nb_paused)));
item(TorrentFilter::RESUMED)->setData(Qt::DisplayRole, QVariant(tr("Resumed (%1)").arg(report.nb_downloading + report.nb_seeding - report.nb_paused)));
item(TorrentFilter::ACTIVE)->setData(Qt::DisplayRole, QVariant(tr("Active (%1)").arg(report.nb_active)));
item(TorrentFilter::INACTIVE)->setData(Qt::DisplayRole, QVariant(tr("Inactive (%1)").arg(report.nb_inactive)));
item(TorrentFilter::All)->setData(Qt::DisplayRole, QVariant(tr("All (%1)").arg(report.nbActive + report.nbInactive)));
item(TorrentFilter::Downloading)->setData(Qt::DisplayRole, QVariant(tr("Downloading (%1)").arg(report.nbDownloading)));
item(TorrentFilter::Seeding)->setData(Qt::DisplayRole, QVariant(tr("Seeding (%1)").arg(report.nbSeeding)));
item(TorrentFilter::Completed)->setData(Qt::DisplayRole, QVariant(tr("Completed (%1)").arg(report.nbCompleted)));
item(TorrentFilter::Paused)->setData(Qt::DisplayRole, QVariant(tr("Paused (%1)").arg(report.nbPaused)));
item(TorrentFilter::Resumed)->setData(Qt::DisplayRole, QVariant(tr("Resumed (%1)").arg(report.nbResumed)));
item(TorrentFilter::Active)->setData(Qt::DisplayRole, QVariant(tr("Active (%1)").arg(report.nbActive)));
item(TorrentFilter::Inactive)->setData(Qt::DisplayRole, QVariant(tr("Inactive (%1)").arg(report.nbInactive)));
}
void StatusFiltersWidget::showMenu(QPoint) {}
@@ -177,10 +179,10 @@ LabelFiltersList::LabelFiltersList(QWidget *parent, TransferListWidget *transfer
// Add Label filters
QListWidgetItem *allLabels = new QListWidgetItem(this);
allLabels->setData(Qt::DisplayRole, QVariant(tr("All (0)", "this is for the label filter")));
allLabels->setData(Qt::DecorationRole, IconProvider::instance()->getIcon("inode-directory"));
allLabels->setData(Qt::DecorationRole, GuiIconProvider::instance()->getIcon("inode-directory"));
QListWidgetItem *noLabel = new QListWidgetItem(this);
noLabel->setData(Qt::DisplayRole, QVariant(tr("Unlabeled (0)")));
noLabel->setData(Qt::DecorationRole, IconProvider::instance()->getIcon("inode-directory"));
noLabel->setData(Qt::DecorationRole, GuiIconProvider::instance()->getIcon("inode-directory"));
const Preferences* const pref = Preferences::instance();
QStringList labelList = pref->getTorrentLabels();
@@ -215,7 +217,7 @@ void LabelFiltersList::addItem(QString &label, bool hasTorrent)
}
else {
labelItem = new QListWidgetItem();
labelItem->setData(Qt::DecorationRole, IconProvider::instance()->getIcon("inode-directory"));
labelItem->setData(Qt::DecorationRole, GuiIconProvider::instance()->getIcon("inode-directory"));
}
if (hasTorrent) {
@@ -269,9 +271,12 @@ void LabelFiltersList::removeItem(const QString &label)
void LabelFiltersList::removeSelectedLabel()
{
const int labelRow = row(selectedItems().first());
if (labelRow < 2)
return;
QList<QListWidgetItem*> items = selectedItems();
if (items.size() == 0) return;
const int labelRow = row(items.first());
if (labelRow < 2) return;
const QString &label = labelFromRow(labelRow);
Q_ASSERT(m_labels.contains(label));
m_labels.remove(label);
@@ -314,16 +319,16 @@ void LabelFiltersList::torrentChangedLabel(TorrentModelItem *torrentItem, QStrin
void LabelFiltersList::showMenu(QPoint)
{
QMenu menu(this);
QAction *addAct = menu.addAction(IconProvider::instance()->getIcon("list-add"), tr("Add label..."));
QAction *addAct = menu.addAction(GuiIconProvider::instance()->getIcon("list-add"), tr("Add label..."));
QAction *removeAct = 0;
QAction *removeUnusedAct = 0;
if (!selectedItems().empty() && row(selectedItems().first()) > 1)
removeAct = menu.addAction(IconProvider::instance()->getIcon("list-remove"), tr("Remove label"));
removeUnusedAct = menu.addAction(IconProvider::instance()->getIcon("list-remove"), tr("Remove unused labels"));
removeAct = menu.addAction(GuiIconProvider::instance()->getIcon("list-remove"), tr("Remove label"));
removeUnusedAct = menu.addAction(GuiIconProvider::instance()->getIcon("list-remove"), tr("Remove unused labels"));
menu.addSeparator();
QAction *startAct = menu.addAction(IconProvider::instance()->getIcon("media-playback-start"), tr("Resume torrents"));
QAction *pauseAct = menu.addAction(IconProvider::instance()->getIcon("media-playback-pause"), tr("Pause torrents"));
QAction *deleteTorrentsAct = menu.addAction(IconProvider::instance()->getIcon("edit-delete"), tr("Delete torrents"));
QAction *startAct = menu.addAction(GuiIconProvider::instance()->getIcon("media-playback-start"), tr("Resume torrents"));
QAction *pauseAct = menu.addAction(GuiIconProvider::instance()->getIcon("media-playback-pause"), tr("Pause torrents"));
QAction *deleteTorrentsAct = menu.addAction(GuiIconProvider::instance()->getIcon("edit-delete"), tr("Delete torrents"));
QAction *act = 0;
act = menu.exec(QCursor::pos());
if (!act)
@@ -415,17 +420,16 @@ int LabelFiltersList::rowFromLabel(const QString &label) const
TrackerFiltersList::TrackerFiltersList(QWidget *parent, TransferListWidget *transferList)
: FiltersBase(parent, transferList)
, m_downloader(new DownloadThread(this))
, m_totalTorrents(0)
{
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
QListWidgetItem *allTrackers = new QListWidgetItem(this);
allTrackers->setData(Qt::DisplayRole, QVariant(tr("All (0)", "this is for the label filter")));
allTrackers->setData(Qt::DecorationRole, IconProvider::instance()->getIcon("network-server"));
allTrackers->setData(Qt::DecorationRole, GuiIconProvider::instance()->getIcon("network-server"));
QListWidgetItem *noTracker = new QListWidgetItem(this);
noTracker->setData(Qt::DisplayRole, QVariant(tr("Trackerless (0)")));
noTracker->setData(Qt::DecorationRole, IconProvider::instance()->getIcon("network-server"));
noTracker->setData(Qt::DecorationRole, GuiIconProvider::instance()->getIcon("network-server"));
QListWidgetItem *errorTracker = new QListWidgetItem(this);
errorTracker->setData(Qt::DisplayRole, QVariant(tr("Error (0)")));
errorTracker->setData(Qt::DecorationRole, style()->standardIcon(QStyle::SP_MessageBoxCritical));
@@ -435,14 +439,11 @@ TrackerFiltersList::TrackerFiltersList(QWidget *parent, TransferListWidget *tran
m_trackers.insert("", QStringList());
setCurrentRow(0, QItemSelectionModel::SelectCurrent);
connect(m_downloader, SIGNAL(downloadFinished(QString, QString)), SLOT(handleFavicoDownload(QString, QString)));
connect(m_downloader, SIGNAL(downloadFailure(QString, QString)), SLOT(handleFavicoFailure(QString, QString)));
toggleFilter(Preferences::instance()->getTrackerFilterState());
}
TrackerFiltersList::~TrackerFiltersList()
{
delete m_downloader;
foreach (const QString &iconPath, m_iconPaths)
fsutils::forceRemove(iconPath);
}
@@ -466,8 +467,11 @@ void TrackerFiltersList::addItem(const QString &tracker, const QString &hash)
}
else {
trackerItem = new QListWidgetItem();
trackerItem->setData(Qt::DecorationRole, IconProvider::instance()->getIcon("network-server"));
m_downloader->downloadUrl(QString("http://") + host + QString("/favicon.ico"));
trackerItem->setData(Qt::DecorationRole, GuiIconProvider::instance()->getIcon("network-server"));
Net::DownloadHandler *h = Net::DownloadManager::instance()->downloadUrl(QString("http://%1/favicon.ico").arg(host));
connect(h, SIGNAL(downloadFinished(QString, QString)), this, SLOT(handleFavicoDownload(QString, QString)));
connect(h, SIGNAL(downloadFailed(QString, QString)), this, SLOT(handleFavicoFailure(QString, QString)));
}
tmp.append(hash);
@@ -611,18 +615,20 @@ void TrackerFiltersList::trackerWarning(const QString &hash, const QString &trac
void TrackerFiltersList::handleFavicoDownload(const QString& url, const QString& filePath)
{
QString host = getHost(url);
if (!m_trackers.contains(host))
return;
if (!m_trackers.contains(host)) return;
QListWidgetItem *trackerItem = item(rowFromTracker(host));
QIcon icon(filePath);
//Detect a non-decodable icon
bool invalid = icon.pixmap(icon.availableSizes().first()).isNull();
QList<QSize> sizes = icon.availableSizes();
bool invalid = (sizes.size() > 0 ? icon.pixmap(sizes.first()).isNull() : true);
if (invalid) {
if (url.endsWith(".ico", Qt::CaseInsensitive)) {
Logger::instance()->addMessage(tr("Couldn't decode favico for url `%1`. Trying to download favico in PNG format.").arg(url),
Log::WARNING);
m_downloader->downloadUrl(url.left(url.size() - 4) + ".png");
Net::DownloadHandler *h = Net::DownloadManager::instance()->downloadUrl(url.left(url.size() - 4) + ".png");
connect(h, SIGNAL(downloadFinished(QString, QString)), this, SLOT(handleFavicoDownload(QString, QString)));
connect(h, SIGNAL(downloadFailed(QString, QString)), this, SLOT(handleFavicoFailure(QString, QString)));
}
else {
Logger::instance()->addMessage(tr("Couldn't decode favico for url `%1`.").arg(url), Log::WARNING);
@@ -646,9 +652,9 @@ void TrackerFiltersList::handleFavicoFailure(const QString& url, const QString&
void TrackerFiltersList::showMenu(QPoint)
{
QMenu menu(this);
QAction *startAct = menu.addAction(IconProvider::instance()->getIcon("media-playback-start"), tr("Resume torrents"));
QAction *pauseAct = menu.addAction(IconProvider::instance()->getIcon("media-playback-pause"), tr("Pause torrents"));
QAction *deleteTorrentsAct = menu.addAction(IconProvider::instance()->getIcon("edit-delete"), tr("Delete torrents"));
QAction *startAct = menu.addAction(GuiIconProvider::instance()->getIcon("media-playback-start"), tr("Resume torrents"));
QAction *pauseAct = menu.addAction(GuiIconProvider::instance()->getIcon("media-playback-pause"), tr("Pause torrents"));
QAction *deleteTorrentsAct = menu.addAction(GuiIconProvider::instance()->getIcon("edit-delete"), tr("Delete torrents"));
QAction *act = 0;
act = menu.exec(QCursor::pos());
@@ -673,11 +679,11 @@ void TrackerFiltersList::applyFilter(int row)
void TrackerFiltersList::handleNewTorrent(TorrentModelItem* torrentItem)
{
QTorrentHandle handle = torrentItem->torrentHandle();
QString hash = handle.hash();
std::vector<libtorrent::announce_entry> trackers = handle.trackers();
for (std::vector<libtorrent::announce_entry>::iterator i = trackers.begin(), e = trackers.end(); i != e; ++i)
addItem(misc::toQStringU(i->url), hash);
BitTorrent::TorrentHandle *const handle = torrentItem->torrentHandle();
QString hash = handle->hash();
QList<BitTorrent::TrackerEntry> trackers = handle->trackers();
foreach (const BitTorrent::TrackerEntry &tracker, trackers)
addItem(tracker.url(), hash);
//Check for trackerless torrent
if (trackers.size() == 0)
@@ -688,11 +694,11 @@ void TrackerFiltersList::handleNewTorrent(TorrentModelItem* torrentItem)
void TrackerFiltersList::torrentAboutToBeDeleted(TorrentModelItem* torrentItem)
{
QTorrentHandle handle = torrentItem->torrentHandle();
QString hash = handle.hash();
std::vector<libtorrent::announce_entry> trackers = handle.trackers();
for (std::vector<libtorrent::announce_entry>::iterator i = trackers.begin(), e = trackers.end(); i != e; ++i)
removeItem(misc::toQStringU(i->url), hash);
BitTorrent::TorrentHandle *const handle = torrentItem->torrentHandle();
QString hash = handle->hash();
QList<BitTorrent::TrackerEntry> trackers = handle->trackers();
foreach (const BitTorrent::TrackerEntry &tracker, trackers)
removeItem(tracker.url(), hash);
//Check for trackerless torrent
if (trackers.size() == 0)
@@ -817,19 +823,34 @@ TransferListFiltersWidget::TransferListFiltersWidget(QWidget *parent, TransferLi
connect(this, SIGNAL(trackerWarning(const QString &, const QString &)), trackerFilters, SLOT(trackerWarning(const QString &, const QString &)));
}
void TransferListFiltersWidget::addTrackers(const QStringList &trackers, const QString &hash)
void TransferListFiltersWidget::addTrackers(BitTorrent::TorrentHandle *const torrent, const QList<BitTorrent::TrackerEntry> &trackers)
{
foreach (const QString &tracker, trackers)
trackerFilters->addItem(tracker, hash);
foreach (const BitTorrent::TrackerEntry &tracker, trackers)
trackerFilters->addItem(tracker.url(), torrent->hash());
}
void TransferListFiltersWidget::removeTrackers(const QStringList &trackers, const QString &hash)
void TransferListFiltersWidget::removeTrackers(BitTorrent::TorrentHandle *const torrent, const QList<BitTorrent::TrackerEntry> &trackers)
{
foreach (const QString &tracker, trackers)
trackerFilters->removeItem(tracker, hash);
foreach (const BitTorrent::TrackerEntry &tracker, trackers)
trackerFilters->removeItem(tracker.url(), torrent->hash());
}
void TransferListFiltersWidget::changeTrackerless(bool trackerless, const QString &hash)
void TransferListFiltersWidget::changeTrackerless(BitTorrent::TorrentHandle *const torrent, bool trackerless)
{
trackerFilters->changeTrackerless(trackerless, hash);
trackerFilters->changeTrackerless(trackerless, torrent->hash());
}
void TransferListFiltersWidget::trackerSuccess(BitTorrent::TorrentHandle *const torrent, const QString &tracker)
{
emit trackerSuccess(torrent->hash(), tracker);
}
void TransferListFiltersWidget::trackerWarning(BitTorrent::TorrentHandle *const torrent, const QString &tracker)
{
emit trackerWarning(torrent->hash(), tracker);
}
void TransferListFiltersWidget::trackerError(BitTorrent::TorrentHandle *const torrent, const QString &tracker)
{
emit trackerError(torrent->hash(), tracker);
}

View File

@@ -41,8 +41,13 @@ QT_END_NAMESPACE
class TransferListWidget;
class TorrentModelItem;
class QTorrentHandle;
class DownloadThread;
namespace BitTorrent
{
class TorrentHandle;
class TrackerEntry;
struct TorrentStatusReport;
}
class FiltersBase: public QListWidget
{
@@ -76,7 +81,7 @@ public:
~StatusFiltersWidget();
private slots:
void updateTorrentNumbers();
void updateTorrentNumbers(const BitTorrent::TorrentStatusReport &report);
private:
// These 4 methods are virtual slots in the base class.
@@ -158,7 +163,6 @@ private:
QHash<QString, QStringList> m_trackers;
QHash<QString, QStringList> m_errors;
QHash<QString, QStringList> m_warnings;
DownloadThread *m_downloader;
QStringList m_iconPaths;
int m_totalTorrents;
};
@@ -171,9 +175,12 @@ public:
TransferListFiltersWidget(QWidget *parent, TransferListWidget *transferList);
public slots:
void addTrackers(const QStringList &trackers, const QString &hash);
void removeTrackers(const QStringList &trackers, const QString &hash);
void changeTrackerless(bool trackerless, const QString &hash);
void addTrackers(BitTorrent::TorrentHandle *const torrent, const QList<BitTorrent::TrackerEntry> &trackers);
void removeTrackers(BitTorrent::TorrentHandle *const torrent, const QList<BitTorrent::TrackerEntry> &trackers);
void changeTrackerless(BitTorrent::TorrentHandle *const torrent, bool trackerless);
void trackerSuccess(BitTorrent::TorrentHandle *const torrent, const QString &tracker);
void trackerWarning(BitTorrent::TorrentHandle *const torrent, const QString &tracker);
void trackerError(BitTorrent::TorrentHandle *const torrent, const QString &tracker);
signals:
void trackerSuccess(const QString &hash, const QString &tracker);

View File

@@ -28,61 +28,46 @@
* Contact : daymansmail@gmail.com
*/
#include "transferlistsortmodel.h"
#include <QStringList>
#include "torrentmodel.h"
#include "core/misc.h"
#include "core/bittorrent/torrenthandle.h"
#include "torrentmodel.h"
#include "transferlistsortmodel.h"
TransferListSortModel::TransferListSortModel(QObject *parent)
: QSortFilterProxyModel(parent)
, filter0(TorrentFilter::ALL)
, labelFilterEnabled(false)
, trackerFilterEnabled(false)
{
}
void TransferListSortModel::setStatusFilter(const TorrentFilter::TorrentFilter &filter)
void TransferListSortModel::setStatusFilter(TorrentFilter::Type filter)
{
if (filter != filter0) {
filter0 = filter;
if (m_filter.setType(filter))
invalidateFilter();
}
}
void TransferListSortModel::setLabelFilter(const QString &label)
{
if (!labelFilterEnabled || labelFilter != label) {
labelFilterEnabled = true;
labelFilter = label;
if (m_filter.setLabel(label))
invalidateFilter();
}
}
void TransferListSortModel::disableLabelFilter()
{
if (labelFilterEnabled) {
labelFilterEnabled = false;
labelFilter = QString();
if (m_filter.setLabel(TorrentFilter::AnyLabel))
invalidateFilter();
}
}
void TransferListSortModel::setTrackerFilter(const QStringList &hashes)
{
if (!trackerFilterEnabled || trackerFilter != hashes) {
trackerFilterEnabled = true;
trackerFilter = hashes;
if (m_filter.setHashSet(hashes.toSet()))
invalidateFilter();
}
}
void TransferListSortModel::disableTrackerFilter()
{
if (trackerFilterEnabled) {
trackerFilterEnabled = false;
trackerFilter = QStringList();
if (m_filter.setHashSet(TorrentFilter::AnyHash))
invalidateFilter();
}
}
bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
@@ -92,12 +77,7 @@ bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex
if (column == TorrentModelItem::TR_NAME) {
QVariant vL = left.data();
QVariant vR = right.data();
if (!(vL.isValid() && vR.isValid()))
return lowerPositionThan(left, right);
Q_ASSERT(vL.isValid());
Q_ASSERT(vR.isValid());
if (vL == vR)
if (!vL.isValid() || !vR.isValid() || (vL == vR))
return lowerPositionThan(left, right);
bool res = false;
@@ -136,7 +116,7 @@ bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex
}
}
else if (column == TorrentModelItem::TR_ETA) {
const QAbstractItemModel *model = sourceModel();
TorrentModel *model = qobject_cast<TorrentModel *>(sourceModel());
const int prioL = model->data(model->index(left.row(), TorrentModelItem::TR_PRIORITY)).toInt();
const int prioR = model->data(model->index(right.row(), TorrentModelItem::TR_PRIORITY)).toInt();
const qlonglong etaL = left.data().toLongLong();
@@ -146,36 +126,9 @@ bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex
const bool invalidR = (etaR < 0 || etaR >= MAX_ETA);
const bool seedingL = (prioL < 0);
const bool seedingR = (prioR < 0);
bool activeL;
bool activeR;
switch (model->data(model->index(left.row(), TorrentModelItem::TR_STATUS)).toInt()) {
case TorrentModelItem::STATE_DOWNLOADING:
case TorrentModelItem::STATE_DOWNLOADING_META:
case TorrentModelItem::STATE_FORCED_DL:
case TorrentModelItem::STATE_STALLED_DL:
case TorrentModelItem::STATE_SEEDING:
case TorrentModelItem::STATE_FORCED_UP:
case TorrentModelItem::STATE_STALLED_UP:
activeL = true;
break;
default:
activeL = false;
}
switch (model->data(model->index(right.row(), TorrentModelItem::TR_STATUS)).toInt()) {
case TorrentModelItem::STATE_DOWNLOADING:
case TorrentModelItem::STATE_DOWNLOADING_META:
case TorrentModelItem::STATE_FORCED_DL:
case TorrentModelItem::STATE_STALLED_DL:
case TorrentModelItem::STATE_SEEDING:
case TorrentModelItem::STATE_FORCED_UP:
case TorrentModelItem::STATE_STALLED_UP:
activeR = true;
break;
default:
activeR = false;
}
bool activeR = TorrentFilter::ActiveTorrent.match(model->torrentHandle(model->index(right.row())));
bool activeL = TorrentFilter::ActiveTorrent.match(model->torrentHandle(model->index(right.row())));
// Sorting rules prioritized.
// 1. Active torrents at the top
@@ -189,7 +142,6 @@ bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex
}
if (invalidL && invalidR) {
if (seedingL) { //Both seeding
QDateTime dateL = model->data(model->index(left.row(), TorrentModelItem::TR_SEED_DATE)).toDateTime();
QDateTime dateR = model->data(model->index(right.row(), TorrentModelItem::TR_SEED_DATE)).toDateTime();
@@ -204,7 +156,7 @@ bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex
return prioL < prioR;
}
}
else if ((invalidL == false) && (invalidR == false)) {
else if (!invalidL && !invalidR) {
return lowerPositionThan(left, right);
}
else {
@@ -243,14 +195,8 @@ bool TransferListSortModel::lowerPositionThan(const QModelIndex &left, const QMo
// Sort according to TR_PRIORITY
const int queueL = model->data(model->index(left.row(), TorrentModelItem::TR_PRIORITY)).toInt();
const int queueR = model->data(model->index(right.row(), TorrentModelItem::TR_PRIORITY)).toInt();
if (!(queueL < 0 && queueR < 0)) {
if (queueL > 0 && queueR > 0)
return queueL < queueR;
else if (queueL < 0)
return false;
else
return true;
}
if ((queueL > 0) || (queueR > 0))
return queueL < queueR;
// Sort according to TR_SEED_DATE
const QDateTime dateL = model->data(model->index(left.row(), TorrentModelItem::TR_SEED_DATE)).toDateTime();
@@ -272,88 +218,17 @@ bool TransferListSortModel::lowerPositionThan(const QModelIndex &left, const QMo
bool TransferListSortModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
return matchStatusFilter(sourceRow, sourceParent)
&& matchLabelFilter(sourceRow, sourceParent)
&& matchTrackerFilter(sourceRow, sourceParent)
&& QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
return matchFilter(sourceRow, sourceParent)
&& QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
}
bool TransferListSortModel::matchStatusFilter(int sourceRow, const QModelIndex &sourceParent) const
bool TransferListSortModel::matchFilter(int sourceRow, const QModelIndex &sourceParent) const
{
if (filter0 == TorrentFilter::ALL)
return true;
QAbstractItemModel *model = sourceModel();
if (!model) return false;
QModelIndex index = model->index(sourceRow, TorrentModelItem::TR_STATUS, sourceParent);
TorrentModelItem::State state = (TorrentModelItem::State)index.data().toInt();
switch (filter0) {
case TorrentFilter::DOWNLOADING:
return (state == TorrentModelItem::STATE_DOWNLOADING || state == TorrentModelItem::STATE_STALLED_DL
|| state == TorrentModelItem::STATE_PAUSED_DL || state == TorrentModelItem::STATE_CHECKING_DL
|| state == TorrentModelItem::STATE_QUEUED_DL || state == TorrentModelItem::STATE_DOWNLOADING_META
|| state == TorrentModelItem::STATE_PAUSED_MISSING || state == TorrentModelItem::STATE_FORCED_DL);
case TorrentFilter::SEEDING:
return (state == TorrentModelItem::STATE_SEEDING || state == TorrentModelItem::STATE_STALLED_UP
|| state == TorrentModelItem::STATE_CHECKING_UP || state == TorrentModelItem::STATE_QUEUED_UP
|| state == TorrentModelItem::STATE_FORCED_UP);
case TorrentFilter::COMPLETED:
return (state == TorrentModelItem::STATE_SEEDING || state == TorrentModelItem::STATE_STALLED_UP
|| state == TorrentModelItem::STATE_PAUSED_UP || state == TorrentModelItem::STATE_CHECKING_UP
|| state == TorrentModelItem::STATE_QUEUED_UP || state == TorrentModelItem::STATE_FORCED_UP);
case TorrentFilter::PAUSED:
return (state == TorrentModelItem::STATE_PAUSED_DL || state == TorrentModelItem::STATE_PAUSED_MISSING);
case TorrentFilter::RESUMED:
return (state != TorrentModelItem::STATE_PAUSED_UP && state != TorrentModelItem::STATE_PAUSED_DL
&& state != TorrentModelItem::STATE_PAUSED_MISSING);
case TorrentFilter::ACTIVE:
if (state == TorrentModelItem::STATE_STALLED_DL) {
const qulonglong up_speed = model->index(sourceRow, TorrentModelItem::TR_UPSPEED, sourceParent).data().toULongLong();
return (up_speed > 0);
}
return (state == TorrentModelItem::STATE_DOWNLOADING || state == TorrentModelItem::STATE_SEEDING
|| state == TorrentModelItem::STATE_FORCED_DL || state == TorrentModelItem::STATE_FORCED_UP);
case TorrentFilter::INACTIVE:
if (state == TorrentModelItem::STATE_STALLED_DL) {
const qulonglong up_speed = model->index(sourceRow, TorrentModelItem::TR_UPSPEED, sourceParent).data().toULongLong();
return !(up_speed > 0);
}
return (state != TorrentModelItem::STATE_DOWNLOADING && state != TorrentModelItem::STATE_SEEDING
&& state != TorrentModelItem::STATE_FORCED_DL && state != TorrentModelItem::STATE_FORCED_UP);
default:
return false;
}
}
bool TransferListSortModel::matchLabelFilter(int sourceRow, const QModelIndex &sourceParent) const
{
if (!labelFilterEnabled)
return true;
QAbstractItemModel *model = sourceModel();
if (!model)
return false;
return model->index(sourceRow, TorrentModelItem::TR_LABEL, sourceParent).data().toString() == labelFilter;
}
bool TransferListSortModel::matchTrackerFilter(int sourceRow, const QModelIndex &sourceParent) const
{
if (!trackerFilterEnabled)
return true;
TorrentModel *model = qobject_cast<TorrentModel *>(sourceModel());
if (!model)
return false;
if (!model) return false;
return trackerFilter.contains(model->torrentHash(sourceRow));
BitTorrent::TorrentHandle *const torrent = model->torrentHandle(model->index(sourceRow, 0, sourceParent));
if (!torrent) return false;
return m_filter.match(torrent);
}

View File

@@ -32,8 +32,9 @@
#define TRANSFERLISTSORTMODEL_H
#include <QSortFilterProxyModel>
#include <QStringList>
#include "torrentfilterenum.h"
#include "core/torrentfilter.h"
class QStringList;
class TransferListSortModel: public QSortFilterProxyModel
{
@@ -42,7 +43,7 @@ class TransferListSortModel: public QSortFilterProxyModel
public:
TransferListSortModel(QObject *parent = 0);
void setStatusFilter(const TorrentFilter::TorrentFilter &filter);
void setStatusFilter(TorrentFilter::Type filter);
void setLabelFilter(const QString &label);
void disableLabelFilter();
void setTrackerFilter(const QStringList &hashes);
@@ -52,18 +53,10 @@ private:
bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
bool lowerPositionThan(const QModelIndex &left, const QModelIndex &right) const;
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
bool matchStatusFilter(int sourceRow, const QModelIndex &sourceParent) const;
bool matchLabelFilter(int sourceRow, const QModelIndex &sourceParent) const;
bool matchTrackerFilter(int sourceRow, const QModelIndex &sourceParent) const;
bool matchFilter(int sourceRow, const QModelIndex &sourceParent) const;
private:
TorrentFilter::TorrentFilter filter0;
bool labelFilterEnabled;
QString labelFilter;
bool trackerFilterEnabled;
QStringList trackerFilter;
TorrentFilter m_filter;
};
#endif // TRANSFERLISTSORTMODEL_H

View File

@@ -42,14 +42,10 @@
#include <QFileDialog>
#include <QMessageBox>
#include <libtorrent/version.hpp>
#include <libtorrent/magnet_uri.hpp>
#include <vector>
#include <queue>
#include "transferlistwidget.h"
#include "qbtsession.h"
#include "core/torrentpersistentdata.h"
#include "core/bittorrent/session.h"
#include "core/bittorrent/torrenthandle.h"
#include "core/torrentfilter.h"
#include "transferlistdelegate.h"
#include "previewselect.h"
#include "speedlimitdlg.h"
@@ -60,15 +56,14 @@
#include "torrentmodel.h"
#include "deletionconfirmationdlg.h"
#include "propertieswidget.h"
#include "iconprovider.h"
#include "guiiconprovider.h"
#include "core/fs_utils.h"
#include "autoexpandabledialog.h"
#include "transferlistsortmodel.h"
using namespace libtorrent;
TransferListWidget::TransferListWidget(QWidget *parent, MainWindow *main_window, QBtSession *_BTSession):
QTreeView(parent), BTSession(_BTSession), main_window(main_window)
TransferListWidget::TransferListWidget(QWidget *parent, MainWindow *main_window)
: QTreeView(parent)
, main_window(main_window)
{
setUniformRowHeights(true);
@@ -181,12 +176,6 @@ void TransferListWidget::previewFile(QString filePath)
openUrl(filePath);
}
void TransferListWidget::setRefreshInterval(int t)
{
qDebug("Settings transfer list refresh interval to %dms", t);
listModel->setRefreshInterval(t);
}
int TransferListWidget::getRowFromHash(QString hash) const
{
return listModel->torrentRow(hash);
@@ -216,24 +205,24 @@ void TransferListWidget::torrentDoubleClicked(const QModelIndex& index)
{
const int row = mapToSource(index).row();
const QString hash = getHashFromRow(row);
QTorrentHandle h = BTSession->getTorrentHandle(hash);
if (!h.is_valid()) return;
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (!torrent) return;
int action;
if (h.is_seed())
if (torrent->isSeed())
action = Preferences::instance()->getActionOnDblClOnTorrentFn();
else
action = Preferences::instance()->getActionOnDblClOnTorrentDl();
switch(action) {
case TOGGLE_PAUSE:
if (h.is_paused())
h.resume();
if (torrent->isPaused())
torrent->resume();
else
h.pause();
torrent->pause();
break;
case OPEN_DEST:
const QString path = h.root_path();
openUrl(path);
openUrl(torrent->rootPath());
}
}
@@ -250,72 +239,85 @@ void TransferListWidget::setSelectedTorrentsLocation()
{
const QStringList hashes = getSelectedTorrentsHashes();
if (hashes.isEmpty()) return;
BitTorrent::TorrentHandle *const firstTorrent = BitTorrent::Session::instance()->findTorrent(hashes.first());
if (!firstTorrent) return;
QString dir;
const QDir saveDir(TorrentPersistentData::instance()->getSavePath(hashes.first()));
const QDir saveDir(firstTorrent->savePath());
qDebug("Old save path is %s", qPrintable(saveDir.absolutePath()));
dir = QFileDialog::getExistingDirectory(this, tr("Choose save path"), saveDir.absolutePath(),
QFileDialog::DontConfirmOverwrite | QFileDialog::ShowDirsOnly | QFileDialog::HideNameFilterDetails);
if (!dir.isNull()) {
qDebug("New path is %s", qPrintable(dir));
// Check if savePath exists
QDir savePath(fsutils::expandPathAbs(dir));
qDebug("New path after clean up is %s", qPrintable(savePath.absolutePath()));
foreach (const QString & hash, hashes) {
foreach (const QString &hash, hashes) {
// Actually move storage
QTorrentHandle h = BTSession->getTorrentHandle(hash);
if (!BTSession->useTemporaryFolder() || h.is_seed()) {
if (!savePath.exists()) savePath.mkpath(savePath.absolutePath());
h.move_storage(savePath.absolutePath());
}
else {
TorrentPersistentData::instance()->saveSavePath(h.hash(), savePath.absolutePath());
main_window->getProperties()->updateSavePath(h);
}
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (!torrent) continue;
torrent->move(fsutils::expandPathAbs(dir));
main_window->getProperties()->updateSavePath(torrent);
}
}
}
void TransferListWidget::pauseAllTorrents()
{
foreach (BitTorrent::TorrentHandle *const torrent, BitTorrent::Session::instance()->torrents())
torrent->pause();
}
void TransferListWidget::resumeAllTorrents()
{
foreach (BitTorrent::TorrentHandle *const torrent, BitTorrent::Session::instance()->torrents())
torrent->resume();
}
void TransferListWidget::startSelectedTorrents()
{
const QStringList hashes = getSelectedTorrentsHashes();
foreach (const QString &hash, hashes)
BTSession->resumeTorrent(hash);
foreach (const QString &hash, getSelectedTorrentsHashes()) {
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (torrent)
torrent->resume();
}
}
void TransferListWidget::forceStartSelectedTorrents()
{
const QStringList hashes = getSelectedTorrentsHashes();
foreach (const QString &hash, hashes)
BTSession->resumeTorrent(hash, true);
foreach (const QString &hash, getSelectedTorrentsHashes()) {
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (torrent)
torrent->resume(true);
}
}
void TransferListWidget::startVisibleTorrents()
{
QStringList hashes;
for (int i = 0; i<nameFilterModel->rowCount(); ++i) {
for (int i = 0; i < nameFilterModel->rowCount(); ++i) {
const int row = mapToSource(nameFilterModel->index(i, 0)).row();
hashes << getHashFromRow(row);
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(getHashFromRow(row));
if (torrent)
torrent->resume();
}
foreach (const QString &hash, hashes)
BTSession->resumeTorrent(hash);
}
void TransferListWidget::pauseSelectedTorrents()
{
const QStringList hashes = getSelectedTorrentsHashes();
foreach (const QString &hash, hashes)
BTSession->pauseTorrent(hash);
foreach (const QString &hash, getSelectedTorrentsHashes()) {
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (torrent)
torrent->pause();
}
}
void TransferListWidget::pauseVisibleTorrents()
{
QStringList hashes;
for (int i = 0; i<nameFilterModel->rowCount(); ++i) {
for (int i = 0; i < nameFilterModel->rowCount(); ++i) {
const int row = mapToSource(nameFilterModel->index(i, 0)).row();
hashes << getHashFromRow(row);
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(getHashFromRow(row));
if (torrent)
torrent->pause();
}
foreach (const QString &hash, hashes)
BTSession->pauseTorrent(hash);
}
void TransferListWidget::deleteSelectedTorrents()
@@ -323,13 +325,14 @@ void TransferListWidget::deleteSelectedTorrents()
if (main_window->getCurrentTabWidget() != this) return;
const QStringList& hashes = getSelectedTorrentsHashes();
if (hashes.empty()) return;
QTorrentHandle torrent = BTSession->getTorrentHandle(hashes[0]);
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hashes[0]);
bool delete_local_files = false;
if (Preferences::instance()->confirmTorrentDeletion() &&
!DeletionConfirmationDlg::askForDeletionConfirmation(delete_local_files, hashes.size(), torrent.name()))
!DeletionConfirmationDlg::askForDeletionConfirmation(delete_local_files, hashes.size(), torrent->name()))
return;
foreach (const QString &hash, hashes)
BTSession->deleteTorrent(hash, delete_local_files);
BitTorrent::Session::instance()->deleteTorrent(hash, delete_local_files);
}
void TransferListWidget::deleteVisibleTorrents()
@@ -340,83 +343,40 @@ void TransferListWidget::deleteVisibleTorrents()
const int row = mapToSource(nameFilterModel->index(i, 0)).row();
hashes << getHashFromRow(row);
}
QTorrentHandle torrent = BTSession->getTorrentHandle(hashes[0]);
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hashes[0]);
bool delete_local_files = false;
if (Preferences::instance()->confirmTorrentDeletion() &&
!DeletionConfirmationDlg::askForDeletionConfirmation(delete_local_files, hashes.size(), torrent.name()))
!DeletionConfirmationDlg::askForDeletionConfirmation(delete_local_files, hashes.size(), torrent->name()))
return;
foreach (const QString &hash, hashes)
BTSession->deleteTorrent(hash, delete_local_files);
BitTorrent::Session::instance()->deleteTorrent(hash, delete_local_files);
}
void TransferListWidget::increasePrioSelectedTorrents()
{
qDebug() << Q_FUNC_INFO;
if (main_window->getCurrentTabWidget() != this) return;
const QStringList hashes = getSelectedTorrentsHashes();
std::priority_queue<QPair<int, QTorrentHandle>, std::vector<QPair<int, QTorrentHandle> >, std::greater<QPair<int, QTorrentHandle> > > torrent_queue;
// Sort torrents by priority
foreach (const QString &hash, hashes) {
try {
QTorrentHandle h = BTSession->getTorrentHandle(hash);
if (!h.is_seed())
torrent_queue.push(qMakePair(h.queue_position(), h));
}catch(invalid_handle&) {}
}
// Increase torrents priority (starting with the ones with highest priority)
while(!torrent_queue.empty()) {
QTorrentHandle h = torrent_queue.top().second;
try {
h.queue_position_up();
} catch(invalid_handle& h) {}
torrent_queue.pop();
}
if (main_window->getCurrentTabWidget() == this)
BitTorrent::Session::instance()->increaseTorrentsPriority(getSelectedTorrentsHashes());
}
void TransferListWidget::decreasePrioSelectedTorrents()
{
qDebug() << Q_FUNC_INFO;
if (main_window->getCurrentTabWidget() != this) return;
const QStringList hashes = getSelectedTorrentsHashes();
std::priority_queue<QPair<int, QTorrentHandle>, std::vector<QPair<int, QTorrentHandle> >, std::less<QPair<int, QTorrentHandle> > > torrent_queue;
// Sort torrents by priority
foreach (const QString &hash, hashes) {
try {
QTorrentHandle h = BTSession->getTorrentHandle(hash);
if (!h.is_seed())
torrent_queue.push(qMakePair(h.queue_position(), h));
}catch(invalid_handle&) {}
}
// Decrease torrents priority (starting with the ones with lowest priority)
while(!torrent_queue.empty()) {
QTorrentHandle h = torrent_queue.top().second;
try {
h.queue_position_down();
} catch(invalid_handle& h) {}
torrent_queue.pop();
}
if (main_window->getCurrentTabWidget() == this)
BitTorrent::Session::instance()->decreaseTorrentsPriority(getSelectedTorrentsHashes());
}
void TransferListWidget::topPrioSelectedTorrents()
{
if (main_window->getCurrentTabWidget() != this) return;
const QStringList hashes = getSelectedTorrentsHashes();
foreach (const QString &hash, hashes) {
QTorrentHandle h = BTSession->getTorrentHandle(hash);
if (h.is_valid() && !h.is_seed())
h.queue_position_top();
}
if (main_window->getCurrentTabWidget() == this)
BitTorrent::Session::instance()->topTorrentsPriority(getSelectedTorrentsHashes());
}
void TransferListWidget::bottomPrioSelectedTorrents()
{
if (main_window->getCurrentTabWidget() != this) return;
const QStringList hashes = getSelectedTorrentsHashes();
foreach (const QString &hash, hashes) {
QTorrentHandle h = BTSession->getTorrentHandle(hash);
if (h.is_valid() && !h.is_seed())
h.queue_position_bottom();
}
if (main_window->getCurrentTabWidget() == this)
BitTorrent::Session::instance()->bottomTorrentsPriority(getSelectedTorrentsHashes());
}
void TransferListWidget::copySelectedMagnetURIs() const
@@ -424,9 +384,9 @@ void TransferListWidget::copySelectedMagnetURIs() const
QStringList magnet_uris;
const QStringList hashes = getSelectedTorrentsHashes();
foreach (const QString &hash, hashes) {
const QTorrentHandle h = BTSession->getTorrentHandle(hash);
if (h.is_valid())
magnet_uris << misc::toQString(make_magnet_uri(h));
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (torrent)
magnet_uris << torrent->toMagnetUri();
}
qApp->clipboard()->setText(magnet_uris.join("\n"));
}
@@ -436,9 +396,9 @@ void TransferListWidget::copySelectedNames() const
QStringList torrent_names;
const QStringList hashes = getSelectedTorrentsHashes();
foreach (const QString &hash, hashes) {
const QTorrentHandle h = BTSession->getTorrentHandle(hash);
if (h.is_valid())
torrent_names << h.name();
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (torrent)
torrent_names << torrent->name();
}
qApp->clipboard()->setText(torrent_names.join("\n"));
}
@@ -456,9 +416,9 @@ void TransferListWidget::openSelectedTorrentsFolder() const
QSet<QString> pathsList;
const QStringList hashes = getSelectedTorrentsHashes();
foreach (const QString &hash, hashes) {
const QTorrentHandle h = BTSession->getTorrentHandle(hash);
if (h.is_valid()) {
QString rootFolder = h.root_path();
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (torrent) {
QString rootFolder = torrent->rootPath();
qDebug("Opening path at %s", qPrintable(rootFolder));
if (!pathsList.contains(rootFolder)) {
pathsList.insert(rootFolder);
@@ -472,27 +432,27 @@ void TransferListWidget::previewSelectedTorrents()
{
const QStringList hashes = getSelectedTorrentsHashes();
foreach (const QString &hash, hashes) {
const QTorrentHandle h = BTSession->getTorrentHandle(hash);
if (h.is_valid() && h.has_metadata())
new PreviewSelect(this, h);
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (torrent && torrent->hasMetadata())
new PreviewSelect(this, torrent);
}
}
void TransferListWidget::setDlLimitSelectedTorrents()
{
QList<QTorrentHandle> selected_torrents;
QList<BitTorrent::TorrentHandle *> selected_torrents;
bool first = true;
bool all_same_limit = true;
const QStringList hashes = getSelectedTorrentsHashes();
foreach (const QString &hash, hashes) {
const QTorrentHandle h = BTSession->getTorrentHandle(hash);
if (h.is_valid() && !h.is_seed()) {
selected_torrents << h;
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (torrent && !torrent->isSeed()) {
selected_torrents << torrent;
// Determine current limit for selected torrents
if (first)
first = false;
else
if (all_same_limit && h.download_limit() != selected_torrents.first().download_limit())
if (all_same_limit && (torrent->downloadLimit() != selected_torrents.first()->downloadLimit()))
all_same_limit = false;
}
}
@@ -501,31 +461,31 @@ void TransferListWidget::setDlLimitSelectedTorrents()
bool ok = false;
int default_limit = -1;
if (all_same_limit)
default_limit = selected_torrents.first().download_limit();
default_limit = selected_torrents.first()->downloadLimit();
const long new_limit = SpeedLimitDialog::askSpeedLimit(&ok, tr("Torrent Download Speed Limiting"), default_limit, Preferences::instance()->getGlobalDownloadLimit() * 1024.);
if (ok) {
foreach (const QTorrentHandle &h, selected_torrents) {
qDebug("Applying download speed limit of %ld Kb/s to torrent %s", (long)(new_limit / 1024.), qPrintable(h.hash()));
BTSession->setDownloadLimit(h.hash(), new_limit);
foreach (BitTorrent::TorrentHandle *const torrent, selected_torrents) {
qDebug("Applying download speed limit of %ld Kb/s to torrent %s", (long)(new_limit / 1024.), qPrintable(torrent->hash()));
torrent->setDownloadLimit(new_limit);
}
}
}
void TransferListWidget::setUpLimitSelectedTorrents()
{
QList<QTorrentHandle> selected_torrents;
QList<BitTorrent::TorrentHandle *> selected_torrents;
bool first = true;
bool all_same_limit = true;
const QStringList hashes = getSelectedTorrentsHashes();
foreach (const QString &hash, hashes) {
const QTorrentHandle h = BTSession->getTorrentHandle(hash);
if (h.is_valid()) {
selected_torrents << h;
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (torrent) {
selected_torrents << torrent;
// Determine current limit for selected torrents
if (first)
first = false;
else
if (all_same_limit && h.upload_limit() != selected_torrents.first().upload_limit())
if (all_same_limit && (torrent->uploadLimit() != selected_torrents.first()->uploadLimit()))
all_same_limit = false;
}
}
@@ -534,12 +494,12 @@ void TransferListWidget::setUpLimitSelectedTorrents()
bool ok = false;
int default_limit = -1;
if (all_same_limit)
default_limit = selected_torrents.first().upload_limit();
default_limit = selected_torrents.first()->uploadLimit();
const long new_limit = SpeedLimitDialog::askSpeedLimit(&ok, tr("Torrent Upload Speed Limiting"), default_limit, Preferences::instance()->getGlobalUploadLimit() * 1024.);
if (ok) {
foreach (const QTorrentHandle &h, selected_torrents) {
qDebug("Applying upload speed limit of %ld Kb/s to torrent %s", (long)(new_limit / 1024.), qPrintable(h.hash()));
BTSession->setUploadLimit(h.hash(), new_limit);
foreach (BitTorrent::TorrentHandle *const torrent, selected_torrents) {
qDebug("Applying upload speed limit of %ld Kb/s to torrent %s", (long)(new_limit / 1024.), qPrintable(torrent->hash()));
torrent->setUploadLimit(new_limit);
}
}
}
@@ -549,34 +509,37 @@ void TransferListWidget::setMaxRatioSelectedTorrents()
const QStringList hashes = getSelectedTorrentsHashes();
if (hashes.isEmpty())
return;
bool useGlobalValue;
qreal currentMaxRatio;
bool useGlobalValue = true;
qreal currentMaxRatio = BitTorrent::Session::instance()->globalMaxRatio();;
if (hashes.count() == 1) {
currentMaxRatio = BTSession->getMaxRatioPerTorrent(hashes.first(), &useGlobalValue);
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hashes.first());
if (torrent)
currentMaxRatio = torrent->maxRatio(&useGlobalValue);
}
else {
useGlobalValue = true;
currentMaxRatio = BTSession->getGlobalMaxRatio();
}
UpDownRatioDlg dlg(useGlobalValue, currentMaxRatio, QBtSession::MAX_RATIO, this);
if (dlg.exec() != QDialog::Accepted)
return;
UpDownRatioDlg dlg(useGlobalValue, currentMaxRatio, BitTorrent::TorrentHandle::MAX_RATIO, this);
if (dlg.exec() != QDialog::Accepted) return;
foreach (const QString &hash, hashes) {
if (dlg.useDefault())
BTSession->removeRatioPerTorrent(hash);
else
BTSession->setMaxRatioPerTorrent(hash, dlg.ratio());
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (torrent) {
qreal ratio = (dlg.useDefault() ? BitTorrent::TorrentHandle::USE_GLOBAL_RATIO : dlg.ratio());
torrent->setRatioLimit(ratio);
}
}
}
void TransferListWidget::recheckSelectedTorrents()
{
QMessageBox::StandardButton ret = QMessageBox::question(this, tr("Recheck confirmation"), tr("Are you sure you want to recheck the selected torrent(s)?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
if (ret != QMessageBox::Yes)
return;
if (ret != QMessageBox::Yes) return;
const QStringList hashes = getSelectedTorrentsHashes();
foreach (const QString &hash, hashes)
BTSession->recheckTorrent(hash);
foreach (const QString &hash, hashes) {
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (torrent)
torrent->forceRecheck();
}
}
// hide/show columns menu
@@ -586,7 +549,7 @@ void TransferListWidget::displayDLHoSMenu(const QPoint&)
hideshowColumn.setTitle(tr("Column visibility"));
QList<QAction*> actions;
for (int i = 0; i < listModel->columnCount(); ++i) {
if (!BTSession->isQueueingEnabled() && i == TorrentModelItem::TR_PRIORITY) {
if (!BitTorrent::Session::instance()->isQueueingEnabled() && i == TorrentModelItem::TR_PRIORITY) {
actions.append(0);
continue;
}
@@ -624,9 +587,9 @@ void TransferListWidget::toggleSelectedTorrentsSuperSeeding() const
{
const QStringList hashes = getSelectedTorrentsHashes();
foreach (const QString &hash, hashes) {
QTorrentHandle h = BTSession->getTorrentHandle(hash);
if (h.is_valid() && h.has_metadata())
h.super_seeding(!h.status(0).super_seeding);
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (torrent && torrent->hasMetadata())
torrent->setSuperSeeding(!torrent->superSeeding());
}
}
@@ -634,8 +597,9 @@ void TransferListWidget::toggleSelectedTorrentsSequentialDownload() const
{
const QStringList hashes = getSelectedTorrentsHashes();
foreach (const QString &hash, hashes) {
QTorrentHandle h = BTSession->getTorrentHandle(hash);
h.toggleSequentialDownload();
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (torrent)
torrent->toggleSequentialDownload();
}
}
@@ -643,8 +607,9 @@ void TransferListWidget::toggleSelectedFirstLastPiecePrio() const
{
QStringList hashes = getSelectedTorrentsHashes();
foreach (const QString &hash, hashes) {
QTorrentHandle h = BTSession->getTorrentHandle(hash);
h.toggleFirstLastPiecePrio();
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (torrent)
torrent->setFirstLastPiecePriority(!torrent->hasFirstLastPiecePriority());
}
}
@@ -685,11 +650,12 @@ void TransferListWidget::renameSelectedTorrent()
if (!selectedIndexes.first().isValid()) return;
QModelIndex mi = mapToSource(selectedIndexes.first());
const QString hash = getHashFromRow(mi.row());
const QTorrentHandle h = BTSession->getTorrentHandle(hash);
if (!h.is_valid()) return;
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (!torrent) return;
// Ask for a new Name
bool ok;
QString name = AutoExpandableDialog::getText(this, tr("Rename"), tr("New name:"), QLineEdit::Normal, h.name(), &ok);
QString name = AutoExpandableDialog::getText(this, tr("Rename"), tr("New name:"), QLineEdit::Normal, torrent->name(), &ok);
if (ok && !name.isEmpty()) {
name.replace(QRegExp("\r?\n|\r"), " ");
// Rename the torrent
@@ -703,23 +669,15 @@ void TransferListWidget::setSelectionLabel(QString label)
foreach (const QString &hash, hashes) {
Q_ASSERT(!hash.isEmpty());
const int row = getRowFromHash(hash);
const QString old_label = listModel->data(listModel->index(row, TorrentModelItem::TR_LABEL)).toString();
listModel->setData(listModel->index(row, TorrentModelItem::TR_LABEL), QVariant(label), Qt::DisplayRole);
// Update save path if necessary
QTorrentHandle h = BTSession->getTorrentHandle(hash);
BTSession->changeLabelInTorrentSavePath(h, old_label, label);
}
}
void TransferListWidget::removeLabelFromRows(QString label)
{
for (int i = 0; i<listModel->rowCount(); ++i) {
for (int i = 0; i < listModel->rowCount(); ++i) {
if (listModel->data(listModel->index(i, TorrentModelItem::TR_LABEL)) == label) {
const QString hash = getHashFromRow(i);
listModel->setData(listModel->index(i, TorrentModelItem::TR_LABEL), "", Qt::DisplayRole);
// Update save path if necessary
QTorrentHandle h = BTSession->getTorrentHandle(hash);
BTSession->changeLabelInTorrentSavePath(h, label, "");
}
}
}
@@ -730,15 +688,15 @@ void TransferListWidget::displayListMenu(const QPoint&)
if (selectedIndexes.size() == 0)
return;
// Create actions
QAction actionStart(IconProvider::instance()->getIcon("media-playback-start"), tr("Resume", "Resume/start the torrent"), 0);
QAction actionStart(GuiIconProvider::instance()->getIcon("media-playback-start"), tr("Resume", "Resume/start the torrent"), 0);
connect(&actionStart, SIGNAL(triggered()), this, SLOT(startSelectedTorrents()));
QAction actionForceStart(tr("Force Resume", "Force Resume/start the torrent"), 0);
connect(&actionForceStart, SIGNAL(triggered()), this, SLOT(forceStartSelectedTorrents()));
QAction actionPause(IconProvider::instance()->getIcon("media-playback-pause"), tr("Pause", "Pause the torrent"), 0);
QAction actionPause(GuiIconProvider::instance()->getIcon("media-playback-pause"), tr("Pause", "Pause the torrent"), 0);
connect(&actionPause, SIGNAL(triggered()), this, SLOT(pauseSelectedTorrents()));
QAction actionDelete(IconProvider::instance()->getIcon("edit-delete"), tr("Delete", "Delete the torrent"), 0);
QAction actionDelete(GuiIconProvider::instance()->getIcon("edit-delete"), tr("Delete", "Delete the torrent"), 0);
connect(&actionDelete, SIGNAL(triggered()), this, SLOT(deleteSelectedTorrents()));
QAction actionPreview_file(IconProvider::instance()->getIcon("view-preview"), tr("Preview file..."), 0);
QAction actionPreview_file(GuiIconProvider::instance()->getIcon("view-preview"), tr("Preview file..."), 0);
connect(&actionPreview_file, SIGNAL(triggered()), this, SLOT(previewSelectedTorrents()));
QAction actionSet_max_ratio(QIcon(QString::fromUtf8(":/icons/skin/ratio.png")), tr("Limit share ratio..."), 0);
connect(&actionSet_max_ratio, SIGNAL(triggered()), this, SLOT(setMaxRatioSelectedTorrents()));
@@ -746,28 +704,28 @@ void TransferListWidget::displayListMenu(const QPoint&)
connect(&actionSet_upload_limit, SIGNAL(triggered()), this, SLOT(setUpLimitSelectedTorrents()));
QAction actionSet_download_limit(QIcon(QString::fromUtf8(":/icons/skin/download.png")), tr("Limit download rate..."), 0);
connect(&actionSet_download_limit, SIGNAL(triggered()), this, SLOT(setDlLimitSelectedTorrents()));
QAction actionOpen_destination_folder(IconProvider::instance()->getIcon("inode-directory"), tr("Open destination folder"), 0);
QAction actionOpen_destination_folder(GuiIconProvider::instance()->getIcon("inode-directory"), tr("Open destination folder"), 0);
connect(&actionOpen_destination_folder, SIGNAL(triggered()), this, SLOT(openSelectedTorrentsFolder()));
QAction actionIncreasePriority(IconProvider::instance()->getIcon("go-up"), tr("Move up", "i.e. move up in the queue"), 0);
QAction actionIncreasePriority(GuiIconProvider::instance()->getIcon("go-up"), tr("Move up", "i.e. move up in the queue"), 0);
connect(&actionIncreasePriority, SIGNAL(triggered()), this, SLOT(increasePrioSelectedTorrents()));
QAction actionDecreasePriority(IconProvider::instance()->getIcon("go-down"), tr("Move down", "i.e. Move down in the queue"), 0);
QAction actionDecreasePriority(GuiIconProvider::instance()->getIcon("go-down"), tr("Move down", "i.e. Move down in the queue"), 0);
connect(&actionDecreasePriority, SIGNAL(triggered()), this, SLOT(decreasePrioSelectedTorrents()));
QAction actionTopPriority(IconProvider::instance()->getIcon("go-top"), tr("Move to top", "i.e. Move to top of the queue"), 0);
QAction actionTopPriority(GuiIconProvider::instance()->getIcon("go-top"), tr("Move to top", "i.e. Move to top of the queue"), 0);
connect(&actionTopPriority, SIGNAL(triggered()), this, SLOT(topPrioSelectedTorrents()));
QAction actionBottomPriority(IconProvider::instance()->getIcon("go-bottom"), tr("Move to bottom", "i.e. Move to bottom of the queue"), 0);
QAction actionBottomPriority(GuiIconProvider::instance()->getIcon("go-bottom"), tr("Move to bottom", "i.e. Move to bottom of the queue"), 0);
connect(&actionBottomPriority, SIGNAL(triggered()), this, SLOT(bottomPrioSelectedTorrents()));
QAction actionSetTorrentPath(IconProvider::instance()->getIcon("inode-directory"), tr("Set location..."), 0);
QAction actionSetTorrentPath(GuiIconProvider::instance()->getIcon("inode-directory"), tr("Set location..."), 0);
connect(&actionSetTorrentPath, SIGNAL(triggered()), this, SLOT(setSelectedTorrentsLocation()));
QAction actionForce_recheck(IconProvider::instance()->getIcon("document-edit-verify"), tr("Force recheck"), 0);
QAction actionForce_recheck(GuiIconProvider::instance()->getIcon("document-edit-verify"), tr("Force recheck"), 0);
connect(&actionForce_recheck, SIGNAL(triggered()), this, SLOT(recheckSelectedTorrents()));
QAction actionCopy_magnet_link(QIcon(":/icons/magnet.png"), tr("Copy magnet link"), 0);
connect(&actionCopy_magnet_link, SIGNAL(triggered()), this, SLOT(copySelectedMagnetURIs()));
QAction actionCopy_name(IconProvider::instance()->getIcon("edit-copy"), tr("Copy name"), 0);
QAction actionCopy_name(GuiIconProvider::instance()->getIcon("edit-copy"), tr("Copy name"), 0);
connect(&actionCopy_name, SIGNAL(triggered()), this, SLOT(copySelectedNames()));
QAction actionSuper_seeding_mode(tr("Super seeding mode"), 0);
actionSuper_seeding_mode.setCheckable(true);
connect(&actionSuper_seeding_mode, SIGNAL(triggered()), this, SLOT(toggleSelectedTorrentsSuperSeeding()));
QAction actionRename(IconProvider::instance()->getIcon("edit-rename"), tr("Rename..."), 0);
QAction actionRename(GuiIconProvider::instance()->getIcon("edit-rename"), tr("Rename..."), 0);
connect(&actionRename, SIGNAL(triggered()), this, SLOT(renameSelectedTorrent()));
QAction actionSequential_download(tr("Download in sequential order"), 0);
actionSequential_download.setCheckable(true);
@@ -786,43 +744,45 @@ void TransferListWidget::displayListMenu(const QPoint&)
bool one_has_metadata = false, one_not_seed = false;
bool first = true;
bool forced = false;
QTorrentHandle h;
BitTorrent::TorrentHandle *torrent;
qDebug("Displaying menu");
foreach (const QModelIndex &index, selectedIndexes) {
// Get the file name
QString hash = getHashFromRow(mapToSource(index).row());
// Get handle and pause the torrent
h = BTSession->getTorrentHandle(hash);
if (!h.is_valid()) continue;
if (h.has_metadata())
torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (!torrent) continue;
if (torrent->hasMetadata())
one_has_metadata = true;
forced = h.is_forced();
if (!h.is_seed()) {
forced = torrent->isForced();
if (!torrent->isSeed()) {
one_not_seed = true;
if (h.has_metadata()) {
if (torrent->hasMetadata()) {
if (first) {
sequential_download_mode = h.is_sequential_download();
prioritize_first_last = h.first_last_piece_first();
sequential_download_mode = torrent->isSequentialDownload();
prioritize_first_last = torrent->hasFirstLastPiecePriority();
}
else {
if (sequential_download_mode != h.is_sequential_download())
if (sequential_download_mode != torrent->isSequentialDownload())
all_same_sequential_download_mode = false;
if (prioritize_first_last != h.first_last_piece_first())
if (prioritize_first_last != torrent->hasFirstLastPiecePriority())
all_same_prio_firstlast = false;
}
}
}
else {
if (!one_not_seed && all_same_super_seeding && h.has_metadata()) {
if (!one_not_seed && all_same_super_seeding && torrent->hasMetadata()) {
if (first) {
super_seeding_mode = h.status(0).super_seeding;
super_seeding_mode = torrent->superSeeding();
}
else if (super_seeding_mode != h.status(0).super_seeding)
else if (super_seeding_mode != torrent->superSeeding())
all_same_super_seeding = false;
}
}
if (h.is_paused()) {
if (torrent->isPaused()) {
if (!has_start) {
listMenu.addAction(&actionStart);
has_start = true;
@@ -852,7 +812,7 @@ void TransferListWidget::displayListMenu(const QPoint&)
has_pause = true;
}
}
if (h.has_metadata() && !has_preview)
if (torrent->hasMetadata() && !has_preview)
has_preview = true;
first = false;
if (has_pause && has_start && has_force && has_preview && one_not_seed) break;
@@ -867,12 +827,12 @@ void TransferListWidget::displayListMenu(const QPoint&)
QStringList customLabels = Preferences::instance()->getTorrentLabels();
customLabels.sort();
QList<QAction*> labelActions;
QMenu *labelMenu = listMenu.addMenu(IconProvider::instance()->getIcon("view-categories"), tr("Label"));
labelActions << labelMenu->addAction(IconProvider::instance()->getIcon("list-add"), tr("New...", "New label..."));
labelActions << labelMenu->addAction(IconProvider::instance()->getIcon("edit-clear"), tr("Reset", "Reset label"));
QMenu *labelMenu = listMenu.addMenu(GuiIconProvider::instance()->getIcon("view-categories"), tr("Label"));
labelActions << labelMenu->addAction(GuiIconProvider::instance()->getIcon("list-add"), tr("New...", "New label..."));
labelActions << labelMenu->addAction(GuiIconProvider::instance()->getIcon("edit-clear"), tr("Reset", "Reset label"));
labelMenu->addSeparator();
foreach (const QString &label, customLabels)
labelActions << labelMenu->addAction(IconProvider::instance()->getIcon("inode-directory"), label);
labelActions << labelMenu->addAction(GuiIconProvider::instance()->getIcon("inode-directory"), label);
listMenu.addSeparator();
if (one_not_seed)
listMenu.addAction(&actionSet_download_limit);
@@ -907,7 +867,7 @@ void TransferListWidget::displayListMenu(const QPoint&)
listMenu.addSeparator();
}
listMenu.addAction(&actionOpen_destination_folder);
if (BTSession->isQueueingEnabled() && one_not_seed) {
if (BitTorrent::Session::instance()->isQueueingEnabled() && one_not_seed) {
listMenu.addSeparator();
QMenu *prioMenu = listMenu.addMenu(tr("Priority"));
prioMenu->addAction(&actionTopPriority);
@@ -944,14 +904,14 @@ void TransferListWidget::displayListMenu(const QPoint&)
void TransferListWidget::currentChanged(const QModelIndex& current, const QModelIndex&)
{
qDebug("CURRENT CHANGED");
QTorrentHandle h;
BitTorrent::TorrentHandle *torrent = 0;
if (current.isValid()) {
const int row = mapToSource(current).row();
h = BTSession->getTorrentHandle(getHashFromRow(row));
torrent = BitTorrent::Session::instance()->findTorrent(getHashFromRow(row));
// Scroll Fix
scrollTo(current);
}
emit currentTorrentChanged(h);
emit currentTorrentChanged(torrent);
}
void TransferListWidget::applyLabelFilterAll()
@@ -982,7 +942,7 @@ void TransferListWidget::applyNameFilter(const QString& name)
void TransferListWidget::applyStatusFilter(int f)
{
nameFilterModel->setStatusFilter((TorrentFilter::TorrentFilter)f);
nameFilterModel->setStatusFilter(static_cast<TorrentFilter::Type>(f));
// Select first item if nothing is selected
if (selectionModel()->selectedRows(0).empty() && nameFilterModel->rowCount() > 0) {
qDebug("Nothing is selected, selecting first row: %s", qPrintable(nameFilterModel->index(0, TorrentModelItem::TR_NAME).data().toString()));

View File

@@ -32,10 +32,12 @@
#define TRANSFERLISTWIDGET_H
#include <QTreeView>
#include <libtorrent/version.hpp>
class QBtSession;
class QTorrentHandle;
namespace BitTorrent
{
class TorrentHandle;
}
class MainWindow;
class TransferListDelegate;
class TransferListSortModel;
@@ -52,14 +54,15 @@ class TransferListWidget: public QTreeView
Q_OBJECT
public:
TransferListWidget(QWidget *parent, MainWindow *main_window, QBtSession* BTSession);
TransferListWidget(QWidget *parent, MainWindow *main_window);
~TransferListWidget();
TorrentModel* getSourceModel() const;
public slots:
void setSelectionLabel(QString label);
void setRefreshInterval(int t);
void setSelectedTorrentsLocation();
void pauseAllTorrents();
void resumeAllTorrents();
void startSelectedTorrents();
void forceStartSelectedTorrents();
void startVisibleTorrents();
@@ -113,13 +116,12 @@ private:
bool openUrl(const QString& _path) const;
signals:
void currentTorrentChanged(const QTorrentHandle &h);
void currentTorrentChanged(BitTorrent::TorrentHandle *const torrent);
private:
TransferListDelegate *listDelegate;
TorrentModel *listModel;
TransferListSortModel *nameFilterModel;
QBtSession* BTSession;
MainWindow *main_window;
QShortcut *editHotkey;
QShortcut *deleteHotkey;