Browse Source

Merge pull request #9541 from Piccirello/webui-file-priority

Set priority for multiple files in one WebAPI request
adaptive-webui-19844
Mike Tzou 6 years ago committed by GitHub
parent
commit
cf9d903ba9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      src/base/CMakeLists.txt
  2. 2
      src/base/base.pri
  3. 46
      src/base/bittorrent/filepriority.cpp
  4. 43
      src/base/bittorrent/filepriority.h
  5. 10
      src/base/bittorrent/torrenthandle.cpp
  6. 1
      src/base/bittorrent/torrenthandle.h
  7. 13
      src/gui/addnewtorrentdialog.cpp
  8. 2
      src/gui/ipsubnetwhitelistoptionsdialog.cpp
  9. 2
      src/gui/ipsubnetwhitelistoptionsdialog.h
  10. 13
      src/gui/properties/propertieswidget.cpp
  11. 33
      src/gui/properties/proplistdelegate.cpp
  12. 30
      src/gui/torrentcontentmodel.cpp
  13. 4
      src/gui/torrentcontentmodelfile.cpp
  14. 3
      src/gui/torrentcontentmodelfile.h
  15. 12
      src/gui/torrentcontentmodelfolder.cpp
  16. 3
      src/gui/torrentcontentmodelfolder.h
  17. 6
      src/gui/torrentcontentmodelitem.cpp
  18. 18
      src/gui/torrentcontentmodelitem.h
  19. 37
      src/webui/api/torrentscontroller.cpp
  20. 2
      src/webui/www/private/properties_content.html
  21. 190
      src/webui/www/private/scripts/prop-files.js

2
src/base/CMakeLists.txt

@ -4,6 +4,7 @@ add_library(qbt_base STATIC
# headers # headers
bittorrent/addtorrentparams.h bittorrent/addtorrentparams.h
bittorrent/cachestatus.h bittorrent/cachestatus.h
bittorrent/filepriority.h
bittorrent/infohash.h bittorrent/infohash.h
bittorrent/magneturi.h bittorrent/magneturi.h
bittorrent/peerinfo.h bittorrent/peerinfo.h
@ -77,6 +78,7 @@ types.h
unicodestrings.h unicodestrings.h
# sources # sources
bittorrent/filepriority.cpp
bittorrent/infohash.cpp bittorrent/infohash.cpp
bittorrent/magneturi.cpp bittorrent/magneturi.cpp
bittorrent/peerinfo.cpp bittorrent/peerinfo.cpp

2
src/base/base.pri

@ -3,6 +3,7 @@ HEADERS += \
$$PWD/asyncfilestorage.h \ $$PWD/asyncfilestorage.h \
$$PWD/bittorrent/addtorrentparams.h \ $$PWD/bittorrent/addtorrentparams.h \
$$PWD/bittorrent/cachestatus.h \ $$PWD/bittorrent/cachestatus.h \
$$PWD/bittorrent/filepriority.h \
$$PWD/bittorrent/infohash.h \ $$PWD/bittorrent/infohash.h \
$$PWD/bittorrent/magneturi.h \ $$PWD/bittorrent/magneturi.h \
$$PWD/bittorrent/peerinfo.h \ $$PWD/bittorrent/peerinfo.h \
@ -76,6 +77,7 @@ HEADERS += \
SOURCES += \ SOURCES += \
$$PWD/asyncfilestorage.cpp \ $$PWD/asyncfilestorage.cpp \
$$PWD/bittorrent/filepriority.cpp \
$$PWD/bittorrent/infohash.cpp \ $$PWD/bittorrent/infohash.cpp \
$$PWD/bittorrent/magneturi.cpp \ $$PWD/bittorrent/magneturi.cpp \
$$PWD/bittorrent/peerinfo.cpp \ $$PWD/bittorrent/peerinfo.cpp \

46
src/base/bittorrent/filepriority.cpp

@ -0,0 +1,46 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2018 Thomas Piccirello <thomas.piccirello@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#include "filepriority.h"
namespace BitTorrent
{
bool isValidFilePriority(const BitTorrent::FilePriority priority)
{
switch (priority) {
case BitTorrent::FilePriority::Ignored:
case BitTorrent::FilePriority::Normal:
case BitTorrent::FilePriority::High:
case BitTorrent::FilePriority::Maximum:
case BitTorrent::FilePriority::Mixed:
return true;
default:
return false;
}
}
}

43
src/base/bittorrent/filepriority.h

@ -0,0 +1,43 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2018 Thomas Piccirello <thomas.piccirello@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#pragma once
namespace BitTorrent
{
enum class FilePriority : int
{
Ignored = 0,
Normal = 1,
High = 6,
Maximum = 7,
Mixed = -1
};
bool isValidFilePriority(BitTorrent::FilePriority priority);
}

10
src/base/bittorrent/torrenthandle.cpp

@ -1424,16 +1424,6 @@ bool TorrentHandle::saveTorrentFile(const QString &path)
return false; return false;
} }
void TorrentHandle::setFilePriority(int index, int priority)
{
std::vector<int> priorities = m_nativeHandle.file_priorities();
if ((priorities.size() > static_cast<quint64>(index)) && (priorities[index] != priority)) {
priorities[index] = priority;
prioritizeFiles(QVector<int>::fromStdVector(priorities));
}
}
void TorrentHandle::handleStateUpdate(const libt::torrent_status &nativeStatus) void TorrentHandle::handleStateUpdate(const libt::torrent_status &nativeStatus)
{ {
updateStatus(nativeStatus); updateStatus(nativeStatus);

1
src/base/bittorrent/torrenthandle.h

@ -348,7 +348,6 @@ namespace BitTorrent
void renameFile(int index, const QString &name); void renameFile(int index, const QString &name);
bool saveTorrentFile(const QString &path); bool saveTorrentFile(const QString &path);
void prioritizeFiles(const QVector<int> &priorities); void prioritizeFiles(const QVector<int> &priorities);
void setFilePriority(int index, int priority);
void setRatioLimit(qreal limit); void setRatioLimit(qreal limit);
void setSeedingTimeLimit(int limit); void setSeedingTimeLimit(int limit);
void setUploadLimit(int limit); void setUploadLimit(int limit);

13
src/gui/addnewtorrentdialog.cpp

@ -36,6 +36,7 @@
#include <QUrl> #include <QUrl>
#include <QVector> #include <QVector>
#include "base/bittorrent/filepriority.h"
#include "base/bittorrent/magneturi.h" #include "base/bittorrent/magneturi.h"
#include "base/bittorrent/session.h" #include "base/bittorrent/session.h"
#include "base/bittorrent/torrenthandle.h" #include "base/bittorrent/torrenthandle.h"
@ -622,18 +623,18 @@ void AddNewTorrentDialog::displayContentTreeMenu(const QPoint &)
renameSelectedFile(); renameSelectedFile();
} }
else { else {
int prio = prio::NORMAL; BitTorrent::FilePriority prio = BitTorrent::FilePriority::Normal;
if (act == m_ui->actionHigh) if (act == m_ui->actionHigh)
prio = prio::HIGH; prio = BitTorrent::FilePriority::High;
else if (act == m_ui->actionMaximum) else if (act == m_ui->actionMaximum)
prio = prio::MAXIMUM; prio = BitTorrent::FilePriority::Maximum;
else if (act == m_ui->actionNotDownloaded) else if (act == m_ui->actionNotDownloaded)
prio = prio::IGNORED; prio = BitTorrent::FilePriority::Ignored;
qDebug("Setting files priority"); qDebug("Setting files priority");
for (const QModelIndex &index : selectedRows) { for (const QModelIndex &index : selectedRows) {
qDebug("Setting priority(%d) for file at row %d", prio, index.row()); qDebug("Setting priority(%d) for file at row %d", static_cast<int>(prio), index.row());
m_contentModel->setData(m_contentModel->index(index.row(), PRIORITY, index.parent()), prio); m_contentModel->setData(m_contentModel->index(index.row(), PRIORITY, index.parent()), static_cast<int>(prio));
} }
} }
} }

