mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2024-10-22 10:46:04 +03:00
- Added Magnet URI support (might be still buggy)
* Known problem: Always added in paused state for some obscure reason)
This commit is contained in:
parent
2742a54d6e
commit
e619b6977a
13 changed files with 848 additions and 650 deletions
|
@ -1,4 +1,5 @@
|
||||||
* Unknown - Christophe Dumez <chris@qbittorrent.org> - v1.5.0
|
* Unknown - Christophe Dumez <chris@qbittorrent.org> - v1.5.0
|
||||||
|
- FEATURE: Added Magnet URI support
|
||||||
- BUGFIX: torrent resume code rewrited
|
- BUGFIX: torrent resume code rewrited
|
||||||
|
|
||||||
* Thu Aug 13 2009 - Christophe Dumez <chris@qbittorrent.org> - v1.4.0
|
* Thu Aug 13 2009 - Christophe Dumez <chris@qbittorrent.org> - v1.4.0
|
||||||
|
|
|
@ -64,6 +64,8 @@ FinishedTorrents::FinishedTorrents(QObject *parent, bittorrent *BTSession) : par
|
||||||
if(!loadColWidthFinishedList()){
|
if(!loadColWidthFinishedList()){
|
||||||
finishedList->header()->resizeSection(0, 200);
|
finishedList->header()->resizeSection(0, 200);
|
||||||
}
|
}
|
||||||
|
// Connect BTSession signals
|
||||||
|
connect(BTSession, SIGNAL(metadataReceived(QTorrentHandle&)), this, SLOT(updateMetadata(QTorrentHandle&)));
|
||||||
// Make download list header clickable for sorting
|
// Make download list header clickable for sorting
|
||||||
finishedList->header()->setClickable(true);
|
finishedList->header()->setClickable(true);
|
||||||
finishedList->header()->setSortIndicatorShown(true);
|
finishedList->header()->setSortIndicatorShown(true);
|
||||||
|
@ -266,6 +268,16 @@ void FinishedTorrents::on_actionSet_upload_limit_triggered(){
|
||||||
new BandwidthAllocationDialog(this, true, BTSession, hashes);
|
new BandwidthAllocationDialog(this, true, BTSession, hashes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FinishedTorrents::updateMetadata(QTorrentHandle &h) {
|
||||||
|
QString hash = h.hash();
|
||||||
|
int row = getRowFromHash(hash);
|
||||||
|
if(row != -1) {
|
||||||
|
qDebug("Updating torrent metadata in download list");
|
||||||
|
finishedListModel->setData(finishedListModel->index(row, F_NAME), QVariant(h.name()));
|
||||||
|
finishedListModel->setData(finishedListModel->index(row, F_SIZE), QVariant((qlonglong)h.actual_size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FinishedTorrents::updateTorrent(QTorrentHandle h) {
|
void FinishedTorrents::updateTorrent(QTorrentHandle h) {
|
||||||
QString hash = h.hash();
|
QString hash = h.hash();
|
||||||
int row = getRowFromHash(hash);
|
int row = getRowFromHash(hash);
|
||||||
|
|
|
@ -93,6 +93,7 @@ class FinishedTorrents : public QWidget, public Ui::seeding {
|
||||||
void deleteTorrent(QString hash);
|
void deleteTorrent(QString hash);
|
||||||
void showPropertiesFromHash(QString hash);
|
void showPropertiesFromHash(QString hash);
|
||||||
void loadLastSortedColumn();
|
void loadLastSortedColumn();
|
||||||
|
void updateMetadata(QTorrentHandle &h);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void torrentMovedFromFinishedList(QString);
|
void torrentMovedFromFinishedList(QString);
|
||||||
|
|
30
src/GUI.cpp
30
src/GUI.cpp
|
@ -763,6 +763,11 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), dis
|
||||||
BTSession->downloadFromUrl(file);
|
BTSession->downloadFromUrl(file);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if(file.startsWith("magnet:", Qt::CaseInsensitive)) {
|
||||||
|
// FIXME: Possibly skipped torrent addition dialog
|
||||||
|
BTSession->addMagnetUri(file);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if(useTorrentAdditionDialog) {
|
if(useTorrentAdditionDialog) {
|
||||||
torrentAdditionDialog *dialog = new torrentAdditionDialog(this, BTSession);
|
torrentAdditionDialog *dialog = new torrentAdditionDialog(this, BTSession);
|
||||||
dialog->showLoad(file);
|
dialog->showLoad(file);
|
||||||
|
@ -921,11 +926,16 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), dis
|
||||||
if(param.startsWith(QString::fromUtf8("http://"), Qt::CaseInsensitive) || param.startsWith(QString::fromUtf8("ftp://"), Qt::CaseInsensitive) || param.startsWith(QString::fromUtf8("https://"), Qt::CaseInsensitive)) {
|
if(param.startsWith(QString::fromUtf8("http://"), Qt::CaseInsensitive) || param.startsWith(QString::fromUtf8("ftp://"), Qt::CaseInsensitive) || param.startsWith(QString::fromUtf8("https://"), Qt::CaseInsensitive)) {
|
||||||
BTSession->downloadFromUrl(param);
|
BTSession->downloadFromUrl(param);
|
||||||
}else{
|
}else{
|
||||||
if(useTorrentAdditionDialog) {
|
if(param.startsWith("magnet:", Qt::CaseInsensitive)) {
|
||||||
torrentAdditionDialog *dialog = new torrentAdditionDialog(this, BTSession);
|
// FIXME: Possibily skipped torrent addition dialog
|
||||||
dialog->showLoad(param);
|
BTSession->addMagnetUri(param);
|
||||||
}else{
|
} else {
|
||||||
BTSession->addTorrent(param);
|
if(useTorrentAdditionDialog) {
|
||||||
|
torrentAdditionDialog *dialog = new torrentAdditionDialog(this, BTSession);
|
||||||
|
dialog->showLoad(param);
|
||||||
|
}else{
|
||||||
|
BTSession->addTorrent(param);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1491,8 +1501,14 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), dis
|
||||||
* *
|
* *
|
||||||
*****************************************************/
|
*****************************************************/
|
||||||
|
|
||||||
void GUI::downloadFromURLList(const QStringList& urls) {
|
void GUI::downloadFromURLList(const QStringList& url_list) {
|
||||||
BTSession->downloadFromURLList(urls);
|
foreach(const QString url, url_list) {
|
||||||
|
if(url.startsWith("magnet:", Qt::CaseInsensitive)) {
|
||||||
|
BTSession->addMagnetUri(url);
|
||||||
|
} else {
|
||||||
|
BTSession->downloadFromUrl(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************
|
/*****************************************************
|
||||||
|
|
|
@ -37,234 +37,234 @@
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
||||||
class torrent_file {
|
class torrent_file {
|
||||||
private:
|
private:
|
||||||
torrent_file *parent;
|
torrent_file *parent;
|
||||||
bool is_dir;
|
bool is_dir;
|
||||||
QString rel_path;
|
QString rel_path;
|
||||||
QList<const torrent_file*> children;
|
QList<const torrent_file*> children;
|
||||||
size_type size;
|
size_type size;
|
||||||
float progress;
|
float progress;
|
||||||
int priority;
|
int priority;
|
||||||
int index; // Index in torrent_info
|
int index; // Index in torrent_info
|
||||||
|
|
||||||
public:
|
public:
|
||||||
torrent_file(torrent_file *parent, QString path, bool dir, size_type size=0, int index=-1, float progress=0., int priority=1): parent(parent), is_dir(dir), size(size), progress(progress), priority(priority), index(index){
|
torrent_file(torrent_file *parent, QString path, bool dir, size_type size=0, int index=-1, float progress=0., int priority=1): parent(parent), is_dir(dir), size(size), progress(progress), priority(priority), index(index){
|
||||||
qDebug("created a file with index %d", index);
|
qDebug("created a file with index %d", index);
|
||||||
rel_path = QDir::cleanPath(path);
|
rel_path = QDir::cleanPath(path);
|
||||||
Q_ASSERT(progress >= 0.);
|
Q_ASSERT(progress >= 0.);
|
||||||
Q_ASSERT(progress <= 1.);
|
Q_ASSERT(progress <= 1.);
|
||||||
if(parent) {
|
if(parent) {
|
||||||
parent->updateProgress();
|
parent->updateProgress();
|
||||||
parent->updatePriority(priority);
|
parent->updatePriority(priority);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
~torrent_file() {
|
~torrent_file() {
|
||||||
qDeleteAll(children);
|
qDeleteAll(children);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString path() const {
|
QString path() const {
|
||||||
return rel_path;
|
return rel_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString name() const {
|
QString name() const {
|
||||||
return rel_path.split(QDir::separator()).last();
|
return rel_path.split(QDir::separator()).last();
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateProgress() {
|
void updateProgress() {
|
||||||
Q_ASSERT(is_dir);
|
Q_ASSERT(is_dir);
|
||||||
if(children.isEmpty()) {
|
if(children.isEmpty()) {
|
||||||
progress = 0.;
|
progress = 0.;
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
double wanted = 0.;
|
|
||||||
double done = 0.;
|
|
||||||
foreach(const torrent_file *child, children) {
|
|
||||||
wanted += child->getSize();
|
|
||||||
done += child->getSize()*child->getProgress();
|
|
||||||
}
|
|
||||||
progress = done / wanted;
|
|
||||||
Q_ASSERT(progress >= 0.);
|
|
||||||
Q_ASSERT(progress <= 1.);
|
|
||||||
}
|
}
|
||||||
|
double wanted = 0.;
|
||||||
|
double done = 0.;
|
||||||
|
foreach(const torrent_file *child, children) {
|
||||||
|
wanted += child->getSize();
|
||||||
|
done += child->getSize()*child->getProgress();
|
||||||
|
}
|
||||||
|
progress = done / wanted;
|
||||||
|
Q_ASSERT(progress >= 0.);
|
||||||
|
Q_ASSERT(progress <= 1.);
|
||||||
|
}
|
||||||
|
|
||||||
void updatePriority(int prio) {
|
void updatePriority(int prio) {
|
||||||
Q_ASSERT(is_dir);
|
Q_ASSERT(is_dir);
|
||||||
foreach(const torrent_file *child, children) {
|
foreach(const torrent_file *child, children) {
|
||||||
if(child->getPriority() != prio) return;
|
if(child->getPriority() != prio) return;
|
||||||
}
|
|
||||||
priority = prio;
|
|
||||||
}
|
}
|
||||||
|
priority = prio;
|
||||||
|
}
|
||||||
|
|
||||||
int getPriority() const {
|
int getPriority() const {
|
||||||
return priority;
|
return priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type getSize() const {
|
size_type getSize() const {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
float getProgress() const {
|
float getProgress() const {
|
||||||
return progress;
|
return progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getIndex() const {
|
int getIndex() const {
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isDir() const {
|
bool isDir() const {
|
||||||
return is_dir;
|
return is_dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasChildren() const {
|
bool hasChildren() const {
|
||||||
return (!children.isEmpty());
|
return (!children.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<const torrent_file*> getChildren() const {
|
QList<const torrent_file*> getChildren() const {
|
||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
|
|
||||||
const torrent_file* getChild(QString fileName) const {
|
const torrent_file* getChild(QString fileName) const {
|
||||||
Q_ASSERT(is_dir);
|
Q_ASSERT(is_dir);
|
||||||
foreach(const torrent_file *f, children) {
|
foreach(const torrent_file *f, children) {
|
||||||
if(f->name() == fileName) return f;
|
if(f->name() == fileName) return f;
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void addBytes(size_type b) {
|
void addBytes(size_type b) {
|
||||||
size += b;
|
size += b;
|
||||||
if(parent)
|
if(parent)
|
||||||
parent->addBytes(b);
|
parent->addBytes(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
torrent_file* addChild(QString fileName, bool dir, size_type size=0, int index = -1, float progress=0., int priority=1) {
|
torrent_file* addChild(QString fileName, bool dir, size_type size=0, int index = -1, float progress=0., int priority=1) {
|
||||||
Q_ASSERT(is_dir);
|
Q_ASSERT(is_dir);
|
||||||
qDebug("Adding a new child of size: %ld", (long)size);
|
qDebug("Adding a new child of size: %ld", (long)size);
|
||||||
torrent_file *f = new torrent_file(this, QDir::cleanPath(rel_path+QDir::separator()+fileName), dir, size, index, progress, priority);
|
torrent_file *f = new torrent_file(this, QDir::cleanPath(rel_path+QDir::separator()+fileName), dir, size, index, progress, priority);
|
||||||
children << f;
|
children << f;
|
||||||
if(size) {
|
if(size) {
|
||||||
addBytes(size);
|
addBytes(size);
|
||||||
}
|
|
||||||
return f;
|
|
||||||
}
|
}
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
bool removeFromFS(QString saveDir) const {
|
bool removeFromFS(QString saveDir) const {
|
||||||
QString full_path = saveDir + QDir::separator() + rel_path;
|
QString full_path = saveDir + QDir::separator() + rel_path;
|
||||||
if(!QFile::exists(full_path)) {
|
if(!QFile::exists(full_path)) {
|
||||||
qDebug("%s does not exist, no need to remove it", full_path.toLocal8Bit().data());
|
qDebug("%s does not exist, no need to remove it", full_path.toLocal8Bit().data());
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
bool success = true;
|
|
||||||
qDebug("We have %d children", children.size());
|
|
||||||
foreach(const torrent_file *f, children) {
|
|
||||||
bool s = f->removeFromFS(saveDir);
|
|
||||||
success = s && success;
|
|
||||||
}
|
|
||||||
if(is_dir) {
|
|
||||||
qDebug("trying to remove directory: %s", full_path.toLocal8Bit().data());
|
|
||||||
QDir dir(full_path);
|
|
||||||
dir.rmdir(full_path);
|
|
||||||
} else {
|
|
||||||
qDebug("trying to remove file: %s", full_path.toLocal8Bit().data());
|
|
||||||
bool s = QFile::remove(full_path);
|
|
||||||
success = s && success;
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
bool success = true;
|
||||||
|
qDebug("We have %d children", children.size());
|
||||||
|
foreach(const torrent_file *f, children) {
|
||||||
|
bool s = f->removeFromFS(saveDir);
|
||||||
|
success = s && success;
|
||||||
|
}
|
||||||
|
if(is_dir) {
|
||||||
|
qDebug("trying to remove directory: %s", full_path.toLocal8Bit().data());
|
||||||
|
QDir dir(full_path);
|
||||||
|
dir.rmdir(full_path);
|
||||||
|
} else {
|
||||||
|
qDebug("trying to remove file: %s", full_path.toLocal8Bit().data());
|
||||||
|
bool s = QFile::remove(full_path);
|
||||||
|
success = s && success;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class arborescence {
|
class arborescence {
|
||||||
private:
|
private:
|
||||||
torrent_file *root;
|
torrent_file *root;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
arborescence(boost::intrusive_ptr<torrent_info> t) {
|
arborescence(boost::intrusive_ptr<torrent_info> t) {
|
||||||
torrent_info::file_iterator fi = t->begin_files();
|
torrent_info::file_iterator fi = t->begin_files();
|
||||||
if(t->num_files() > 1) {
|
if(t->num_files() > 1) {
|
||||||
root = new torrent_file(0, misc::toQString(t->name()), true);
|
root = new torrent_file(0, misc::toQString(t->name()), true);
|
||||||
} else {
|
} else {
|
||||||
// XXX: Will crash if there is no file in torrent
|
// XXX: Will crash if there is no file in torrent
|
||||||
root = new torrent_file(0, misc::toQString(t->name()), false, fi->size, 0);
|
root = new torrent_file(0, misc::toQString(t->name()), false, fi->size, 0);
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
int i = 0;
|
|
||||||
while(fi != t->end_files()) {
|
|
||||||
QString path = QDir::cleanPath(misc::toQString(fi->path.string()));
|
|
||||||
addFile(path, fi->size, i);
|
|
||||||
fi++;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
qDebug("real size: %ld, tree size: %ld", (long)t->total_size(), (long)root->getSize());
|
|
||||||
Q_ASSERT(root->getSize() == t->total_size());
|
|
||||||
}
|
}
|
||||||
|
int i = 0;
|
||||||
arborescence(torrent_info const& t, std::vector<size_type> fp, std::vector<int> files_priority) {
|
while(fi != t->end_files()) {
|
||||||
torrent_info::file_iterator fi = t.begin_files();
|
QString path = QDir::cleanPath(misc::toQString(fi->path.string()));
|
||||||
if(t.num_files() > 1) {
|
addFile(path, fi->size, i);
|
||||||
qDebug("More than one file in the torrent, setting a folder as root");
|
fi++;
|
||||||
root = new torrent_file(0, misc::toQString(t.name()), true);
|
++i;
|
||||||
} else {
|
|
||||||
// XXX: Will crash if there is no file in torrent
|
|
||||||
qDebug("one file in the torrent, setting it as root with index 0");
|
|
||||||
root = new torrent_file(0, misc::toQString(t.name()), false, fi->size, 0, ((double)fp[0])/t.file_at(0).size, files_priority.at(0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int i = 0;
|
|
||||||
while(fi != t.end_files()) {
|
|
||||||
QString path = QDir::cleanPath(misc::toQString(fi->path.string()));
|
|
||||||
addFile(path, fi->size, i, ((double)fp[i])/t.file_at(i).size, files_priority.at(i));
|
|
||||||
fi++;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
qDebug("real size: %ld, tree size: %ld", (long)t.total_size(), (long)root->getSize());
|
|
||||||
Q_ASSERT(root->getSize() == t.total_size());
|
|
||||||
}
|
}
|
||||||
|
qDebug("real size: %ld, tree size: %ld", (long)t->total_size(), (long)root->getSize());
|
||||||
|
Q_ASSERT(root->getSize() == t->total_size());
|
||||||
|
}
|
||||||
|
|
||||||
~arborescence() {
|
arborescence(torrent_info const& t, std::vector<size_type> fp, std::vector<int> files_priority) {
|
||||||
delete root;
|
torrent_info::file_iterator fi = t.begin_files();
|
||||||
|
if(t.num_files() > 1) {
|
||||||
|
qDebug("More than one file in the torrent, setting a folder as root");
|
||||||
|
root = new torrent_file(0, misc::toQString(t.name()), true);
|
||||||
|
} else {
|
||||||
|
// XXX: Will crash if there is no file in torrent
|
||||||
|
qDebug("one file in the torrent, setting it as root with index 0");
|
||||||
|
root = new torrent_file(0, misc::toQString(t.name()), false, fi->size, 0, ((double)fp[0])/t.file_at(0).size, files_priority.at(0));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
int i = 0;
|
||||||
torrent_file* getRoot() const {
|
while(fi != t.end_files()) {
|
||||||
return root;
|
QString path = QDir::cleanPath(misc::toQString(fi->path.string()));
|
||||||
|
addFile(path, fi->size, i, ((double)fp[i])/t.file_at(i).size, files_priority.at(i));
|
||||||
|
fi++;
|
||||||
|
++i;
|
||||||
}
|
}
|
||||||
|
qDebug("real size: %ld, tree size: %ld", (long)t.total_size(), (long)root->getSize());
|
||||||
|
Q_ASSERT(root->getSize() == t.total_size());
|
||||||
|
}
|
||||||
|
|
||||||
bool removeFromFS(QString saveDir) {
|
~arborescence() {
|
||||||
if(!QFile::exists(saveDir+QDir::separator()+root->path())) return true;
|
delete root;
|
||||||
bool success = root->removeFromFS(saveDir);
|
}
|
||||||
QDir root_dir(root->path());
|
|
||||||
root_dir.rmdir(saveDir+QDir::separator()+root->path());
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
torrent_file* getRoot() const {
|
||||||
void addFile(QString path, size_type file_size, int index, float progress=0., int priority=1) {
|
return root;
|
||||||
Q_ASSERT(root->isDir());
|
}
|
||||||
path = QDir::cleanPath(path);
|
|
||||||
//Q_ASSERT(path.startsWith(root->path()));
|
bool removeFromFS(QString saveDir) {
|
||||||
QString relative_path = path.remove(0, root->path().size());
|
if(!QFile::exists(saveDir+QDir::separator()+root->path())) return true;
|
||||||
if(relative_path.at(0) ==QDir::separator())
|
bool success = root->removeFromFS(saveDir);
|
||||||
relative_path.remove(0, 1);
|
QDir root_dir(root->path());
|
||||||
QStringList fileNames = relative_path.split(QDir::separator());
|
root_dir.rmdir(saveDir+QDir::separator()+root->path());
|
||||||
torrent_file *dad = root;
|
return success;
|
||||||
unsigned int nb_i = 0;
|
}
|
||||||
unsigned int size = fileNames.size();
|
|
||||||
foreach(const QString &fileName, fileNames) {
|
protected:
|
||||||
++nb_i;
|
void addFile(QString path, size_type file_size, int index, float progress=0., int priority=1) {
|
||||||
if(fileName == ".") continue;
|
Q_ASSERT(root->isDir());
|
||||||
const torrent_file* child = dad->getChild(fileName);
|
path = QDir::cleanPath(path);
|
||||||
if(!child) {
|
//Q_ASSERT(path.startsWith(root->path()));
|
||||||
if(nb_i != size) {
|
QString relative_path = path.remove(0, root->path().size());
|
||||||
// Folder
|
if(relative_path.at(0) ==QDir::separator())
|
||||||
child = dad->addChild(fileName, true);
|
relative_path.remove(0, 1);
|
||||||
} else {
|
QStringList fileNames = relative_path.split(QDir::separator());
|
||||||
// File
|
torrent_file *dad = root;
|
||||||
child = dad->addChild(fileName, false, file_size, index, progress, priority);
|
unsigned int nb_i = 0;
|
||||||
}
|
unsigned int size = fileNames.size();
|
||||||
|
foreach(const QString &fileName, fileNames) {
|
||||||
|
++nb_i;
|
||||||
|
if(fileName == ".") continue;
|
||||||
|
const torrent_file* child = dad->getChild(fileName);
|
||||||
|
if(!child) {
|
||||||
|
if(nb_i != size) {
|
||||||
|
// Folder
|
||||||
|
child = dad->addChild(fileName, true);
|
||||||
|
} else {
|
||||||
|
// File
|
||||||
|
child = dad->addChild(fileName, false, file_size, index, progress, priority);
|
||||||
}
|
}
|
||||||
dad = (torrent_file*)child;
|
|
||||||
}
|
}
|
||||||
|
dad = (torrent_file*)child;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -360,6 +360,123 @@ void bittorrent::loadWebSeeds(QString hash) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QTorrentHandle bittorrent::addMagnetUri(QString magnet_uri, bool resumed) {
|
||||||
|
QTorrentHandle h;
|
||||||
|
QString hash = misc::magnetUriToHash(magnet_uri);
|
||||||
|
if(hash.isEmpty()) {
|
||||||
|
addConsoleMessage(tr("'%1' is not a valid magnet URI.").arg(magnet_uri));
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
if(resumed) {
|
||||||
|
qDebug("Resuming magnet URI: %s", hash.toUtf8().data());
|
||||||
|
} else {
|
||||||
|
qDebug("Adding new magnet URI");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fastResume=false;
|
||||||
|
Q_ASSERT(magnet_uri.startsWith("magnet:"));
|
||||||
|
QDir torrentBackup(misc::qBittorrentPath() + "BT_backup");
|
||||||
|
// Checking if BT_backup Dir exists
|
||||||
|
// create it if it is not
|
||||||
|
if(! torrentBackup.exists()) {
|
||||||
|
if(! torrentBackup.mkpath(torrentBackup.path())) {
|
||||||
|
std::cerr << "Couldn't create the directory: '" << torrentBackup.path().toLocal8Bit().data() << "'\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if torrent is already in download list
|
||||||
|
if(s->find_torrent(sha1_hash(hash.toUtf8().data())).is_valid()) {
|
||||||
|
qDebug("/!\\ Torrent is already in download list");
|
||||||
|
// Update info Bar
|
||||||
|
addConsoleMessage(tr("'%1' is already in download list.", "e.g: 'xxx.avi' is already in download list.").arg(magnet_uri));
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_torrent_params p;
|
||||||
|
//Getting fast resume data if existing
|
||||||
|
std::vector<char> buf;
|
||||||
|
if(resumed) {
|
||||||
|
qDebug("Trying to load fastresume data: %s", (torrentBackup.path()+QDir::separator()+hash+QString(".fastresume")).toLocal8Bit().data());
|
||||||
|
if (load_file((torrentBackup.path()+QDir::separator()+hash+QString(".fastresume")).toLocal8Bit().data(), buf) == 0) {
|
||||||
|
fastResume = true;
|
||||||
|
p.resume_data = &buf;
|
||||||
|
qDebug("Successfuly loaded");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QString savePath = getSavePath(hash);
|
||||||
|
qDebug("addMagnetURI: using save_path: %s", savePath.toUtf8().data());
|
||||||
|
if(defaultTempPath.isEmpty() || (resumed && TorrentPersistentData::isSeed(hash))) {
|
||||||
|
p.save_path = savePath.toLocal8Bit().data();
|
||||||
|
} else {
|
||||||
|
p.save_path = defaultTempPath.toLocal8Bit().data();
|
||||||
|
}
|
||||||
|
// Preallocate all?
|
||||||
|
if(preAllocateAll)
|
||||||
|
p.storage_mode = storage_mode_allocate;
|
||||||
|
else
|
||||||
|
p.storage_mode = storage_mode_sparse;
|
||||||
|
// Start in pause
|
||||||
|
//p.paused = true;
|
||||||
|
p.duplicate_is_error = false; // Already checked
|
||||||
|
p.auto_managed = false; // Because it is added in paused state
|
||||||
|
// Adding torrent to bittorrent session
|
||||||
|
try {
|
||||||
|
h = QTorrentHandle(add_magnet_uri(*s, magnet_uri.toStdString(), p));
|
||||||
|
}catch(std::exception e){
|
||||||
|
qDebug("Error: %s", e.what());
|
||||||
|
}
|
||||||
|
// Check if it worked
|
||||||
|
if(!h.is_valid()) {
|
||||||
|
// No need to keep on, it failed.
|
||||||
|
qDebug("/!\\ Error: Invalid handle");
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
Q_ASSERT(h.hash() == hash);
|
||||||
|
// Connections limit per torrent
|
||||||
|
h.set_max_connections(maxConnecsPerTorrent);
|
||||||
|
// Uploads limit per torrent
|
||||||
|
h.set_max_uploads(maxUploadsPerTorrent);
|
||||||
|
// Load filtered files
|
||||||
|
if(resumed) {
|
||||||
|
// Load custom url seeds
|
||||||
|
loadWebSeeds(hash);
|
||||||
|
// Load speed limit from hard drive
|
||||||
|
loadTorrentSpeedLimits(hash);
|
||||||
|
// Load trackers
|
||||||
|
loadTrackerFile(hash);
|
||||||
|
// XXX: only when resuming because torrentAddition dialog is not supported yet
|
||||||
|
loadFilesPriorities(h);
|
||||||
|
} else {
|
||||||
|
// Sequential download
|
||||||
|
if(TorrentTempData::hasTempData(hash)) {
|
||||||
|
qDebug("addMagnetUri: Setting download as sequential (from tmp data)");
|
||||||
|
h.set_sequential_download(TorrentTempData::isSequential(hash));
|
||||||
|
}
|
||||||
|
// Save persistent data for new torrent
|
||||||
|
Q_ASSERT(h.is_valid());
|
||||||
|
qDebug("addMagnetUri: hash: %s", h.hash().toUtf8().data());
|
||||||
|
TorrentPersistentData::saveTorrentPersistentData(h, true);
|
||||||
|
qDebug("Persistent data saved");
|
||||||
|
// Save save_path
|
||||||
|
if(!defaultTempPath.isEmpty()) {
|
||||||
|
qDebug("addMagnetUri: Saving save_path in persistent data: %s", savePath.toUtf8().data());
|
||||||
|
TorrentPersistentData::saveSavePath(hash, savePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!addInPause && !fastResume) {
|
||||||
|
// Start torrent because it was added in paused state
|
||||||
|
h.resume();
|
||||||
|
}
|
||||||
|
// Send torrent addition signal
|
||||||
|
if(fastResume)
|
||||||
|
addConsoleMessage(tr("'%1' resumed. (fast resume)", "'/home/y/xxx.torrent' was resumed. (fast resume)").arg(magnet_uri));
|
||||||
|
else
|
||||||
|
addConsoleMessage(tr("'%1' added to download list.", "'/home/y/xxx.torrent' was added to download list.").arg(magnet_uri));
|
||||||
|
emit addedTorrent(h);
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
// Add a torrent to the bittorrent session
|
// Add a torrent to the bittorrent session
|
||||||
QTorrentHandle bittorrent::addTorrent(QString path, bool fromScanDir, QString from_url, bool resumed) {
|
QTorrentHandle bittorrent::addTorrent(QString path, bool fromScanDir, QString from_url, bool resumed) {
|
||||||
QTorrentHandle h;
|
QTorrentHandle h;
|
||||||
|
@ -406,13 +523,7 @@ QTorrentHandle bittorrent::addTorrent(QString path, bool fromScanDir, QString fr
|
||||||
qDebug(" -> Hash: %s", misc::toString(t->info_hash()).c_str());
|
qDebug(" -> Hash: %s", misc::toString(t->info_hash()).c_str());
|
||||||
qDebug(" -> Name: %s", t->name().c_str());
|
qDebug(" -> Name: %s", t->name().c_str());
|
||||||
hash = misc::toQString(t->info_hash());
|
hash = misc::toQString(t->info_hash());
|
||||||
if(file.startsWith(torrentBackup.path())) {
|
|
||||||
QFileInfo fi(file);
|
|
||||||
QString old_hash = fi.baseName();
|
|
||||||
if(old_hash != hash){
|
|
||||||
qDebug("* ERROR: Strange, hash changed from %s to %s", old_hash.toLocal8Bit().data(), hash.toLocal8Bit().data());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Check if torrent is already in download list
|
// Check if torrent is already in download list
|
||||||
if(s->find_torrent(t->info_hash()).is_valid()) {
|
if(s->find_torrent(t->info_hash()).is_valid()) {
|
||||||
qDebug("/!\\ Torrent is already in download list");
|
qDebug("/!\\ Torrent is already in download list");
|
||||||
|
@ -726,7 +837,7 @@ void bittorrent::loadTorrentSpeedLimits(QString hash) {
|
||||||
// Read pieces priorities from hard disk
|
// Read pieces priorities from hard disk
|
||||||
// and ask QTorrentHandle to consider them
|
// and ask QTorrentHandle to consider them
|
||||||
void bittorrent::loadFilesPriorities(QTorrentHandle &h) {
|
void bittorrent::loadFilesPriorities(QTorrentHandle &h) {
|
||||||
qDebug("Applying pieces priorities");
|
qDebug("Applying files priority");
|
||||||
if(!h.is_valid()) {
|
if(!h.is_valid()) {
|
||||||
qDebug("/!\\ Error: Invalid handle");
|
qDebug("/!\\ Error: Invalid handle");
|
||||||
return;
|
return;
|
||||||
|
@ -1142,6 +1253,10 @@ void bittorrent::readAlerts() {
|
||||||
bencode(std::ostream_iterator<char>(out), *p->resume_data);
|
bencode(std::ostream_iterator<char>(out), *p->resume_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (metadata_received_alert* p = dynamic_cast<metadata_received_alert*>(a.get())) {
|
||||||
|
QTorrentHandle h(p->handle);
|
||||||
|
emit metadataReceived(h);
|
||||||
|
}
|
||||||
else if (file_error_alert* p = dynamic_cast<file_error_alert*>(a.get())) {
|
else if (file_error_alert* p = dynamic_cast<file_error_alert*>(a.get())) {
|
||||||
QTorrentHandle h(p->handle);
|
QTorrentHandle h(p->handle);
|
||||||
h.auto_managed(false);
|
h.auto_managed(false);
|
||||||
|
@ -1300,13 +1415,6 @@ void bittorrent::processDownloadedFile(QString url, QString file_path) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void bittorrent::downloadFromURLList(const QStringList& url_list) {
|
|
||||||
qDebug("DownloadFromUrlList");
|
|
||||||
foreach(const QString url, url_list) {
|
|
||||||
downloadFromUrl(url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return current download rate for the BT
|
// Return current download rate for the BT
|
||||||
// session. Payload means that it only take into
|
// session. Payload means that it only take into
|
||||||
// account "useful" part of the rate
|
// account "useful" part of the rate
|
||||||
|
@ -1352,7 +1460,7 @@ void bittorrent::startUpTorrents() {
|
||||||
QStringList fileNames;
|
QStringList fileNames;
|
||||||
QStringList known_torrents = TorrentPersistentData::knownTorrents();
|
QStringList known_torrents = TorrentPersistentData::knownTorrents();
|
||||||
if(isQueueingEnabled()) {
|
if(isQueueingEnabled()) {
|
||||||
QList<QPair<int, QString> > filePaths;
|
QList<QPair<int, QString> > hashes;
|
||||||
foreach(const QString &hash, known_torrents) {
|
foreach(const QString &hash, known_torrents) {
|
||||||
QString filePath;
|
QString filePath;
|
||||||
if(TorrentPersistentData::isMagnet(hash)) {
|
if(TorrentPersistentData::isMagnet(hash)) {
|
||||||
|
@ -1361,21 +1469,27 @@ void bittorrent::startUpTorrents() {
|
||||||
filePath = torrentBackup.path()+QDir::separator()+hash+".torrent";
|
filePath = torrentBackup.path()+QDir::separator()+hash+".torrent";
|
||||||
}
|
}
|
||||||
int prio = TorrentPersistentData::getPriority(hash);
|
int prio = TorrentPersistentData::getPriority(hash);
|
||||||
misc::insertSort2<QString>(filePaths, qMakePair(prio, filePath));
|
misc::insertSort2<QString>(hashes, qMakePair(prio, hash));
|
||||||
}
|
}
|
||||||
// Resume downloads
|
// Resume downloads
|
||||||
QPair<int, QString> fileName;
|
QPair<int, QString> couple;
|
||||||
foreach(fileName, filePaths) {
|
foreach(couple, hashes) {
|
||||||
addTorrent(fileName.second, false, QString(), true);
|
QString hash = couple.second;
|
||||||
|
qDebug("Starting up torrent %s", hash.toUtf8().data());
|
||||||
|
if(TorrentPersistentData::isMagnet(hash)) {
|
||||||
|
addMagnetUri(TorrentPersistentData::getMagnetUri(hash), true);
|
||||||
|
} else {
|
||||||
|
addTorrent(torrentBackup.path()+QDir::separator()+hash+".torrent", false, QString(), true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
QStringList filePaths;
|
|
||||||
foreach(const QString &fileName, fileNames) {
|
|
||||||
filePaths.append(torrentBackup.path()+QDir::separator()+fileName);
|
|
||||||
}
|
|
||||||
// Resume downloads
|
// Resume downloads
|
||||||
foreach(const QString &fileName, filePaths) {
|
foreach(const QString &hash, known_torrents) {
|
||||||
addTorrent(fileName, false, QString(), true);
|
qDebug("Starting up torrent %s", hash.toUtf8().data());
|
||||||
|
if(TorrentPersistentData::isMagnet(hash))
|
||||||
|
addMagnetUri(TorrentPersistentData::getMagnetUri(hash), true);
|
||||||
|
else
|
||||||
|
addTorrent(torrentBackup.path()+QDir::separator()+hash+".torrent", false, QString(), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
qDebug("Unfinished torrents resumed");
|
qDebug("Unfinished torrents resumed");
|
||||||
|
|
|
@ -111,10 +111,10 @@ class bittorrent : public QObject {
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
QTorrentHandle addTorrent(QString path, bool fromScanDir = false, QString from_url = QString(), bool resumed = false);
|
QTorrentHandle addTorrent(QString path, bool fromScanDir = false, QString from_url = QString(), bool resumed = false);
|
||||||
|
QTorrentHandle addMagnetUri(QString magnet_uri, bool resumed=false);
|
||||||
void loadSessionState();
|
void loadSessionState();
|
||||||
void saveSessionState();
|
void saveSessionState();
|
||||||
void downloadFromUrl(QString url);
|
void downloadFromUrl(QString url);
|
||||||
void downloadFromURLList(const QStringList& url_list);
|
|
||||||
void deleteTorrent(QString hash, bool permanent = false);
|
void deleteTorrent(QString hash, bool permanent = false);
|
||||||
void startUpTorrents();
|
void startUpTorrents();
|
||||||
/* Needed by Web UI */
|
/* Needed by Web UI */
|
||||||
|
@ -185,6 +185,7 @@ class bittorrent : public QObject {
|
||||||
void updateFileSize(QString hash);
|
void updateFileSize(QString hash);
|
||||||
void downloadFromUrlFailure(QString url, QString reason);
|
void downloadFromUrlFailure(QString url, QString reason);
|
||||||
void torrentFinishedChecking(QTorrentHandle& h);
|
void torrentFinishedChecking(QTorrentHandle& h);
|
||||||
|
void metadataReceived(QTorrentHandle &h);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -53,8 +53,8 @@ DownloadingTorrents::DownloadingTorrents(QObject *parent, bittorrent *BTSession)
|
||||||
actionSet_download_limit->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png")));
|
actionSet_download_limit->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png")));
|
||||||
actionDelete_Permanently->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/delete_perm.png")));
|
actionDelete_Permanently->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/delete_perm.png")));
|
||||||
actionTorrent_Properties->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/properties.png")));
|
actionTorrent_Properties->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/properties.png")));
|
||||||
// tabBottom->setTabIcon(0, QIcon(QString::fromUtf8(":/Icons/oxygen/log.png")));
|
// tabBottom->setTabIcon(0, QIcon(QString::fromUtf8(":/Icons/oxygen/log.png")));
|
||||||
// tabBottom->setTabIcon(1, QIcon(QString::fromUtf8(":/Icons/oxygen/filter.png")));
|
// tabBottom->setTabIcon(1, QIcon(QString::fromUtf8(":/Icons/oxygen/filter.png")));
|
||||||
|
|
||||||
// Set Download list model
|
// Set Download list model
|
||||||
DLListModel = new QStandardItemModel(0,10);
|
DLListModel = new QStandardItemModel(0,10);
|
||||||
|
@ -79,6 +79,7 @@ DownloadingTorrents::DownloadingTorrents(QObject *parent, bittorrent *BTSession)
|
||||||
loadHiddenColumns();
|
loadHiddenColumns();
|
||||||
|
|
||||||
connect(BTSession, SIGNAL(torrentFinishedChecking(QTorrentHandle&)), this, SLOT(sortProgressColumn(QTorrentHandle&)));
|
connect(BTSession, SIGNAL(torrentFinishedChecking(QTorrentHandle&)), this, SLOT(sortProgressColumn(QTorrentHandle&)));
|
||||||
|
connect(BTSession, SIGNAL(metadataReceived(QTorrentHandle&)), this, SLOT(updateMetadata(QTorrentHandle&)));
|
||||||
|
|
||||||
// Load last columns width for download list
|
// Load last columns width for download list
|
||||||
if(!loadColWidthDLList()) {
|
if(!loadColWidthDLList()) {
|
||||||
|
@ -173,10 +174,12 @@ void DownloadingTorrents::showProperties(const QModelIndex &index) {
|
||||||
|
|
||||||
void DownloadingTorrents::showPropertiesFromHash(QString hash) {
|
void DownloadingTorrents::showPropertiesFromHash(QString hash) {
|
||||||
QTorrentHandle h = BTSession->getTorrentHandle(hash);
|
QTorrentHandle h = BTSession->getTorrentHandle(hash);
|
||||||
properties *prop = new properties(this, BTSession, h);
|
if(h.is_valid() && h.has_metadata()) {
|
||||||
connect(prop, SIGNAL(filteredFilesChanged(QString)), this, SLOT(updateFileSizeAndProgress(QString)));
|
properties *prop = new properties(this, BTSession, h);
|
||||||
connect(prop, SIGNAL(trackersChanged(QString)), BTSession, SLOT(saveTrackerFile(QString)));
|
connect(prop, SIGNAL(filteredFilesChanged(QString)), this, SLOT(updateFileSizeAndProgress(QString)));
|
||||||
prop->show();
|
connect(prop, SIGNAL(trackersChanged(QString)), BTSession, SLOT(saveTrackerFile(QString)));
|
||||||
|
prop->show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove a torrent from the download list but NOT from the BT Session
|
// Remove a torrent from the download list but NOT from the BT Session
|
||||||
|
@ -228,14 +231,14 @@ void DownloadingTorrents::propertiesSelection(){
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadingTorrents::forceRecheck() {
|
void DownloadingTorrents::forceRecheck() {
|
||||||
QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes();
|
QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes();
|
||||||
foreach(const QModelIndex &index, selectedIndexes){
|
foreach(const QModelIndex &index, selectedIndexes){
|
||||||
if(index.column() == NAME){
|
if(index.column() == NAME){
|
||||||
QString hash = DLListModel->data(DLListModel->index(index.row(), HASH)).toString();
|
QString hash = DLListModel->data(DLListModel->index(index.row(), HASH)).toString();
|
||||||
QTorrentHandle h = BTSession->getTorrentHandle(hash);
|
QTorrentHandle h = BTSession->getTorrentHandle(hash);
|
||||||
h.force_recheck();
|
h.force_recheck();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadingTorrents::displayDLListMenu(const QPoint&) {
|
void DownloadingTorrents::displayDLListMenu(const QPoint&) {
|
||||||
|
@ -243,13 +246,19 @@ void DownloadingTorrents::displayDLListMenu(const QPoint&) {
|
||||||
// Enable/disable pause/start action given the DL state
|
// Enable/disable pause/start action given the DL state
|
||||||
QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes();
|
QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes();
|
||||||
bool has_pause = false, has_start = false, has_preview = false;
|
bool has_pause = false, has_start = false, has_preview = false;
|
||||||
|
bool show_properties_entry = false;
|
||||||
|
QTorrentHandle h;
|
||||||
|
qDebug("Displaying menu");
|
||||||
foreach(const QModelIndex &index, selectedIndexes) {
|
foreach(const QModelIndex &index, selectedIndexes) {
|
||||||
if(index.column() == NAME) {
|
if(index.column() == NAME) {
|
||||||
// Get the file name
|
// Get the file name
|
||||||
QString hash = DLListModel->data(DLListModel->index(index.row(), HASH)).toString();
|
QString hash = DLListModel->data(DLListModel->index(index.row(), HASH)).toString();
|
||||||
// Get handle and pause the torrent
|
// Get handle and pause the torrent
|
||||||
QTorrentHandle h = BTSession->getTorrentHandle(hash);
|
h = BTSession->getTorrentHandle(hash);
|
||||||
if(!h.is_valid()) continue;
|
if(!h.is_valid()) continue;
|
||||||
|
if(h.has_metadata()) {
|
||||||
|
show_properties_entry = true;
|
||||||
|
}
|
||||||
if(h.is_paused()) {
|
if(h.is_paused()) {
|
||||||
if(!has_start) {
|
if(!has_start) {
|
||||||
myDLLlistMenu.addAction(actionStart);
|
myDLLlistMenu.addAction(actionStart);
|
||||||
|
@ -261,9 +270,9 @@ void DownloadingTorrents::displayDLListMenu(const QPoint&) {
|
||||||
has_pause = true;
|
has_pause = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(BTSession->isFilePreviewPossible(hash) && !has_preview) {
|
if(h.has_metadata() && BTSession->isFilePreviewPossible(hash) && !has_preview) {
|
||||||
myDLLlistMenu.addAction(actionPreview_file);
|
myDLLlistMenu.addAction(actionPreview_file);
|
||||||
has_preview = true;
|
has_preview = true;
|
||||||
}
|
}
|
||||||
if(has_pause && has_start && has_preview) break;
|
if(has_pause && has_start && has_preview) break;
|
||||||
}
|
}
|
||||||
|
@ -278,7 +287,8 @@ void DownloadingTorrents::displayDLListMenu(const QPoint&) {
|
||||||
myDLLlistMenu.addAction(actionForce_recheck);
|
myDLLlistMenu.addAction(actionForce_recheck);
|
||||||
myDLLlistMenu.addSeparator();
|
myDLLlistMenu.addSeparator();
|
||||||
myDLLlistMenu.addAction(actionOpen_destination_folder);
|
myDLLlistMenu.addAction(actionOpen_destination_folder);
|
||||||
myDLLlistMenu.addAction(actionTorrent_Properties);
|
if(show_properties_entry)
|
||||||
|
myDLLlistMenu.addAction(actionTorrent_Properties);
|
||||||
if(BTSession->isQueueingEnabled()) {
|
if(BTSession->isQueueingEnabled()) {
|
||||||
myDLLlistMenu.addSeparator();
|
myDLLlistMenu.addSeparator();
|
||||||
myDLLlistMenu.addAction(actionIncreasePriority);
|
myDLLlistMenu.addAction(actionIncreasePriority);
|
||||||
|
@ -378,7 +388,7 @@ bool DownloadingTorrents::loadHiddenColumns() {
|
||||||
if(ishidden_list.size() == DLListModel->columnCount()-1) {
|
if(ishidden_list.size() == DLListModel->columnCount()-1) {
|
||||||
unsigned int listSize = ishidden_list.size();
|
unsigned int listSize = ishidden_list.size();
|
||||||
for(unsigned int i=0; i<listSize; ++i){
|
for(unsigned int i=0; i<listSize; ++i){
|
||||||
downloadList->header()->resizeSection(i, ishidden_list.at(i).toInt());
|
downloadList->header()->resizeSection(i, ishidden_list.at(i).toInt());
|
||||||
}
|
}
|
||||||
loaded = true;
|
loaded = true;
|
||||||
}
|
}
|
||||||
|
@ -433,36 +443,36 @@ void DownloadingTorrents::hideOrShowColumnPriority() {
|
||||||
// getter, return the action hide or show whose id is index
|
// getter, return the action hide or show whose id is index
|
||||||
QAction* DownloadingTorrents::getActionHoSCol(int index) {
|
QAction* DownloadingTorrents::getActionHoSCol(int index) {
|
||||||
switch(index) {
|
switch(index) {
|
||||||
case NAME :
|
case NAME :
|
||||||
return actionHOSColName;
|
return actionHOSColName;
|
||||||
break;
|
break;
|
||||||
case SIZE :
|
case SIZE :
|
||||||
return actionHOSColSize;
|
return actionHOSColSize;
|
||||||
break;
|
break;
|
||||||
case PROGRESS :
|
case PROGRESS :
|
||||||
return actionHOSColProgress;
|
return actionHOSColProgress;
|
||||||
break;
|
break;
|
||||||
case DLSPEED :
|
case DLSPEED :
|
||||||
return actionHOSColDownSpeed;
|
return actionHOSColDownSpeed;
|
||||||
break;
|
break;
|
||||||
case UPSPEED :
|
case UPSPEED :
|
||||||
return actionHOSColUpSpeed;
|
return actionHOSColUpSpeed;
|
||||||
break;
|
break;
|
||||||
case SEEDSLEECH :
|
case SEEDSLEECH :
|
||||||
return actionHOSColSeedersLeechers;
|
return actionHOSColSeedersLeechers;
|
||||||
break;
|
break;
|
||||||
case RATIO :
|
case RATIO :
|
||||||
return actionHOSColRatio;
|
return actionHOSColRatio;
|
||||||
break;
|
break;
|
||||||
case ETA :
|
case ETA :
|
||||||
return actionHOSColEta;
|
return actionHOSColEta;
|
||||||
break;
|
break;
|
||||||
case PRIORITY :
|
case PRIORITY :
|
||||||
return actionHOSColPriority;
|
return actionHOSColPriority;
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList DownloadingTorrents::getSelectedTorrents(bool only_one) const{
|
QStringList DownloadingTorrents::getSelectedTorrents(bool only_one) const{
|
||||||
|
@ -479,96 +489,106 @@ QStringList DownloadingTorrents::getSelectedTorrents(bool only_one) const{
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DownloadingTorrents::updateMetadata(QTorrentHandle &h) {
|
||||||
|
QString hash = h.hash();
|
||||||
|
int row = getRowFromHash(hash);
|
||||||
|
if(row != -1) {
|
||||||
|
qDebug("Updating torrent metadata in download list");
|
||||||
|
DLListModel->setData(DLListModel->index(row, NAME), QVariant(h.name()));
|
||||||
|
DLListModel->setData(DLListModel->index(row, SIZE), QVariant((qlonglong)h.actual_size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// get information from torrent handles and
|
// get information from torrent handles and
|
||||||
// update download list accordingly
|
// update download list accordingly
|
||||||
bool DownloadingTorrents::updateTorrent(QTorrentHandle h) {
|
bool DownloadingTorrents::updateTorrent(QTorrentHandle h) {
|
||||||
bool added = false;
|
bool added = false;
|
||||||
try{
|
try{
|
||||||
QString hash = h.hash();
|
QString hash = h.hash();
|
||||||
int row = getRowFromHash(hash);
|
int row = getRowFromHash(hash);
|
||||||
if(row == -1) {
|
if(row == -1) {
|
||||||
qDebug("Info: Could not find filename in download list, adding it...");
|
qDebug("Info: Could not find filename in download list, adding it...");
|
||||||
addTorrent(hash);
|
addTorrent(hash);
|
||||||
row = getRowFromHash(hash);
|
row = getRowFromHash(hash);
|
||||||
added = true;
|
added = true;
|
||||||
}
|
}
|
||||||
Q_ASSERT(row != -1);
|
Q_ASSERT(row != -1);
|
||||||
// Update Priority
|
// Update Priority
|
||||||
if(BTSession->isQueueingEnabled()) {
|
if(BTSession->isQueueingEnabled()) {
|
||||||
DLListModel->setData(DLListModel->index(row, PRIORITY), QVariant((int)BTSession->getDlTorrentPriority(hash)));
|
DLListModel->setData(DLListModel->index(row, PRIORITY), QVariant((int)BTSession->getDlTorrentPriority(hash)));
|
||||||
if(h.is_queued()) {
|
if(h.is_queued()) {
|
||||||
if(h.state() == torrent_status::checking_files || h.state() == torrent_status::queued_for_checking) {
|
if(h.state() == torrent_status::checking_files || h.state() == torrent_status::queued_for_checking) {
|
||||||
DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/oxygen/time.png"))), Qt::DecorationRole);
|
|
||||||
if(!downloadList->isColumnHidden(PROGRESS)) {
|
|
||||||
DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)h.progress()));
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/queued.png"))), Qt::DecorationRole);
|
|
||||||
if(!downloadList->isColumnHidden(ETA)) {
|
|
||||||
DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Reset speeds and seeds/leech
|
|
||||||
DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)0.));
|
|
||||||
DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)0.));
|
|
||||||
DLListModel->setData(DLListModel->index(row, SEEDSLEECH), QVariant("0/0"));
|
|
||||||
setRowColor(row, QString::fromUtf8("grey"));
|
|
||||||
return added;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!downloadList->isColumnHidden(PROGRESS))
|
|
||||||
DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)h.progress()));
|
|
||||||
// No need to update a paused torrent
|
|
||||||
if(h.is_paused()) return added;
|
|
||||||
// Parse download state
|
|
||||||
// Setting download state
|
|
||||||
switch(h.state()) {
|
|
||||||
case torrent_status::checking_files:
|
|
||||||
case torrent_status::queued_for_checking:
|
|
||||||
DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/oxygen/time.png"))), Qt::DecorationRole);
|
DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/oxygen/time.png"))), Qt::DecorationRole);
|
||||||
setRowColor(row, QString::fromUtf8("grey"));
|
if(!downloadList->isColumnHidden(PROGRESS)) {
|
||||||
break;
|
DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)h.progress()));
|
||||||
case torrent_status::downloading:
|
|
||||||
case torrent_status::downloading_metadata:
|
|
||||||
if(h.download_payload_rate() > 0) {
|
|
||||||
DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png"))), Qt::DecorationRole);
|
|
||||||
if(!downloadList->isColumnHidden(ETA)) {
|
|
||||||
DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)BTSession->getETA(hash)));
|
|
||||||
}
|
|
||||||
setRowColor(row, QString::fromUtf8("green"));
|
|
||||||
}else{
|
|
||||||
DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/stalled.png"))), Qt::DecorationRole);
|
|
||||||
if(!downloadList->isColumnHidden(ETA)) {
|
|
||||||
DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1));
|
|
||||||
}
|
|
||||||
setRowColor(row, QApplication::palette().color(QPalette::WindowText));
|
|
||||||
}
|
}
|
||||||
if(!downloadList->isColumnHidden(DLSPEED)) {
|
}else {
|
||||||
DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)h.download_payload_rate()));
|
DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/queued.png"))), Qt::DecorationRole);
|
||||||
}
|
|
||||||
if(!downloadList->isColumnHidden(UPSPEED)) {
|
|
||||||
DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)h.upload_payload_rate()));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if(!downloadList->isColumnHidden(ETA)) {
|
if(!downloadList->isColumnHidden(ETA)) {
|
||||||
DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1));
|
DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// Reset speeds and seeds/leech
|
||||||
|
DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)0.));
|
||||||
|
DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)0.));
|
||||||
|
DLListModel->setData(DLListModel->index(row, SEEDSLEECH), QVariant("0/0"));
|
||||||
|
setRowColor(row, QString::fromUtf8("grey"));
|
||||||
|
return added;
|
||||||
}
|
}
|
||||||
if(!downloadList->isColumnHidden(SEEDSLEECH)) {
|
}
|
||||||
QString tmp = misc::toQString(h.num_seeds(), true);
|
if(!downloadList->isColumnHidden(PROGRESS))
|
||||||
if(h.num_complete() >= 0)
|
DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)h.progress()));
|
||||||
tmp.append(QString("(")+misc::toQString(h.num_complete())+QString(")"));
|
// No need to update a paused torrent
|
||||||
tmp.append(QString("/")+misc::toQString(h.num_peers() - h.num_seeds(), true));
|
if(h.is_paused()) return added;
|
||||||
if(h.num_incomplete() >= 0)
|
// Parse download state
|
||||||
tmp.append(QString("(")+misc::toQString(h.num_incomplete())+QString(")"));
|
// Setting download state
|
||||||
DLListModel->setData(DLListModel->index(row, SEEDSLEECH), QVariant(tmp));
|
switch(h.state()) {
|
||||||
|
case torrent_status::checking_files:
|
||||||
|
case torrent_status::queued_for_checking:
|
||||||
|
DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/oxygen/time.png"))), Qt::DecorationRole);
|
||||||
|
setRowColor(row, QString::fromUtf8("grey"));
|
||||||
|
break;
|
||||||
|
case torrent_status::downloading:
|
||||||
|
case torrent_status::downloading_metadata:
|
||||||
|
if(h.download_payload_rate() > 0) {
|
||||||
|
DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png"))), Qt::DecorationRole);
|
||||||
|
if(!downloadList->isColumnHidden(ETA)) {
|
||||||
|
DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)BTSession->getETA(hash)));
|
||||||
|
}
|
||||||
|
setRowColor(row, QString::fromUtf8("green"));
|
||||||
|
}else{
|
||||||
|
DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/stalled.png"))), Qt::DecorationRole);
|
||||||
|
if(!downloadList->isColumnHidden(ETA)) {
|
||||||
|
DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1));
|
||||||
|
}
|
||||||
|
setRowColor(row, QApplication::palette().color(QPalette::WindowText));
|
||||||
}
|
}
|
||||||
if(!downloadList->isColumnHidden(RATIO)) {
|
if(!downloadList->isColumnHidden(DLSPEED)) {
|
||||||
DLListModel->setData(DLListModel->index(row, RATIO), QVariant(misc::toQString(BTSession->getRealRatio(hash))));
|
DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)h.download_payload_rate()));
|
||||||
}
|
}
|
||||||
}catch(invalid_handle e) {}
|
if(!downloadList->isColumnHidden(UPSPEED)) {
|
||||||
return added;
|
DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)h.upload_payload_rate()));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if(!downloadList->isColumnHidden(ETA)) {
|
||||||
|
DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!downloadList->isColumnHidden(SEEDSLEECH)) {
|
||||||
|
QString tmp = misc::toQString(h.num_seeds(), true);
|
||||||
|
if(h.num_complete() >= 0)
|
||||||
|
tmp.append(QString("(")+misc::toQString(h.num_complete())+QString(")"));
|
||||||
|
tmp.append(QString("/")+misc::toQString(h.num_peers() - h.num_seeds(), true));
|
||||||
|
if(h.num_incomplete() >= 0)
|
||||||
|
tmp.append(QString("(")+misc::toQString(h.num_incomplete())+QString(")"));
|
||||||
|
DLListModel->setData(DLListModel->index(row, SEEDSLEECH), QVariant(tmp));
|
||||||
|
}
|
||||||
|
if(!downloadList->isColumnHidden(RATIO)) {
|
||||||
|
DLListModel->setData(DLListModel->index(row, RATIO), QVariant(misc::toQString(BTSession->getRealRatio(hash))));
|
||||||
|
}
|
||||||
|
}catch(invalid_handle e) {}
|
||||||
|
return added;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadingTorrents::addTorrent(QString hash) {
|
void DownloadingTorrents::addTorrent(QString hash) {
|
||||||
|
@ -657,17 +677,17 @@ void DownloadingTorrents::toggleDownloadListSortOrder(int index) {
|
||||||
sortOrder = (Qt::SortOrder)!(bool)downloadList->header()->sortIndicatorOrder();
|
sortOrder = (Qt::SortOrder)!(bool)downloadList->header()->sortIndicatorOrder();
|
||||||
}
|
}
|
||||||
switch(index) {
|
switch(index) {
|
||||||
case SIZE:
|
case SIZE:
|
||||||
case ETA:
|
case ETA:
|
||||||
case UPSPEED:
|
case UPSPEED:
|
||||||
case DLSPEED:
|
case DLSPEED:
|
||||||
case PROGRESS:
|
case PROGRESS:
|
||||||
case PRIORITY:
|
case PRIORITY:
|
||||||
case RATIO:
|
case RATIO:
|
||||||
sortDownloadListFloat(index, sortOrder);
|
sortDownloadListFloat(index, sortOrder);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sortDownloadListString(index, sortOrder);
|
sortDownloadListString(index, sortOrder);
|
||||||
}
|
}
|
||||||
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
|
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
|
||||||
QString sortOrderLetter;
|
QString sortOrderLetter;
|
||||||
|
@ -699,16 +719,16 @@ void DownloadingTorrents::sortDownloadList(int index, Qt::SortOrder sortOrder) {
|
||||||
downloadList->header()->setSortIndicator(index, sortOrder);
|
downloadList->header()->setSortIndicator(index, sortOrder);
|
||||||
}
|
}
|
||||||
switch(index) {
|
switch(index) {
|
||||||
case SIZE:
|
case SIZE:
|
||||||
case ETA:
|
case ETA:
|
||||||
case UPSPEED:
|
case UPSPEED:
|
||||||
case DLSPEED:
|
case DLSPEED:
|
||||||
case PRIORITY:
|
case PRIORITY:
|
||||||
case PROGRESS:
|
case PROGRESS:
|
||||||
sortDownloadListFloat(index, sortOrder);
|
sortDownloadListFloat(index, sortOrder);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sortDownloadListString(index, sortOrder);
|
sortDownloadListString(index, sortOrder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -761,7 +781,7 @@ bool DownloadingTorrents::loadColWidthDLList() {
|
||||||
}
|
}
|
||||||
unsigned int listSize = width_list.size();
|
unsigned int listSize = width_list.size();
|
||||||
for(unsigned int i=0; i<listSize; ++i) {
|
for(unsigned int i=0; i<listSize; ++i) {
|
||||||
downloadList->header()->resizeSection(i, width_list.at(i).toInt());
|
downloadList->header()->resizeSection(i, width_list.at(i).toInt());
|
||||||
}
|
}
|
||||||
QVariantList visualIndexes = settings.value(QString::fromUtf8("DownloadListVisualIndexes"), QVariantList()).toList();
|
QVariantList visualIndexes = settings.value(QString::fromUtf8("DownloadListVisualIndexes"), QVariantList()).toList();
|
||||||
if(visualIndexes.size() != DLListModel->columnCount()-1) {
|
if(visualIndexes.size() != DLListModel->columnCount()-1) {
|
||||||
|
|
|
@ -103,6 +103,7 @@ class DownloadingTorrents : public QWidget, public Ui::downloading{
|
||||||
void sortProgressColumn(QTorrentHandle& h);
|
void sortProgressColumn(QTorrentHandle& h);
|
||||||
void loadLastSortedColumn();
|
void loadLastSortedColumn();
|
||||||
void addTorrent(QString hash);
|
void addTorrent(QString hash);
|
||||||
|
void updateMetadata(QTorrentHandle &h);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
423
src/misc.h
423
src/misc.h
|
@ -47,231 +47,244 @@ using namespace libtorrent;
|
||||||
|
|
||||||
/* Miscellaneaous functions that can be useful */
|
/* Miscellaneaous functions that can be useful */
|
||||||
class misc : public QObject{
|
class misc : public QObject{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Convert any type of variable to C++ String
|
// Convert any type of variable to C++ String
|
||||||
// convert=true will convert -1 to 0
|
// convert=true will convert -1 to 0
|
||||||
template <class T> static std::string toString(const T& x, bool convert=false) {
|
template <class T> static std::string toString(const T& x, bool convert=false) {
|
||||||
std::ostringstream o;
|
std::ostringstream o;
|
||||||
if(!(o<<x)) {
|
if(!(o<<x)) {
|
||||||
throw std::runtime_error("::toString()");
|
throw std::runtime_error("::toString()");
|
||||||
|
}
|
||||||
|
if(o.str() == "-1" && convert)
|
||||||
|
return "0";
|
||||||
|
return o.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T> static QString toQString(const T& x, bool convert=false) {
|
||||||
|
std::ostringstream o;
|
||||||
|
if(!(o<<x)) {
|
||||||
|
throw std::runtime_error("::toString()");
|
||||||
|
}
|
||||||
|
if(o.str() == "-1" && convert)
|
||||||
|
return QString::fromUtf8("0");
|
||||||
|
return QString::fromUtf8(o.str().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T> static QByteArray toQByteArray(const T& x, bool convert=false) {
|
||||||
|
std::ostringstream o;
|
||||||
|
if(!(o<<x)) {
|
||||||
|
throw std::runtime_error("::toString()");
|
||||||
|
}
|
||||||
|
if(o.str() == "-1" && convert)
|
||||||
|
return "0";
|
||||||
|
return QByteArray(o.str().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert C++ string to any type of variable
|
||||||
|
template <class T> static T fromString(const std::string& s) {
|
||||||
|
T x;
|
||||||
|
std::istringstream i(s);
|
||||||
|
if(!(i>>x)) {
|
||||||
|
throw std::runtime_error("::fromString()");
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return best userfriendly storage unit (B, KiB, MiB, GiB, TiB)
|
||||||
|
// use Binary prefix standards from IEC 60027-2
|
||||||
|
// see http://en.wikipedia.org/wiki/Kilobyte
|
||||||
|
// value must be given in bytes
|
||||||
|
static QString friendlyUnit(float val) {
|
||||||
|
if(val < 0)
|
||||||
|
return tr("Unknown", "Unknown (size)");
|
||||||
|
const QString units[5] = {tr("B", "bytes"), tr("KiB", "kibibytes (1024 bytes)"), tr("MiB", "mebibytes (1024 kibibytes)"), tr("GiB", "gibibytes (1024 mibibytes)"), tr("TiB", "tebibytes (1024 gibibytes)")};
|
||||||
|
char i = 0;
|
||||||
|
while(val > 1024. && i++<6)
|
||||||
|
val /= 1024.;
|
||||||
|
return QString(QByteArray::number(val, 'f', 1)) + units[(int)i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isPreviewable(QString extension){
|
||||||
|
extension = extension.toUpper();
|
||||||
|
if(extension == "AVI") return true;
|
||||||
|
if(extension == "MP3") return true;
|
||||||
|
if(extension == "OGG") return true;
|
||||||
|
if(extension == "OGM") return true;
|
||||||
|
if(extension == "WMV") return true;
|
||||||
|
if(extension == "WMA") return true;
|
||||||
|
if(extension == "MPEG") return true;
|
||||||
|
if(extension == "MPG") return true;
|
||||||
|
if(extension == "ASF") return true;
|
||||||
|
if(extension == "QT") return true;
|
||||||
|
if(extension == "RM") return true;
|
||||||
|
if(extension == "RMVB") return true;
|
||||||
|
if(extension == "RMV") return true;
|
||||||
|
if(extension == "SWF") return true;
|
||||||
|
if(extension == "FLV") return true;
|
||||||
|
if(extension == "WAV") return true;
|
||||||
|
if(extension == "MOV") return true;
|
||||||
|
if(extension == "VOB") return true;
|
||||||
|
if(extension == "MID") return true;
|
||||||
|
if(extension == "AC3") return true;
|
||||||
|
if(extension == "MP4") return true;
|
||||||
|
if(extension == "MP2") return true;
|
||||||
|
if(extension == "AVI") return true;
|
||||||
|
if(extension == "FLAC") return true;
|
||||||
|
if(extension == "AU") return true;
|
||||||
|
if(extension == "MPE") return true;
|
||||||
|
if(extension == "MOV") return true;
|
||||||
|
if(extension == "MKV") return true;
|
||||||
|
if(extension == "AIF") return true;
|
||||||
|
if(extension == "AIFF") return true;
|
||||||
|
if(extension == "AIFC") return true;
|
||||||
|
if(extension == "RA") return true;
|
||||||
|
if(extension == "RAM") return true;
|
||||||
|
if(extension == "M4P") return true;
|
||||||
|
if(extension == "M4A") return true;
|
||||||
|
if(extension == "3GP") return true;
|
||||||
|
if(extension == "AAC") return true;
|
||||||
|
if(extension == "SWA") return true;
|
||||||
|
if(extension == "MPC") return true;
|
||||||
|
if(extension == "MPP") return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return qBittorrent config path
|
||||||
|
static QString qBittorrentPath() {
|
||||||
|
QString qBtPath = QDir::homePath()+QDir::separator()+QString::fromUtf8(".qbittorrent") + QDir::separator();
|
||||||
|
// Create dir if it does not exist
|
||||||
|
if(!QFile::exists(qBtPath)){
|
||||||
|
QDir dir(qBtPath);
|
||||||
|
dir.mkpath(qBtPath);
|
||||||
|
}
|
||||||
|
return qBtPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fixTrackersTiers(std::vector<announce_entry> trackers) {
|
||||||
|
unsigned int nbTrackers = trackers.size();
|
||||||
|
for(unsigned int i=0; i<nbTrackers; ++i) {
|
||||||
|
trackers[i].tier = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insertion sort, used instead of bubble sort because it is
|
||||||
|
// approx. 5 times faster.
|
||||||
|
template <class T> static void insertSort(QList<QPair<int, T> > &list, const QPair<int, T>& value, Qt::SortOrder sortOrder) {
|
||||||
|
int i = 0;
|
||||||
|
if(sortOrder == Qt::AscendingOrder) {
|
||||||
|
while(i < list.size() and value.second > list.at(i).second) {
|
||||||
|
++i;
|
||||||
}
|
}
|
||||||
if(o.str() == "-1" && convert)
|
}else{
|
||||||
return "0";
|
while(i < list.size() and value.second < list.at(i).second) {
|
||||||
return o.str();
|
++i;
|
||||||
}
|
|
||||||
|
|
||||||
template <class T> static QString toQString(const T& x, bool convert=false) {
|
|
||||||
std::ostringstream o;
|
|
||||||
if(!(o<<x)) {
|
|
||||||
throw std::runtime_error("::toString()");
|
|
||||||
}
|
|
||||||
if(o.str() == "-1" && convert)
|
|
||||||
return QString::fromUtf8("0");
|
|
||||||
return QString::fromUtf8(o.str().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T> static QByteArray toQByteArray(const T& x, bool convert=false) {
|
|
||||||
std::ostringstream o;
|
|
||||||
if(!(o<<x)) {
|
|
||||||
throw std::runtime_error("::toString()");
|
|
||||||
}
|
|
||||||
if(o.str() == "-1" && convert)
|
|
||||||
return "0";
|
|
||||||
return QByteArray(o.str().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert C++ string to any type of variable
|
|
||||||
template <class T> static T fromString(const std::string& s) {
|
|
||||||
T x;
|
|
||||||
std::istringstream i(s);
|
|
||||||
if(!(i>>x)) {
|
|
||||||
throw std::runtime_error("::fromString()");
|
|
||||||
}
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return best userfriendly storage unit (B, KiB, MiB, GiB, TiB)
|
|
||||||
// use Binary prefix standards from IEC 60027-2
|
|
||||||
// see http://en.wikipedia.org/wiki/Kilobyte
|
|
||||||
// value must be given in bytes
|
|
||||||
static QString friendlyUnit(float val) {
|
|
||||||
if(val < 0)
|
|
||||||
return tr("Unknown", "Unknown (size)");
|
|
||||||
const QString units[5] = {tr("B", "bytes"), tr("KiB", "kibibytes (1024 bytes)"), tr("MiB", "mebibytes (1024 kibibytes)"), tr("GiB", "gibibytes (1024 mibibytes)"), tr("TiB", "tebibytes (1024 gibibytes)")};
|
|
||||||
char i = 0;
|
|
||||||
while(val > 1024. && i++<6)
|
|
||||||
val /= 1024.;
|
|
||||||
return QString(QByteArray::number(val, 'f', 1)) + units[(int)i];
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isPreviewable(QString extension){
|
|
||||||
extension = extension.toUpper();
|
|
||||||
if(extension == "AVI") return true;
|
|
||||||
if(extension == "MP3") return true;
|
|
||||||
if(extension == "OGG") return true;
|
|
||||||
if(extension == "OGM") return true;
|
|
||||||
if(extension == "WMV") return true;
|
|
||||||
if(extension == "WMA") return true;
|
|
||||||
if(extension == "MPEG") return true;
|
|
||||||
if(extension == "MPG") return true;
|
|
||||||
if(extension == "ASF") return true;
|
|
||||||
if(extension == "QT") return true;
|
|
||||||
if(extension == "RM") return true;
|
|
||||||
if(extension == "RMVB") return true;
|
|
||||||
if(extension == "RMV") return true;
|
|
||||||
if(extension == "SWF") return true;
|
|
||||||
if(extension == "FLV") return true;
|
|
||||||
if(extension == "WAV") return true;
|
|
||||||
if(extension == "MOV") return true;
|
|
||||||
if(extension == "VOB") return true;
|
|
||||||
if(extension == "MID") return true;
|
|
||||||
if(extension == "AC3") return true;
|
|
||||||
if(extension == "MP4") return true;
|
|
||||||
if(extension == "MP2") return true;
|
|
||||||
if(extension == "AVI") return true;
|
|
||||||
if(extension == "FLAC") return true;
|
|
||||||
if(extension == "AU") return true;
|
|
||||||
if(extension == "MPE") return true;
|
|
||||||
if(extension == "MOV") return true;
|
|
||||||
if(extension == "MKV") return true;
|
|
||||||
if(extension == "AIF") return true;
|
|
||||||
if(extension == "AIFF") return true;
|
|
||||||
if(extension == "AIFC") return true;
|
|
||||||
if(extension == "RA") return true;
|
|
||||||
if(extension == "RAM") return true;
|
|
||||||
if(extension == "M4P") return true;
|
|
||||||
if(extension == "M4A") return true;
|
|
||||||
if(extension == "3GP") return true;
|
|
||||||
if(extension == "AAC") return true;
|
|
||||||
if(extension == "SWA") return true;
|
|
||||||
if(extension == "MPC") return true;
|
|
||||||
if(extension == "MPP") return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return qBittorrent config path
|
|
||||||
static QString qBittorrentPath() {
|
|
||||||
QString qBtPath = QDir::homePath()+QDir::separator()+QString::fromUtf8(".qbittorrent") + QDir::separator();
|
|
||||||
// Create dir if it does not exist
|
|
||||||
if(!QFile::exists(qBtPath)){
|
|
||||||
QDir dir(qBtPath);
|
|
||||||
dir.mkpath(qBtPath);
|
|
||||||
}
|
|
||||||
return qBtPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fixTrackersTiers(std::vector<announce_entry> trackers) {
|
|
||||||
unsigned int nbTrackers = trackers.size();
|
|
||||||
for(unsigned int i=0; i<nbTrackers; ++i) {
|
|
||||||
trackers[i].tier = i;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
list.insert(i, value);
|
||||||
|
}
|
||||||
|
|
||||||
// Insertion sort, used instead of bubble sort because it is
|
template <class T> static void insertSort2(QList<QPair<int, T> > &list, const QPair<int, T>& value, Qt::SortOrder sortOrder=Qt::AscendingOrder) {
|
||||||
// approx. 5 times faster.
|
int i = 0;
|
||||||
template <class T> static void insertSort(QList<QPair<int, T> > &list, const QPair<int, T>& value, Qt::SortOrder sortOrder) {
|
if(sortOrder == Qt::AscendingOrder) {
|
||||||
int i = 0;
|
while(i < list.size() and value.first > list.at(i).first) {
|
||||||
if(sortOrder == Qt::AscendingOrder) {
|
++i;
|
||||||
while(i < list.size() and value.second > list.at(i).second) {
|
}
|
||||||
++i;
|
}else{
|
||||||
}
|
while(i < list.size() and value.first < list.at(i).first) {
|
||||||
}else{
|
++i;
|
||||||
while(i < list.size() and value.second < list.at(i).second) {
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
list.insert(i, value);
|
|
||||||
}
|
}
|
||||||
|
list.insert(i, value);
|
||||||
|
}
|
||||||
|
|
||||||
template <class T> static void insertSort2(QList<QPair<int, T> > &list, const QPair<int, T>& value, Qt::SortOrder sortOrder=Qt::AscendingOrder) {
|
// Can't use template class for QString because >,< use unicode code for sorting
|
||||||
int i = 0;
|
// which is not what a human would expect when sorting strings.
|
||||||
if(sortOrder == Qt::AscendingOrder) {
|
static void insertSortString(QList<QPair<int, QString> > &list, QPair<int, QString> value, Qt::SortOrder sortOrder) {
|
||||||
while(i < list.size() and value.first > list.at(i).first) {
|
int i = 0;
|
||||||
++i;
|
if(sortOrder == Qt::AscendingOrder) {
|
||||||
}
|
while(i < list.size() and QString::localeAwareCompare(value.second, list.at(i).second) > 0) {
|
||||||
}else{
|
++i;
|
||||||
while(i < list.size() and value.first < list.at(i).first) {
|
}
|
||||||
++i;
|
}else{
|
||||||
}
|
while(i < list.size() and QString::localeAwareCompare(value.second, list.at(i).second) < 0) {
|
||||||
|
++i;
|
||||||
}
|
}
|
||||||
list.insert(i, value);
|
|
||||||
}
|
}
|
||||||
|
list.insert(i, value);
|
||||||
|
}
|
||||||
|
|
||||||
// Can't use template class for QString because >,< use unicode code for sorting
|
static float getPluginVersion(QString filePath) {
|
||||||
// which is not what a human would expect when sorting strings.
|
QFile plugin(filePath);
|
||||||
static void insertSortString(QList<QPair<int, QString> > &list, QPair<int, QString> value, Qt::SortOrder sortOrder) {
|
if(!plugin.exists()){
|
||||||
int i = 0;
|
qDebug("%s plugin does not exist, returning 0.0", filePath.toLocal8Bit().data());
|
||||||
if(sortOrder == Qt::AscendingOrder) {
|
return 0.0;
|
||||||
while(i < list.size() and QString::localeAwareCompare(value.second, list.at(i).second) > 0) {
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
while(i < list.size() and QString::localeAwareCompare(value.second, list.at(i).second) < 0) {
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list.insert(i, value);
|
|
||||||
}
|
}
|
||||||
|
if(!plugin.open(QIODevice::ReadOnly | QIODevice::Text)){
|
||||||
static float getPluginVersion(QString filePath) {
|
return 0.0;
|
||||||
QFile plugin(filePath);
|
|
||||||
if(!plugin.exists()){
|
|
||||||
qDebug("%s plugin does not exist, returning 0.0", filePath.toLocal8Bit().data());
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
if(!plugin.open(QIODevice::ReadOnly | QIODevice::Text)){
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
float version = 0.0;
|
|
||||||
while (!plugin.atEnd()){
|
|
||||||
QByteArray line = plugin.readLine();
|
|
||||||
if(line.startsWith("#VERSION: ")){
|
|
||||||
line = line.split(' ').last();
|
|
||||||
line.replace("\n", "");
|
|
||||||
version = line.toFloat();
|
|
||||||
qDebug("plugin %s version: %.2f", filePath.toLocal8Bit().data(), version);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return version;
|
|
||||||
}
|
}
|
||||||
|
float version = 0.0;
|
||||||
|
while (!plugin.atEnd()){
|
||||||
|
QByteArray line = plugin.readLine();
|
||||||
|
if(line.startsWith("#VERSION: ")){
|
||||||
|
line = line.split(' ').last();
|
||||||
|
line.replace("\n", "");
|
||||||
|
version = line.toFloat();
|
||||||
|
qDebug("plugin %s version: %.2f", filePath.toLocal8Bit().data(), version);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
// Take a number of seconds and return an user-friendly
|
static QString magnetUriToHash(QString magnet_uri) {
|
||||||
// time duration like "1d 2h 10m".
|
QString hash = "";
|
||||||
static QString userFriendlyDuration(qlonglong seconds) {
|
QRegExp reg("urn:btih:([A-Z2-7=]+)");
|
||||||
if(seconds < 0) {
|
int pos = reg.indexIn(magnet_uri);
|
||||||
return QString::fromUtf8("∞");
|
if(pos > -1) {
|
||||||
}
|
sha1_hash sha1;
|
||||||
if(seconds < 60) {
|
sha1.assign(base32decode(reg.cap(1).toStdString()));
|
||||||
return tr("< 1m", "< 1 minute");
|
hash = misc::toQString(sha1);
|
||||||
}
|
}
|
||||||
int minutes = seconds / 60;
|
qDebug("magnetUriToHash: hash: %s", hash.toUtf8().data());
|
||||||
if(minutes < 60) {
|
return hash;
|
||||||
return tr("%1m","e.g: 10minutes").arg(QString::QString::fromUtf8(misc::toString(minutes).c_str()));
|
}
|
||||||
}
|
|
||||||
int hours = minutes / 60;
|
// Take a number of seconds and return an user-friendly
|
||||||
minutes = minutes - hours*60;
|
// time duration like "1d 2h 10m".
|
||||||
if(hours < 24) {
|
static QString userFriendlyDuration(qlonglong seconds) {
|
||||||
return tr("%1h%2m", "e.g: 3hours 5minutes").arg(QString::fromUtf8(misc::toString(hours).c_str())).arg(QString::fromUtf8(misc::toString(minutes).c_str()));
|
if(seconds < 0) {
|
||||||
}
|
|
||||||
int days = hours / 24;
|
|
||||||
hours = hours - days * 24;
|
|
||||||
if(days < 100) {
|
|
||||||
return tr("%1d%2h%3m", "e.g: 2days 10hours 2minutes").arg(QString::fromUtf8(misc::toString(days).c_str())).arg(QString::fromUtf8(misc::toString(hours).c_str())).arg(QString::fromUtf8(misc::toString(minutes).c_str()));
|
|
||||||
}
|
|
||||||
return QString::fromUtf8("∞");
|
return QString::fromUtf8("∞");
|
||||||
}
|
}
|
||||||
|
if(seconds < 60) {
|
||||||
|
return tr("< 1m", "< 1 minute");
|
||||||
|
}
|
||||||
|
int minutes = seconds / 60;
|
||||||
|
if(minutes < 60) {
|
||||||
|
return tr("%1m","e.g: 10minutes").arg(QString::QString::fromUtf8(misc::toString(minutes).c_str()));
|
||||||
|
}
|
||||||
|
int hours = minutes / 60;
|
||||||
|
minutes = minutes - hours*60;
|
||||||
|
if(hours < 24) {
|
||||||
|
return tr("%1h%2m", "e.g: 3hours 5minutes").arg(QString::fromUtf8(misc::toString(hours).c_str())).arg(QString::fromUtf8(misc::toString(minutes).c_str()));
|
||||||
|
}
|
||||||
|
int days = hours / 24;
|
||||||
|
hours = hours - days * 24;
|
||||||
|
if(days < 100) {
|
||||||
|
return tr("%1d%2h%3m", "e.g: 2days 10hours 2minutes").arg(QString::fromUtf8(misc::toString(days).c_str())).arg(QString::fromUtf8(misc::toString(hours).c_str())).arg(QString::fromUtf8(misc::toString(minutes).c_str()));
|
||||||
|
}
|
||||||
|
return QString::fromUtf8("∞");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Trick to get a portable sleep() function
|
// Trick to get a portable sleep() function
|
||||||
class SleeperThread : public QThread{
|
class SleeperThread : public QThread{
|
||||||
public:
|
public:
|
||||||
static void msleep(unsigned long msecs)
|
static void msleep(unsigned long msecs)
|
||||||
{
|
{
|
||||||
QThread::msleep(msecs);
|
QThread::msleep(msecs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -118,6 +118,7 @@ properties::properties(QWidget *parent, bittorrent *BTSession, QTorrentHandle &h
|
||||||
h.file_progress(fp);
|
h.file_progress(fp);
|
||||||
std::vector<int> files_priority = loadFilesPriorities();
|
std::vector<int> files_priority = loadFilesPriorities();
|
||||||
// List files in torrent
|
// List files in torrent
|
||||||
|
h.get_torrent_info();
|
||||||
arborescence *arb = new arborescence(h.get_torrent_info(), fp, files_priority);
|
arborescence *arb = new arborescence(h.get_torrent_info(), fp, files_priority);
|
||||||
addFilesToTree(arb->getRoot(), PropListModel->invisibleRootItem());
|
addFilesToTree(arb->getRoot(), PropListModel->invisibleRootItem());
|
||||||
delete arb;
|
delete arb;
|
||||||
|
@ -137,7 +138,7 @@ properties::properties(QWidget *parent, bittorrent *BTSession, QTorrentHandle &h
|
||||||
progressBarVbox->addWidget(progressBar);
|
progressBarVbox->addWidget(progressBar);
|
||||||
progressBarUpdater = new RealProgressBarThread(progressBar, h);
|
progressBarUpdater = new RealProgressBarThread(progressBar, h);
|
||||||
progressBarUpdater->start();
|
progressBarUpdater->start();
|
||||||
// progressBarUpdater->refresh();
|
// progressBarUpdater->refresh();
|
||||||
connect(updateInfosTimer, SIGNAL(timeout()), progressBarUpdater, SLOT(refresh()));
|
connect(updateInfosTimer, SIGNAL(timeout()), progressBarUpdater, SLOT(refresh()));
|
||||||
loadSettings();
|
loadSettings();
|
||||||
}
|
}
|
||||||
|
@ -313,15 +314,20 @@ void properties::loadWebSeeds(){
|
||||||
std::vector<int> properties::loadFilesPriorities(){
|
std::vector<int> properties::loadFilesPriorities(){
|
||||||
std::vector<int> fp;
|
std::vector<int> fp;
|
||||||
QVariantList files_priority = TorrentPersistentData::getFilesPriority(hash);
|
QVariantList files_priority = TorrentPersistentData::getFilesPriority(hash);
|
||||||
foreach(const QVariant &var_prio, files_priority) {
|
if(files_priority.empty()) {
|
||||||
int priority = var_prio.toInt();
|
for(int i=0; i<h.num_files(); ++i) {
|
||||||
if( priority < 0 || priority > 7){
|
fp.push_back(1);
|
||||||
// Normal priority as default
|
}
|
||||||
priority = 1;
|
} else {
|
||||||
|
foreach(const QVariant &var_prio, files_priority) {
|
||||||
|
int priority = var_prio.toInt();
|
||||||
|
if( priority < 0 || priority > 7){
|
||||||
|
// Normal priority as default
|
||||||
|
priority = 1;
|
||||||
|
}
|
||||||
|
fp.push_back(priority);
|
||||||
}
|
}
|
||||||
fp.push_back(priority);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return fp;
|
return fp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,8 +462,8 @@ void properties::askWebSeed(){
|
||||||
bool ok;
|
bool ok;
|
||||||
// Ask user for a new url seed
|
// Ask user for a new url seed
|
||||||
QString url_seed = QInputDialog::getText(this, tr("New url seed", "New HTTP source"),
|
QString url_seed = QInputDialog::getText(this, tr("New url seed", "New HTTP source"),
|
||||||
tr("New url seed:"), QLineEdit::Normal,
|
tr("New url seed:"), QLineEdit::Normal,
|
||||||
QString::fromUtf8("http://www."), &ok);
|
QString::fromUtf8("http://www."), &ok);
|
||||||
if(!ok) return;
|
if(!ok) return;
|
||||||
qDebug("Adding %s web seed", url_seed.toLocal8Bit().data());
|
qDebug("Adding %s web seed", url_seed.toLocal8Bit().data());
|
||||||
if(urlSeeds.indexOf(url_seed) != -1) {
|
if(urlSeeds.indexOf(url_seed) != -1) {
|
||||||
|
@ -523,8 +529,8 @@ void properties::deleteSelectedTrackers(){
|
||||||
unsigned int nbTrackers = trackers.size();
|
unsigned int nbTrackers = trackers.size();
|
||||||
if(nbTrackers == (unsigned int) selectedItems.size()){
|
if(nbTrackers == (unsigned int) selectedItems.size()){
|
||||||
QMessageBox::warning(this, tr("qBittorrent"),
|
QMessageBox::warning(this, tr("qBittorrent"),
|
||||||
tr("Trackers list can't be empty."),
|
tr("Trackers list can't be empty."),
|
||||||
QMessageBox::Ok);
|
QMessageBox::Ok);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
foreach(QListWidgetItem *item, selectedItems){
|
foreach(QListWidgetItem *item, selectedItems){
|
||||||
|
@ -660,30 +666,30 @@ void properties::on_incrementalDownload_stateChanged(int state){
|
||||||
}
|
}
|
||||||
|
|
||||||
void properties::on_changeSavePathButton_clicked() {
|
void properties::on_changeSavePathButton_clicked() {
|
||||||
QString dir;
|
QString dir;
|
||||||
QDir saveDir(h.save_path());
|
QDir saveDir(h.save_path());
|
||||||
if(saveDir.exists()){
|
if(saveDir.exists()){
|
||||||
dir = QFileDialog::getExistingDirectory(this, tr("Choose save path"), h.save_path());
|
dir = QFileDialog::getExistingDirectory(this, tr("Choose save path"), h.save_path());
|
||||||
}else{
|
}else{
|
||||||
dir = QFileDialog::getExistingDirectory(this, tr("Choose save path"), QDir::homePath());
|
dir = QFileDialog::getExistingDirectory(this, tr("Choose save path"), QDir::homePath());
|
||||||
}
|
}
|
||||||
if(!dir.isNull()){
|
if(!dir.isNull()){
|
||||||
// Check if savePath exists
|
// Check if savePath exists
|
||||||
QDir savePath(dir);
|
QDir savePath(dir);
|
||||||
if(!savePath.exists()){
|
if(!savePath.exists()){
|
||||||
if(!savePath.mkpath(savePath.path())){
|
if(!savePath.mkpath(savePath.path())){
|
||||||
QMessageBox::critical(0, tr("Save path creation error"), tr("Could not create the save path"));
|
QMessageBox::critical(0, tr("Save path creation error"), tr("Could not create the save path"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Save savepath
|
|
||||||
TorrentPersistentData::saveSavePath(hash, savePath.path());
|
|
||||||
// Actually move storage
|
|
||||||
if(!BTSession->useTemporaryFolder() || h.is_seed())
|
|
||||||
h.move_storage(savePath.path());
|
|
||||||
// Update save_path in dialog
|
|
||||||
save_path->setText(savePath.path());
|
|
||||||
}
|
}
|
||||||
|
// Save savepath
|
||||||
|
TorrentPersistentData::saveSavePath(hash, savePath.path());
|
||||||
|
// Actually move storage
|
||||||
|
if(!BTSession->useTemporaryFolder() || h.is_seed())
|
||||||
|
h.move_storage(savePath.path());
|
||||||
|
// Update save_path in dialog
|
||||||
|
save_path->setText(savePath.path());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void properties::on_okButton_clicked(){
|
void properties::on_okButton_clicked(){
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "qtorrenthandle.h"
|
#include "qtorrenthandle.h"
|
||||||
|
#include <libtorrent/magnet_uri.hpp>
|
||||||
|
|
||||||
QTorrentHandle::QTorrentHandle(torrent_handle h): h(h) {}
|
QTorrentHandle::QTorrentHandle(torrent_handle h): h(h) {}
|
||||||
|
|
||||||
|
@ -54,7 +55,7 @@ torrent_info QTorrentHandle::get_torrent_info() const {
|
||||||
|
|
||||||
QString QTorrentHandle::hash() const {
|
QString QTorrentHandle::hash() const {
|
||||||
Q_ASSERT(h.is_valid());
|
Q_ASSERT(h.is_valid());
|
||||||
return misc::toQString(h.get_torrent_info().info_hash());
|
return misc::toQString(h.info_hash());
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QTorrentHandle::name() const {
|
QString QTorrentHandle::name() const {
|
||||||
|
@ -74,13 +75,13 @@ float QTorrentHandle::progress() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bitfield QTorrentHandle::pieces() const {
|
bitfield QTorrentHandle::pieces() const {
|
||||||
Q_ASSERT(h.is_valid());
|
Q_ASSERT(h.is_valid());
|
||||||
return h.status().pieces;
|
return h.status().pieces;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QTorrentHandle::get_download_queue(std::vector<partial_piece_info>& queue) const {
|
void QTorrentHandle::get_download_queue(std::vector<partial_piece_info>& queue) const {
|
||||||
Q_ASSERT(h.is_valid());
|
Q_ASSERT(h.is_valid());
|
||||||
h.get_download_queue(queue);
|
h.get_download_queue(queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QTorrentHandle::current_tracker() const {
|
QString QTorrentHandle::current_tracker() const {
|
||||||
|
@ -98,8 +99,8 @@ bool QTorrentHandle::is_paused() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QTorrentHandle::is_queued() const {
|
bool QTorrentHandle::is_queued() const {
|
||||||
Q_ASSERT(h.is_valid());
|
Q_ASSERT(h.is_valid());
|
||||||
return h.is_paused() && h.is_auto_managed();
|
return h.is_paused() && h.is_auto_managed();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type QTorrentHandle::total_size() const {
|
size_type QTorrentHandle::total_size() const {
|
||||||
|
@ -109,12 +110,12 @@ size_type QTorrentHandle::total_size() const {
|
||||||
|
|
||||||
size_type QTorrentHandle::piece_length() const {
|
size_type QTorrentHandle::piece_length() const {
|
||||||
Q_ASSERT(h.is_valid());
|
Q_ASSERT(h.is_valid());
|
||||||
return h.get_torrent_info().piece_length();
|
return h.get_torrent_info().piece_length();
|
||||||
}
|
}
|
||||||
|
|
||||||
int QTorrentHandle::num_pieces() const {
|
int QTorrentHandle::num_pieces() const {
|
||||||
Q_ASSERT(h.is_valid());
|
Q_ASSERT(h.is_valid());
|
||||||
return h.get_torrent_info().num_pieces();
|
return h.get_torrent_info().num_pieces();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type QTorrentHandle::total_wanted_done() const {
|
size_type QTorrentHandle::total_wanted_done() const {
|
||||||
|
@ -170,12 +171,14 @@ fs::path QTorrentHandle::save_path_boost() const {
|
||||||
QStringList QTorrentHandle::url_seeds() const {
|
QStringList QTorrentHandle::url_seeds() const {
|
||||||
Q_ASSERT(h.is_valid());
|
Q_ASSERT(h.is_valid());
|
||||||
QStringList res;
|
QStringList res;
|
||||||
std::vector<std::string> existing_seeds = h.get_torrent_info().url_seeds();
|
try {
|
||||||
unsigned int nbSeeds = existing_seeds.size();
|
std::vector<std::string> existing_seeds = h.get_torrent_info().url_seeds();
|
||||||
QString existing_seed;
|
unsigned int nbSeeds = existing_seeds.size();
|
||||||
for(unsigned int i=0; i<nbSeeds; ++i) {
|
QString existing_seed;
|
||||||
res << misc::toQString(existing_seeds[i]);
|
for(unsigned int i=0; i<nbSeeds; ++i) {
|
||||||
}
|
res << misc::toQString(existing_seeds[i]);
|
||||||
|
}
|
||||||
|
} catch(std::exception e) {}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,13 +270,13 @@ void QTorrentHandle::file_progress(std::vector<size_type>& fp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type QTorrentHandle::all_time_download() {
|
size_type QTorrentHandle::all_time_download() {
|
||||||
Q_ASSERT(h.is_valid());
|
Q_ASSERT(h.is_valid());
|
||||||
return h.status().all_time_download;
|
return h.status().all_time_download;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type QTorrentHandle::all_time_upload() {
|
size_type QTorrentHandle::all_time_upload() {
|
||||||
Q_ASSERT(h.is_valid());
|
Q_ASSERT(h.is_valid());
|
||||||
return h.status().all_time_upload;
|
return h.status().all_time_upload;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type QTorrentHandle::total_payload_download() {
|
size_type QTorrentHandle::total_payload_download() {
|
||||||
|
@ -301,8 +304,8 @@ QStringList QTorrentHandle::files_path() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
int QTorrentHandle::queue_position() const {
|
int QTorrentHandle::queue_position() const {
|
||||||
Q_ASSERT(h.is_valid());
|
Q_ASSERT(h.is_valid());
|
||||||
return h.queue_position();
|
return h.queue_position();
|
||||||
}
|
}
|
||||||
|
|
||||||
int QTorrentHandle::num_uploads() const {
|
int QTorrentHandle::num_uploads() const {
|
||||||
|
@ -321,13 +324,13 @@ bool QTorrentHandle::is_seed() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QTorrentHandle::is_auto_managed() const {
|
bool QTorrentHandle::is_auto_managed() const {
|
||||||
Q_ASSERT(h.is_valid());
|
Q_ASSERT(h.is_valid());
|
||||||
return h.is_auto_managed();
|
return h.is_auto_managed();
|
||||||
}
|
}
|
||||||
|
|
||||||
int QTorrentHandle::active_time() const {
|
int QTorrentHandle::active_time() const {
|
||||||
Q_ASSERT(h.is_valid());
|
Q_ASSERT(h.is_valid());
|
||||||
return h.status().active_time;
|
return h.status().active_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QTorrentHandle::is_sequential_download() const {
|
bool QTorrentHandle::is_sequential_download() const {
|
||||||
|
@ -398,18 +401,18 @@ void QTorrentHandle::replace_trackers(std::vector<announce_entry> const& v) cons
|
||||||
}
|
}
|
||||||
|
|
||||||
void QTorrentHandle::auto_managed(bool b) const {
|
void QTorrentHandle::auto_managed(bool b) const {
|
||||||
Q_ASSERT(h.is_valid());
|
Q_ASSERT(h.is_valid());
|
||||||
h.auto_managed(b);
|
h.auto_managed(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QTorrentHandle::queue_position_down() const {
|
void QTorrentHandle::queue_position_down() const {
|
||||||
Q_ASSERT(h.is_valid());
|
Q_ASSERT(h.is_valid());
|
||||||
h.queue_position_down();
|
h.queue_position_down();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QTorrentHandle::queue_position_up() const {
|
void QTorrentHandle::queue_position_up() const {
|
||||||
Q_ASSERT(h.is_valid());
|
Q_ASSERT(h.is_valid());
|
||||||
h.queue_position_up();
|
h.queue_position_up();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,18 +432,18 @@ void QTorrentHandle::set_tracker_login(QString username, QString password) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void QTorrentHandle::force_recheck() const {
|
void QTorrentHandle::force_recheck() const {
|
||||||
Q_ASSERT(h.is_valid());
|
Q_ASSERT(h.is_valid());
|
||||||
h.force_recheck();
|
h.force_recheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QTorrentHandle::move_storage(QString new_path) const {
|
void QTorrentHandle::move_storage(QString new_path) const {
|
||||||
Q_ASSERT(h.is_valid());
|
Q_ASSERT(h.is_valid());
|
||||||
h.move_storage(new_path.toLocal8Bit().data());
|
h.move_storage(new_path.toLocal8Bit().data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void QTorrentHandle::file_priority(int index, int priority) const {
|
void QTorrentHandle::file_priority(int index, int priority) const {
|
||||||
Q_ASSERT(h.is_valid());
|
Q_ASSERT(h.is_valid());
|
||||||
h.file_priority(index, priority);
|
h.file_priority(index, priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -453,6 +456,6 @@ QTorrentHandle& QTorrentHandle::operator =(const torrent_handle& new_h) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QTorrentHandle::operator ==(const QTorrentHandle& new_h) const{
|
bool QTorrentHandle::operator ==(const QTorrentHandle& new_h) const{
|
||||||
QString hash = misc::toQString(h.get_torrent_info().info_hash());
|
QString hash = misc::toQString(h.info_hash());
|
||||||
return (hash == new_h.hash());
|
return (hash == new_h.hash());
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
static QString getSavePath(QString hash) {
|
static QString getSavePath(QString hash) {
|
||||||
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
|
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
|
||||||
QHash<QString, QVariant> all_data = settings.value("torrents-tmp", QHash<QString, QVariant>()).toHash();
|
QHash<QString, QVariant> all_data = settings.value("torrents-tmp", QHash<QString, QVariant>()).toHash();
|
||||||
QHash<QString, QVariant> data = all_data[hash].toHash();
|
QHash<QString, QVariant> data = all_data[hash].toHash();
|
||||||
if(data.contains("save_path"))
|
if(data.contains("save_path"))
|
||||||
|
@ -144,6 +144,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
static void saveTorrentPersistentData(QTorrentHandle h, bool is_magnet = false) {
|
static void saveTorrentPersistentData(QTorrentHandle h, bool is_magnet = false) {
|
||||||
|
Q_ASSERT(h.is_valid());
|
||||||
|
qDebug("Saving persistent data for %s", h.hash().toUtf8().data());
|
||||||
// First, remove temp data
|
// First, remove temp data
|
||||||
TorrentTempData::deleteTempData(h.hash());
|
TorrentTempData::deleteTempData(h.hash());
|
||||||
Q_ASSERT(!TorrentTempData::hasTempData(h.hash()));
|
Q_ASSERT(!TorrentTempData::hasTempData(h.hash()));
|
||||||
|
@ -151,7 +153,6 @@ public:
|
||||||
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
|
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
|
||||||
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
|
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
|
||||||
QHash<QString, QVariant> data;
|
QHash<QString, QVariant> data;
|
||||||
data["hash"] = h.hash();
|
|
||||||
data["is_magnet"] = is_magnet;
|
data["is_magnet"] = is_magnet;
|
||||||
if(is_magnet) {
|
if(is_magnet) {
|
||||||
data["magnet_uri"] = misc::toQString(make_magnet_uri(h.get_torrent_handle()));
|
data["magnet_uri"] = misc::toQString(make_magnet_uri(h.get_torrent_handle()));
|
||||||
|
@ -175,15 +176,18 @@ public:
|
||||||
tr_it++;
|
tr_it++;
|
||||||
}
|
}
|
||||||
data["trackers"] = trackers;
|
data["trackers"] = trackers;
|
||||||
QVariantList url_seeds;
|
if(!is_magnet) {
|
||||||
foreach(QString url_seed, h.url_seeds()) {
|
QVariantList url_seeds;
|
||||||
url_seeds << url_seed;
|
foreach(QString url_seed, h.url_seeds()) {
|
||||||
|
url_seeds << url_seed;
|
||||||
|
}
|
||||||
|
data["url_seeds"] = url_seeds;
|
||||||
}
|
}
|
||||||
data["url_seeds"] = url_seeds;
|
|
||||||
data["sequential"] = h.is_sequential_download();
|
data["sequential"] = h.is_sequential_download();
|
||||||
// Save data
|
// Save data
|
||||||
all_data[h.hash()] = data;
|
all_data[h.hash()] = data;
|
||||||
settings.setValue("torrents", all_data);
|
settings.setValue("torrents", all_data);
|
||||||
|
qDebug("TorrentPersistentData: Saving save_path %s, hash: %s", h.save_path().toUtf8().data(), h.hash().toUtf8().data());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void saveTrackers(QTorrentHandle h) {
|
static void saveTrackers(QTorrentHandle h) {
|
||||||
|
@ -222,12 +226,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
static void saveSavePath(QString hash, QString save_path) {
|
static void saveSavePath(QString hash, QString save_path) {
|
||||||
|
Q_ASSERT(!hash.isEmpty());
|
||||||
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
|
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
|
||||||
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
|
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
|
||||||
QHash<QString, QVariant> data = all_data[hash].toHash();
|
QHash<QString, QVariant> data = all_data[hash].toHash();
|
||||||
data["save_path"] = save_path;
|
data["save_path"] = save_path;
|
||||||
all_data[hash] = data;
|
all_data[hash] = data;
|
||||||
settings.setValue("torrents", all_data);
|
settings.setValue("torrents", all_data);
|
||||||
|
qDebug("TorrentPersistentData: Saving save_path: %s, hash: %s", save_path.toUtf8().data(), hash.toUtf8().data());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void saveUrlSeeds(QTorrentHandle h) {
|
static void saveUrlSeeds(QTorrentHandle h) {
|
||||||
|
@ -289,6 +295,7 @@ public:
|
||||||
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
|
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
|
||||||
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
|
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
|
||||||
QHash<QString, QVariant> data = all_data[hash].toHash();
|
QHash<QString, QVariant> data = all_data[hash].toHash();
|
||||||
|
qDebug("TorrentPersistentData: getSavePath %s", data["save_path"].toString().toUtf8().data());
|
||||||
return data["save_path"].toString();
|
return data["save_path"].toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,7 +310,10 @@ public:
|
||||||
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
|
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
|
||||||
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
|
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
|
||||||
QHash<QString, QVariant> data = all_data[hash].toHash();
|
QHash<QString, QVariant> data = all_data[hash].toHash();
|
||||||
return data["url_seeds"].toList();
|
if(data.contains("url_seeds")) {
|
||||||
|
return data["url_seeds"].toList();
|
||||||
|
}
|
||||||
|
return QVariantList();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isSeed(QString hash) {
|
static bool isSeed(QString hash) {
|
||||||
|
|
Loading…
Reference in a new issue