2
src/gui/ipsubnetwhitelistoptionsdialog.cpp

@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2017 Thomas Piccirello <thomas@piccirello.com> * Copyright (C) 2017 Thomas Piccirello <thomas.piccirello@gmail.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License

2
src/gui/ipsubnetwhitelistoptionsdialog.h

@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2017 Thomas Piccirello <thomas@piccirello.com> * Copyright (C) 2017 Thomas Piccirello <thomas.piccirello@gmail.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License

13
src/gui/properties/propertieswidget.cpp

@ -38,6 +38,7 @@
#include <QThread> #include <QThread>
#include <QTimer> #include <QTimer>
#include "base/bittorrent/filepriority.h"
#include "base/bittorrent/session.h" #include "base/bittorrent/session.h"
#include "base/preferences.h" #include "base/preferences.h"
#include "base/unicodestrings.h" #include "base/unicodestrings.h"
@ -621,18 +622,18 @@ void PropertiesWidget::displayFilesListMenu(const QPoint &)
renameSelectedFile(); renameSelectedFile();
} }
else { else {
int prio = prio::NORMAL; BitTorrent::FilePriority prio = BitTorrent::FilePriority::Normal;
if (act == m_ui->actionHigh) if (act == m_ui->actionHigh)
prio = prio::HIGH; prio = BitTorrent::FilePriority::High;
else if (act == m_ui->actionMaximum) else if (act == m_ui->actionMaximum)
prio = prio::MAXIMUM; prio = BitTorrent::FilePriority::Maximum;
else if (act == m_ui->actionNotDownloaded) else if (act == m_ui->actionNotDownloaded)
prio = prio::IGNORED; prio = BitTorrent::FilePriority::Ignored;
qDebug("Setting files priority"); qDebug("Setting files priority");
for (const QModelIndex &index : selectedRows) { for (const QModelIndex &index : selectedRows) {
qDebug("Setting priority(%d) for file at row %d", prio, index.row()); qDebug("Setting priority(%d) for file at row %d", static_cast<int>(prio), index.row());
m_propListModel->setData(m_propListModel->index(index.row(), PRIORITY, index.parent()), prio); m_propListModel->setData(m_propListModel->index(index.row(), PRIORITY, index.parent()), static_cast<int>(prio));
} }
// Save changes // Save changes
filteredFilesChanged(); filteredFilesChanged();

33
src/gui/properties/proplistdelegate.cpp

@ -40,6 +40,7 @@
#include <QProxyStyle> #include <QProxyStyle>
#endif #endif
#include "base/bittorrent/filepriority.h"
#include "base/unicodestrings.h" #include "base/unicodestrings.h"
#include "base/utils/misc.h" #include "base/utils/misc.h"
#include "base/utils/string.h" #include "base/utils/string.h"
@ -92,7 +93,7 @@ void PropListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti
newopt.maximum = 100; newopt.maximum = 100;
newopt.minimum = 0; newopt.minimum = 0;
newopt.textVisible = true; newopt.textVisible = true;
if (index.sibling(index.row(), PRIORITY).data().toInt() == prio::IGNORED) { if (index.sibling(index.row(), PRIORITY).data().toInt() == static_cast<int>(BitTorrent::FilePriority::Ignored)) {
newopt.state &= ~QStyle::State_Enabled; newopt.state &= ~QStyle::State_Enabled;
newopt.palette = progressBarDisabledPalette(); newopt.palette = progressBarDisabledPalette();
} }
@ -110,17 +111,17 @@ void PropListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti
break; break;
case PRIORITY: { case PRIORITY: {
QString text = ""; QString text = "";
switch (index.data().toInt()) { switch (static_cast<BitTorrent::FilePriority>(index.data().toInt())) {
case prio::MIXED: case BitTorrent::FilePriority::Mixed:
text = tr("Mixed", "Mixed (priorities"); text = tr("Mixed", "Mixed (priorities");
break; break;
case prio::IGNORED: case BitTorrent::FilePriority::Ignored:
text = tr("Not downloaded"); text = tr("Not downloaded");
break; break;
case prio::HIGH: case BitTorrent::FilePriority::High:
text = tr("High", "High (priority)"); text = tr("High", "High (priority)");
break; break;
case prio::MAXIMUM: case BitTorrent::FilePriority::Maximum:
text = tr("Maximum", "Maximum (priority)"); text = tr("Maximum", "Maximum (priority)");
break; break;
default: default:
@ -154,14 +155,14 @@ void PropListDelegate::setEditorData(QWidget *editor, const QModelIndex &index)
{ {
QComboBox *combobox = static_cast<QComboBox *>(editor); QComboBox *combobox = static_cast<QComboBox *>(editor);
// Set combobox index // Set combobox index
switch (index.data().toInt()) { switch (static_cast<BitTorrent::FilePriority>(index.data().toInt())) {
case prio::IGNORED: case BitTorrent::FilePriority::Ignored:
combobox->setCurrentIndex(0); combobox->setCurrentIndex(0);
break; break;
case prio::HIGH: case BitTorrent::FilePriority::High:
combobox->setCurrentIndex(2); combobox->setCurrentIndex(2);
break; break;
case prio::MAXIMUM: case BitTorrent::FilePriority::Maximum:
combobox->setCurrentIndex(3); combobox->setCurrentIndex(3);
break; break;
default: default:
@ -180,7 +181,7 @@ QWidget *PropListDelegate::createEditor(QWidget *parent, const QStyleOptionViewI
return nullptr; return nullptr;
} }
if (index.data().toInt() == prio::MIXED) if (index.data().toInt() == static_cast<int>(BitTorrent::FilePriority::Mixed))
return nullptr; return nullptr;
QComboBox *editor = new QComboBox(parent); QComboBox *editor = new QComboBox(parent);
@ -198,20 +199,20 @@ void PropListDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
int value = combobox->currentIndex(); int value = combobox->currentIndex();
qDebug("PropListDelegate: setModelData(%d)", value); qDebug("PropListDelegate: setModelData(%d)", value);
BitTorrent::FilePriority prio = BitTorrent::FilePriority::Normal; // NORMAL
switch (value) { switch (value) {
case 0: case 0:
model->setData(index, prio::IGNORED); // IGNORED prio = BitTorrent::FilePriority::Ignored; // IGNORED
break; break;
case 2: case 2:
model->setData(index, prio::HIGH); // HIGH prio = BitTorrent::FilePriority::High; // HIGH
break; break;
case 3: case 3:
model->setData(index, prio::MAXIMUM); // MAX prio = BitTorrent::FilePriority::Maximum; // MAX
break; break;
default:
model->setData(index, prio::NORMAL); // NORMAL
} }
model->setData(index, static_cast<int>(prio));
emit filteredFilesChanged(); emit filteredFilesChanged();
} }

30
src/gui/torrentcontentmodel.cpp

@ -48,6 +48,7 @@
#include <QPixmapCache> #include <QPixmapCache>
#endif #endif
#include "base/bittorrent/filepriority.h"
#include "base/global.h" #include "base/global.h"
#include "base/utils/misc.h" #include "base/utils/misc.h"
#include "base/utils/fs.h" #include "base/utils/fs.h"
@ -245,7 +246,7 @@ void TorrentContentModel::updateFilesPriorities(const QVector<int> &fprio)
emit layoutAboutToBeChanged(); emit layoutAboutToBeChanged();
for (int i = 0; i < fprio.size(); ++i) for (int i = 0; i < fprio.size(); ++i)
m_filesIndex[i]->setPriority(fprio[i]); m_filesIndex[i]->setPriority(static_cast<BitTorrent::FilePriority>(fprio[i]));
emit dataChanged(index(0, 0), index(rowCount(), columnCount())); emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
} }
@ -268,14 +269,14 @@ QVector<int> TorrentContentModel::getFilePriorities() const
QVector<int> prio; QVector<int> prio;
prio.reserve(m_filesIndex.size()); prio.reserve(m_filesIndex.size());
for (const TorrentContentModelFile *file : asConst(m_filesIndex)) for (const TorrentContentModelFile *file : asConst(m_filesIndex))
prio.push_back(file->priority()); prio.push_back(static_cast<int>(file->priority()));
return prio; return prio;
} }
bool TorrentContentModel::allFiltered() const bool TorrentContentModel::allFiltered() const
{ {
for (const TorrentContentModelFile *fileItem : asConst(m_filesIndex)) for (const TorrentContentModelFile *fileItem : asConst(m_filesIndex))
if (fileItem->priority() != prio::IGNORED) if (fileItem->priority() != BitTorrent::FilePriority::Ignored)
return false; return false;
return true; return true;
} }
@ -296,13 +297,14 @@ bool TorrentContentModel::setData(const QModelIndex &index, const QVariant &valu
if ((index.column() == TorrentContentModelItem::COL_NAME) && (role == Qt::CheckStateRole)) { if ((index.column() == TorrentContentModelItem::COL_NAME) && (role == Qt::CheckStateRole)) {
TorrentContentModelItem *item = static_cast<TorrentContentModelItem*>(index.internalPointer()); TorrentContentModelItem *item = static_cast<TorrentContentModelItem*>(index.internalPointer());
qDebug("setData(%s, %d", qUtf8Printable(item->name()), value.toInt()); qDebug("setData(%s, %d", qUtf8Printable(item->name()), value.toInt());
if (item->priority() != value.toInt()) { if (static_cast<int>(item->priority()) != value.toInt()) {
BitTorrent::FilePriority prio = BitTorrent::FilePriority::Normal;
if (value.toInt() == Qt::PartiallyChecked) if (value.toInt() == Qt::PartiallyChecked)
item->setPriority(prio::MIXED); prio = BitTorrent::FilePriority::Mixed;
else if (value.toInt() == Qt::Unchecked) else if (value.toInt() == Qt::Unchecked)
item->setPriority(prio::IGNORED); prio = BitTorrent::FilePriority::Ignored;
else
item->setPriority(prio::NORMAL); item->setPriority(prio);
// Update folders progress in the tree // Update folders progress in the tree
m_rootItem->recalculateProgress(); m_rootItem->recalculateProgress();
m_rootItem->recalculateAvailability(); m_rootItem->recalculateAvailability();
@ -320,7 +322,7 @@ bool TorrentContentModel::setData(const QModelIndex &index, const QVariant &valu
item->setName(value.toString()); item->setName(value.toString());
break; break;
case TorrentContentModelItem::COL_PRIO: case TorrentContentModelItem::COL_PRIO:
item->setPriority(value.toInt()); item->setPriority(static_cast<BitTorrent::FilePriority>(value.toInt()));
break; break;
default: default:
return false; return false;
@ -362,9 +364,9 @@ QVariant TorrentContentModel::data(const QModelIndex &index, int role) const
} }
if ((index.column() == TorrentContentModelItem::COL_NAME) && (role == Qt::CheckStateRole)) { if ((index.column() == TorrentContentModelItem::COL_NAME) && (role == Qt::CheckStateRole)) {
if (item->data(TorrentContentModelItem::COL_PRIO).toInt() == prio::IGNORED) if (item->data(TorrentContentModelItem::COL_PRIO).toInt() == static_cast<int>(BitTorrent::FilePriority::Ignored))
return Qt::Unchecked; return Qt::Unchecked;
if (item->data(TorrentContentModelItem::COL_PRIO).toInt() == prio::MIXED) if (item->data(TorrentContentModelItem::COL_PRIO).toInt() == static_cast<int>(BitTorrent::FilePriority::Mixed))
return Qt::PartiallyChecked; return Qt::PartiallyChecked;
return Qt::Checked; return Qt::Checked;
} }
@ -499,8 +501,8 @@ void TorrentContentModel::selectAll()
{ {
for (int i = 0; i < m_rootItem->childCount(); ++i) { for (int i = 0; i < m_rootItem->childCount(); ++i) {
TorrentContentModelItem* child = m_rootItem->child(i); TorrentContentModelItem* child = m_rootItem->child(i);
if (child->priority() == prio::IGNORED) if (child->priority() == BitTorrent::FilePriority::Ignored)
child->setPriority(prio::NORMAL); child->setPriority(BitTorrent::FilePriority::Normal);
} }
emit dataChanged(index(0, 0), index(rowCount(), columnCount())); emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
} }
@ -508,6 +510,6 @@ void TorrentContentModel::selectAll()
void TorrentContentModel::selectNone() void TorrentContentModel::selectNone()
{ {
for (int i = 0; i < m_rootItem->childCount(); ++i) for (int i = 0; i < m_rootItem->childCount(); ++i)
m_rootItem->child(i)->setPriority(prio::IGNORED); m_rootItem->child(i)->setPriority(BitTorrent::FilePriority::Ignored);
emit dataChanged(index(0, 0), index(rowCount(), columnCount())); emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
} }

4
src/gui/torrentcontentmodelfile.cpp

@ -52,9 +52,9 @@ int TorrentContentModelFile::fileIndex() const
return m_fileIndex; return m_fileIndex;
} }
void TorrentContentModelFile::setPriority(int newPriority, bool updateParent) void TorrentContentModelFile::setPriority(BitTorrent::FilePriority newPriority, bool updateParent)
{ {
Q_ASSERT(newPriority != prio::MIXED); Q_ASSERT(newPriority != BitTorrent::FilePriority::Mixed);
if (m_priority == newPriority) if (m_priority == newPriority)
return; return;

3
src/gui/torrentcontentmodelfile.h

@ -29,6 +29,7 @@
#ifndef TORRENTCONTENTMODELFILE_H #ifndef TORRENTCONTENTMODELFILE_H
#define TORRENTCONTENTMODELFILE_H #define TORRENTCONTENTMODELFILE_H
#include "base/bittorrent/filepriority.h"
#include "torrentcontentmodelitem.h" #include "torrentcontentmodelitem.h"
class TorrentContentModelFile : public TorrentContentModelItem class TorrentContentModelFile : public TorrentContentModelItem
@ -38,7 +39,7 @@ public:
TorrentContentModelFolder *parent, int fileIndex); TorrentContentModelFolder *parent, int fileIndex);
int fileIndex() const; int fileIndex() const;
void setPriority(int newPriority, bool updateParent = true) override; void setPriority(BitTorrent::FilePriority newPriority, bool updateParent = true) override;
void setProgress(qreal progress); void setProgress(qreal progress);
void setAvailability(qreal availability); void setAvailability(qreal availability);
ItemType itemType() const override; ItemType itemType() const override;

12
src/gui/torrentcontentmodelfolder.cpp

@ -108,10 +108,10 @@ void TorrentContentModelFolder::updatePriority()
// If all children have the same priority // If all children have the same priority
// then the folder should have the same // then the folder should have the same
// priority // priority
const int prio = m_childItems.first()->priority(); const BitTorrent::FilePriority prio = m_childItems.first()->priority();
for (int i = 1; i < m_childItems.size(); ++i) { for (int i = 1; i < m_childItems.size(); ++i) {
if (m_childItems.at(i)->priority() != prio) { if (m_childItems.at(i)->priority() != prio) {
setPriority(prio::MIXED); setPriority(BitTorrent::FilePriority::Mixed);
return; return;
} }
} }
@ -120,7 +120,7 @@ void TorrentContentModelFolder::updatePriority()
setPriority(prio); setPriority(prio);
} }
void TorrentContentModelFolder::setPriority(int newPriority, bool updateParent) void TorrentContentModelFolder::setPriority(BitTorrent::FilePriority newPriority, bool updateParent)
{ {
if (m_priority == newPriority) if (m_priority == newPriority)
return; return;
@ -132,7 +132,7 @@ void TorrentContentModelFolder::setPriority(int newPriority, bool updateParent)
m_parentItem->updatePriority(); m_parentItem->updatePriority();
// Update children // Update children
if (m_priority != prio::MIXED) if (m_priority != BitTorrent::FilePriority::Mixed)
for (TorrentContentModelItem *child : asConst(m_childItems)) for (TorrentContentModelItem *child : asConst(m_childItems))
child->setPriority(m_priority, false); child->setPriority(m_priority, false);
} }
@ -143,7 +143,7 @@ void TorrentContentModelFolder::recalculateProgress()
qulonglong tSize = 0; qulonglong tSize = 0;
qulonglong tRemaining = 0; qulonglong tRemaining = 0;
for (TorrentContentModelItem *child : asConst(m_childItems)) { for (TorrentContentModelItem *child : asConst(m_childItems)) {
if (child->priority() == prio::IGNORED) if (child->priority() == BitTorrent::FilePriority::Ignored)
continue; continue;
if (child->itemType() == FolderType) if (child->itemType() == FolderType)
@ -166,7 +166,7 @@ void TorrentContentModelFolder::recalculateAvailability()
qulonglong tSize = 0; qulonglong tSize = 0;
bool foundAnyData = false; bool foundAnyData = false;
for (TorrentContentModelItem *child : asConst(m_childItems)) { for (TorrentContentModelItem *child : asConst(m_childItems)) {
if (child->priority() == prio::IGNORED) if (child->priority() == BitTorrent::FilePriority::Ignored)
continue; continue;
if (child->itemType() == FolderType) if (child->itemType() == FolderType)

3
src/gui/torrentcontentmodelfolder.h

@ -29,6 +29,7 @@
#ifndef TORRENTCONTENTMODELFOLDER_H #ifndef TORRENTCONTENTMODELFOLDER_H
#define TORRENTCONTENTMODELFOLDER_H #define TORRENTCONTENTMODELFOLDER_H
#include "base/bittorrent/filepriority.h"
#include "torrentcontentmodelitem.h" #include "torrentcontentmodelitem.h"
class TorrentContentModelFolder : public TorrentContentModelItem class TorrentContentModelFolder : public TorrentContentModelItem
@ -49,7 +50,7 @@ public:
void recalculateAvailability(); void recalculateAvailability();
void updatePriority(); void updatePriority();
void setPriority(int newPriority, bool updateParent = true) override; void setPriority(BitTorrent::FilePriority newPriority, bool updateParent = true) override;
void deleteAllChildren(); void deleteAllChildren();
const QList<TorrentContentModelItem*> &children() const; const QList<TorrentContentModelItem*> &children() const;

6
src/gui/torrentcontentmodelitem.cpp

@ -38,7 +38,7 @@ TorrentContentModelItem::TorrentContentModelItem(TorrentContentModelFolder *pare
: m_parentItem(parent) : m_parentItem(parent)
, m_size(0) , m_size(0)
, m_remaining(0) , m_remaining(0)
, m_priority(prio::NORMAL) , m_priority(BitTorrent::FilePriority::Normal)
, m_progress(0) , m_progress(0)
, m_availability(-1.) , m_availability(-1.)
{ {
@ -90,7 +90,7 @@ qreal TorrentContentModelItem::availability() const
return (m_size > 0) ? m_availability : 0; return (m_size > 0) ? m_availability : 0;
} }
int TorrentContentModelItem::priority() const BitTorrent::FilePriority TorrentContentModelItem::priority() const
{ {
Q_ASSERT(!isRootItem()); Q_ASSERT(!isRootItem());
return m_priority; return m_priority;
@ -110,7 +110,7 @@ QVariant TorrentContentModelItem::data(int column) const
case COL_NAME: case COL_NAME:
return m_name; return m_name;
case COL_PRIO: case COL_PRIO:
return m_priority; return static_cast<int>(m_priority);
case COL_PROGRESS: case COL_PROGRESS:
return progress(); return progress();
case COL_SIZE: case COL_SIZE:

18
src/gui/torrentcontentmodelitem.h

@ -32,17 +32,7 @@
#include <QList> #include <QList>
#include <QVariant> #include <QVariant>
namespace prio #include "base/bittorrent/filepriority.h"
{
enum FilePriority
{
IGNORED=0,
NORMAL=1,
HIGH=6,
MAXIMUM=7,
MIXED=-1
};
}
class TorrentContentModelFolder; class TorrentContentModelFolder;
@ -82,8 +72,8 @@ public:
qreal availability() const; qreal availability() const;
int priority() const; BitTorrent::FilePriority priority() const;
virtual void setPriority(int newPriority, bool updateParent = true) = 0; virtual void setPriority(BitTorrent::FilePriority newPriority, bool updateParent = true) = 0;
int columnCount() const; int columnCount() const;
QVariant data(int column) const; QVariant data(int column) const;
@ -97,7 +87,7 @@ protected:
QString m_name; QString m_name;
qulonglong m_size; qulonglong m_size;
qulonglong m_remaining; qulonglong m_remaining;
int m_priority; BitTorrent::FilePriority m_priority;
qreal m_progress; qreal m_progress;
qreal m_availability; qreal m_availability;
}; };

37
src/webui/api/torrentscontroller.cpp

@ -39,6 +39,7 @@
#include <QRegularExpression> #include <QRegularExpression>
#include <QUrl> #include <QUrl>
#include "base/bittorrent/filepriority.h"
#include "base/bittorrent/session.h" #include "base/bittorrent/session.h"
#include "base/bittorrent/torrenthandle.h" #include "base/bittorrent/torrenthandle.h"
#include "base/bittorrent/torrentinfo.h" #include "base/bittorrent/torrentinfo.h"
@ -371,7 +372,7 @@ void TorrentsController::filesAction()
const QString hash {params()["hash"]}; const QString hash {params()["hash"]};
QVariantList fileList; QVariantList fileList;
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); const BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (!torrent) if (!torrent)
throw APIError(APIErrorType::NotFound); throw APIError(APIErrorType::NotFound);
@ -563,12 +564,38 @@ void TorrentsController::filePrioAction()
checkParams({"hash", "id", "priority"}); checkParams({"hash", "id", "priority"});
const QString hash = params()["hash"]; const QString hash = params()["hash"];
int fileID = params()["id"].toInt(); bool ok = false;
int priority = params()["priority"].toInt(); const int priority = params()["priority"].toInt(&ok);
if (!ok)
throw APIError(APIErrorType::BadParams, tr("Priority must be an integer"));
if (!BitTorrent::isValidFilePriority(static_cast<BitTorrent::FilePriority>(priority)))
throw APIError(APIErrorType::BadParams, tr("Priority is not valid"));
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash); BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(hash);
if (!torrent)
throw APIError(APIErrorType::NotFound);
if (!torrent->hasMetadata())
throw APIError(APIErrorType::Conflict, tr("Torrent's metadata has not yet downloaded"));
const int filesCount = torrent->filesCount();
QVector<int> priorities = torrent->filePriorities();
bool priorityChanged = false;
for (const QString &fileID : params()["id"].split('|')) {
const int id = fileID.toInt(&ok);
if (!ok)
throw APIError(APIErrorType::BadParams, tr("File IDs must be integers"));
if ((id < 0) || (id >= filesCount))
throw APIError(APIErrorType::Conflict, tr("File ID is not valid"));
if (priorities[id] != priority) {
priorities[id] = priority;
priorityChanged = true;
}
}
if (torrent && torrent->hasMetadata()) if (priorityChanged)
torrent->setFilePriority(fileID, priority); torrent->prioritizeFiles(priorities);
} }
void TorrentsController::uploadLimitAction() void TorrentsController::uploadLimitAction()

2
src/webui/www/private/properties_content.html

@ -133,7 +133,7 @@
<table class="dynamicTable" style="width: 100%"> <table class="dynamicTable" style="width: 100%">
<thead> <thead>
<tr> <tr>
<th style="width: 4.5em; border-right: 0"><input type="checkbox" id="tristate_cb" style="display: none;" onclick="javascript:switchCBState()" /><label id="all_files_cb" class="tristate" for="tristate_cb"></label></th> <th style="width: 4.5em; border-right: 0"><input type="checkbox" id="tristate_cb" onclick="switchCBState()" /></th>
<th>QBT_TR(Name)QBT_TR[CONTEXT=TorrentContentModel]</th> <th>QBT_TR(Name)QBT_TR[CONTEXT=TorrentContentModel]</th>
<th style="width: 150px;">QBT_TR(Size)QBT_TR[CONTEXT=TorrentContentModel]</th> <th style="width: 150px;">QBT_TR(Size)QBT_TR[CONTEXT=TorrentContentModel]</th>
<th style="width: 90px;">QBT_TR(Progress)QBT_TR[CONTEXT=TorrentContentModel]</th> <th style="width: 90px;">QBT_TR(Progress)QBT_TR[CONTEXT=TorrentContentModel]</th>

190
src/webui/www/private/scripts/prop-files.js

@ -1,74 +1,46 @@
var is_seed = true; var is_seed = true;
var current_hash = ""; var current_hash = "";
if (!(Browser.name == "ie" && Browser.version < 9)) {
$("all_files_cb").removeClass("tristate");
$("all_files_cb").removeClass("partial");
$("all_files_cb").removeClass("checked");
$("tristate_cb").style.display = "inline";
}
var setCBState = function(state) { var setCBState = function(state) {
if (Browser.name == "ie" && Browser.version < 9) { $("tristate_cb").state = state;
if (state == "partial") { if (state === "partial") {
if (!$("all_files_cb").hasClass("partial")) { $("tristate_cb").indeterminate = true;
$("all_files_cb").removeClass("checked");
$("all_files_cb").addClass("partial");
}
return;
}
if (state == "checked") {
if (!$("all_files_cb").hasClass("checked")) {
$("all_files_cb").removeClass("partial");
$("all_files_cb").addClass("checked");
}
return;
}
$("all_files_cb").removeClass("partial");
$("all_files_cb").removeClass("checked");
} }
else { else if (state === "checked") {
if (state == "partial") { $("tristate_cb").indeterminate = false;
$("tristate_cb").indeterminate = true; $("tristate_cb").checked = true;
} }
else if (state == "checked") { else if (state === "unchecked") {
$("tristate_cb").indeterminate = false; $("tristate_cb").indeterminate = false;
$("tristate_cb").checked = true; $("tristate_cb").checked = false;
}
else {
$("tristate_cb").indeterminate = false;
$("tristate_cb").checked = false;
}
} }
}; };
var switchCBState = function() { var switchCBState = function() {
// Uncheck // Uncheck
if ($("all_files_cb").hasClass("partial")) { if (($("tristate_cb").state === "partial") || ($("tristate_cb").state === "checked")) {
$("all_files_cb").removeClass("partial"); $("tristate_cb").state = "unchecked";
$("tristate_cb").checked = false;
// Uncheck all checkboxes // Uncheck all checkboxes
var indexes = [];
$$('input.DownloadedCB').each(function(item, index) { $$('input.DownloadedCB').each(function(item, index) {
item.erase("checked"); item.erase("checked");
setFilePriority(index, 0); indexes.push(index);
}); });
return; setFilePriority(indexes, 0);
} }
if ($("all_files_cb").hasClass("checked")) { else if ($("tristate_cb").state === "unchecked") {
$("all_files_cb").removeClass("checked"); // Check
// Uncheck all checkboxes $("tristate_cb").state = "checked";
$("tristate_cb").checked = true;
// Check all checkboxes
var indexes = [];
$$('input.DownloadedCB').each(function(item, index) { $$('input.DownloadedCB').each(function(item, index) {
item.erase("checked"); item.set("checked", "checked");
setFilePriority(index, 0); indexes.push(index);
}); });
return; setFilePriority(indexes, FilePriority.Normal);
} }
// Check
$("all_files_cb").addClass("checked");
// Check all checkboxes
$$('input.DownloadedCB').each(function(item, index) {
item.set("checked", "checked");
setFilePriority(index, 1);
});
}; };
var allCBChecked = function() { var allCBChecked = function() {
@ -91,24 +63,58 @@ var allCBUnchecked = function() {
return true; return true;
}; };
var FilePriority = {
"Ignored": 0,
"Normal": 1,
"High": 6,
"Maximum": 7,
"Mixed": -1
};
var normalizePriority = function(priority) {
switch (priority) {
case FilePriority.Ignored:
case FilePriority.Normal:
case FilePriority.High:
case FilePriority.Maximum:
case FilePriority.Mixed:
return priority;
default:
return FilePriority.Normal;
}
};
var setFilePriority = function(id, priority) { var setFilePriority = function(id, priority) {
if (current_hash === "") return; if (current_hash === "") return;
var ids = Array.isArray(id) ? id : [id];
clearTimeout(loadTorrentFilesDataTimer);
new Request({ new Request({
url: 'api/v2/torrents/filePrio', url: 'api/v2/torrents/filePrio',
method: 'post', method: 'post',
data: { data: {
'hash': current_hash, 'hash': current_hash,
'id': id, 'id': ids.join('|'),
'priority': priority 'priority': priority
},
onComplete: function() {
loadTorrentFilesDataTimer = loadTorrentFilesData.delay(1000);
} }
}).send(); }).send();
// Display or add combobox // Display or add combobox
if (priority > 0) { if (priority > 0) {
$('comboPrio' + id).set("value", 1); ids.forEach(function(_id) {
$('comboPrio' + id).removeClass("invisible"); if ($('comboPrio' + _id).hasClass("invisible")) {
$('comboPrio' + _id).set("value", priority);
$('comboPrio' + _id).removeClass("invisible");
}
});
} }
else { else {
$('comboPrio' + id).addClass("invisible"); ids.forEach(function(_id) {
if (!$('comboPrio' + _id).hasClass("invisible"))
$('comboPrio' + _id).addClass("invisible");
});
} }
}; };
@ -127,13 +133,11 @@ var createDownloadedCB = function(id, downloaded) {
if (allCBChecked()) { if (allCBChecked()) {
setCBState("checked"); setCBState("checked");
} }
else if (allCBUnchecked()) {
setCBState("unchecked");
}
else { else {
if (allCBUnchecked()) { setCBState("partial");
setCBState("unchecked");
}
else {
setCBState("partial");
}
} }
}); });
return CB; return CB;
@ -146,25 +150,21 @@ var createPriorityCombo = function(id, selected_prio) {
var new_prio = $('comboPrio' + id).get('value'); var new_prio = $('comboPrio' + id).get('value');
setFilePriority(id, new_prio); setFilePriority(id, new_prio);
}); });
var opt = new Element("option");
opt.set('value', '1'); function createOptionElement(priority, html) {
opt.set('html', "QBT_TR(Normal)QBT_TR[CONTEXT=PropListDelegate]"); var elem = new Element("option");
if (selected_prio <= 1) elem.set('value', priority.toString());
opt.setAttribute('selected', ''); elem.set('html', html);
opt.injectInside(select); if (priority == selected_prio)
opt = new Element("option"); elem.setAttribute('selected', '');
opt.set('value', '2'); return elem;
opt.set('html', "QBT_TR(High)QBT_TR[CONTEXT=PropListDelegate]"); }
if (selected_prio == 2)
opt.setAttribute('selected', ''); createOptionElement(FilePriority.Normal, "QBT_TR(Normal)QBT_TR[CONTEXT=PropListDelegate]").injectInside(select);
opt.injectInside(select); createOptionElement(FilePriority.High, "QBT_TR(High)QBT_TR[CONTEXT=PropListDelegate]").injectInside(select);
opt = new Element("option"); createOptionElement(FilePriority.Maximum, "QBT_TR(Maximum)QBT_TR[CONTEXT=PropListDelegate]").injectInside(select);
opt.set('value', '7');
opt.set('html', "QBT_TR(Maximum)QBT_TR[CONTEXT=PropListDelegate]"); if (is_seed || (selected_prio === FilePriority.Ignored) || (selected_prio === FilePriority.Mixed)) {
if (selected_prio == 7)
opt.setAttribute('selected', '');
opt.injectInside(select);
if (is_seed || selected_prio < 1) {
select.addClass("invisible"); select.addClass("invisible");
} }
else { else {
@ -203,19 +203,21 @@ var filesDynTable = new Class({
var tds = tr.getElements('td'); var tds = tr.getElements('td');
for (var i = 0; i < row.length; ++i) { for (var i = 0; i < row.length; ++i) {
switch (i) { switch (i) {
case 0: case 0: // checkbox
if (row[i] > 0) if (row[i] > 0)
tds[i].getChildren('input')[0].set('checked', 'checked'); tds[i].getChildren('input')[0].set('checked', 'checked');
else else
tds[i].getChildren('input')[0].removeProperty('checked'); tds[i].getChildren('input')[0].removeProperty('checked');
break; break;
case 3: case 3: // progress bar
$('pbf_' + id).setValue(row[i].toFloat()); $('pbf_' + id).setValue(row[i].toFloat());
break; break;
case 4: case 4: // download priority
if (!is_seed && row[i] > 0) { var priority = normalizePriority(row[i]);
tds[i].getChildren('select').set('value', row[i]); if (!is_seed && (priority > 0)) {
$('comboPrio' + id).removeClass("invisible"); tds[i].getChildren('select').set('value', priority);
if ($('comboPrio' + id).hasClass("invisible"))
$('comboPrio' + id).removeClass("invisible");
} }
else { else {
if (!$('comboPrio' + id).hasClass("invisible")) if (!$('comboPrio' + id).hasClass("invisible"))
@ -259,7 +261,7 @@ var filesDynTable = new Class({
})); }));
break; break;
case 4: case 4:
td.adopt(createPriorityCombo(id, row[i])); td.adopt(createPriorityCombo(id, normalizePriority(row[i])));
break; break;
default: default:
td.set('html', row[i]); td.set('html', row[i]);
@ -327,13 +329,11 @@ var loadTorrentFilesData = function() {
if (allCBChecked()) { if (allCBChecked()) {
setCBState("checked"); setCBState("checked");
} }
else if (allCBUnchecked()) {
setCBState("unchecked");
}
else { else {
if (allCBUnchecked()) { setCBState("partial");
setCBState("unchecked");
}
else {
setCBState("partial");
}
} }
} }
else { else {

Loading…
Cancel
Save