Browse Source

- Initiated work on torrent labeling/categorization (functional but not perfect yet

adaptive-webui-19844
Christophe Dumez 15 years ago
parent
commit
ed803fb994
  1. BIN
      src/Icons/oxygen/feed-subscribe.png
  2. 4
      src/bittorrent.cpp
  3. 1
      src/icons.qrc
  4. 9
      src/torrentadditiondlg.h
  5. 35
      src/torrentpersistentdata.h
  6. 2
      src/transferlistdelegate.h
  7. 135
      src/transferlistfilterswidget.h
  8. 137
      src/transferlistwidget.cpp
  9. 10
      src/transferlistwidget.h
  10. 47
      src/ui/torrentadditiondlg.ui

BIN
src/Icons/oxygen/feed-subscribe.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

4
src/bittorrent.cpp

@ -910,6 +910,10 @@ QTorrentHandle Bittorrent::addTorrent(QString path, bool fromScanDir, QString fr
} }
// Save persistent data for new torrent // Save persistent data for new torrent
TorrentPersistentData::saveTorrentPersistentData(h); TorrentPersistentData::saveTorrentPersistentData(h);
// Save Label
if(TorrentTempData::hasTempData(hash)) {
TorrentPersistentData::saveLabel(hash, TorrentTempData::getLabel(hash));
}
// Save save_path // Save save_path
if(!defaultTempPath.isEmpty()) { if(!defaultTempPath.isEmpty()) {
qDebug("addTorrent: Saving save_path in persistent data: %s", savePath.toLocal8Bit().data()); qDebug("addTorrent: Saving save_path in persistent data: %s", savePath.toLocal8Bit().data());

1
src/icons.qrc

@ -168,6 +168,7 @@
<file>Icons/oxygen/urlseed.png</file> <file>Icons/oxygen/urlseed.png</file>
<file>Icons/oxygen/edit-cut.png</file> <file>Icons/oxygen/edit-cut.png</file>
<file>Icons/oxygen/unsubscribe.png</file> <file>Icons/oxygen/unsubscribe.png</file>
<file>Icons/oxygen/feed-subscribe.png</file>
<file>Icons/oxygen/subscribe16.png</file> <file>Icons/oxygen/subscribe16.png</file>
</qresource> </qresource>
</RCC> </RCC>

9
src/torrentadditiondlg.h

@ -195,6 +195,14 @@ QPoint screenCenter() const{
//torrentContentList->expandAll(); //torrentContentList->expandAll();
connect(savePathTxt, SIGNAL(textChanged(QString)), this, SLOT(updateDiskSpaceLabels())); connect(savePathTxt, SIGNAL(textChanged(QString)), this, SLOT(updateDiskSpaceLabels()));
updateDiskSpaceLabels(); updateDiskSpaceLabels();
// Load custom labels
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
settings.beginGroup(QString::fromUtf8("TransferListFilters"));
QStringList customLabels = settings.value("customLabels", QStringList()).toStringList();
foreach(const QString& label, customLabels) {
comboLabel->addItem(label);
}
// Show the dialog
show(); show();
} }
@ -319,6 +327,7 @@ public slots:
} }
// Save savepath // Save savepath
TorrentTempData::setSavePath(hash, savePath.path()); TorrentTempData::setSavePath(hash, savePath.path());
TorrentTempData::setLabel(hash, comboLabel->currentText().trimmed());
// Save last dir to remember it // Save last dir to remember it
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
settings.setValue(QString::fromUtf8("LastDirTorrentAdd"), savePathTxt->text()); settings.setValue(QString::fromUtf8("LastDirTorrentAdd"), savePathTxt->text());

35
src/torrentpersistentdata.h

@ -87,6 +87,15 @@ public:
settings.setValue("torrents-tmp", all_data); settings.setValue("torrents-tmp", all_data);
} }
static void setLabel(QString hash, QString label) {
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> data = all_data[hash].toHash();
data["label"] = label;
all_data[hash] = data;
settings.setValue("torrents-tmp", all_data);
}
static void setSequential(QString hash, bool sequential) { static void setSequential(QString hash, bool sequential) {
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();
@ -136,6 +145,15 @@ public:
return QString::null; return QString::null;
} }
static QString getLabel(QString hash) {
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> data = all_data[hash].toHash();
if(data.contains("label"))
return data["label"].toString();
return "";
}
static std::vector<int> getFilesPriority(QString hash) { static std::vector<int> getFilesPriority(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();
@ -211,6 +229,16 @@ public:
qDebug("TorrentPersistentData: Saving save_path: %s, hash: %s", save_path.toLocal8Bit().data(), hash.toLocal8Bit().data()); qDebug("TorrentPersistentData: Saving save_path: %s, hash: %s", save_path.toLocal8Bit().data(), hash.toLocal8Bit().data());
} }
static void saveLabel(QString hash, QString label) {
Q_ASSERT(!hash.isEmpty());
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[hash].toHash();
data["label"] = label;
all_data[hash] = data;
settings.setValue("torrents", all_data);
}
static void savePriority(QTorrentHandle h) { static void savePriority(QTorrentHandle h) {
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();
@ -238,6 +266,13 @@ public:
return data["save_path"].toString(); return data["save_path"].toString();
} }
static QString getLabel(QString hash) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[hash].toHash();
return data.value("label", "").toString();
}
static int getPriority(QString hash) { static int getPriority(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", QHash<QString, QVariant>()).toHash(); QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();

2
src/transferlistdelegate.h

@ -42,7 +42,7 @@
// Defines for download list list columns // Defines for download list list columns
enum TorrentState {STATE_DOWNLOADING, STATE_STALLED_DL, STATE_STALLED_UP, STATE_SEEDING, STATE_PAUSED_DL, STATE_PAUSED_UP, STATE_QUEUED_DL, STATE_QUEUED_UP, STATE_CHECKING_UP, STATE_CHECKING_DL, STATE_INVALID}; enum TorrentState {STATE_DOWNLOADING, STATE_STALLED_DL, STATE_STALLED_UP, STATE_SEEDING, STATE_PAUSED_DL, STATE_PAUSED_UP, STATE_QUEUED_DL, STATE_QUEUED_UP, STATE_CHECKING_UP, STATE_CHECKING_DL, STATE_INVALID};
enum Column {TR_NAME, TR_PRIORITY, TR_SIZE, TR_PROGRESS, TR_STATUS, TR_SEEDS, TR_PEERS, TR_DLSPEED, TR_UPSPEED, TR_ETA, TR_RATIO, TR_HASH}; enum Column {TR_NAME, TR_PRIORITY, TR_SIZE, TR_PROGRESS, TR_STATUS, TR_SEEDS, TR_PEERS, TR_DLSPEED, TR_UPSPEED, TR_ETA, TR_RATIO, TR_LABEL, TR_HASH};
class TransferListDelegate: public QItemDelegate { class TransferListDelegate: public QItemDelegate {
Q_OBJECT Q_OBJECT

135
src/transferlistfilterswidget.h

@ -33,67 +33,170 @@
#include <QListWidget> #include <QListWidget>
#include <QListWidgetItem> #include <QListWidgetItem>
#include <QFrame>
#include <QIcon> #include <QIcon>
#include <QSettings> #include <QSettings>
#include <QVBoxLayout>
#include <QMenu>
#include <QInputDialog>
#include "transferlistwidget.h" #include "transferlistwidget.h"
class TransferListFiltersWidget: public QListWidget { class TransferListFiltersWidget: public QFrame {
Q_OBJECT Q_OBJECT
private: private:
QStringList customLabels;
QListWidget* statusFilters;
QListWidget* labelFilters;
QVBoxLayout* vLayout;
TransferListWidget *transferList; TransferListWidget *transferList;
public: public:
TransferListFiltersWidget(QWidget *parent, TransferListWidget *transferList): QListWidget(parent), transferList(transferList) { TransferListFiltersWidget(QWidget *parent, TransferListWidget *transferList): QFrame(parent), transferList(transferList) {
// Add filters // Construct lists
QListWidgetItem *all = new QListWidgetItem(this); vLayout = new QVBoxLayout();
statusFilters = new QListWidget();
vLayout->addWidget(statusFilters);
labelFilters = new QListWidget();
vLayout->addWidget(labelFilters);
setLayout(vLayout);
// Limit status filters list height
statusFilters->setFixedHeight(100);
setContentsMargins(0,0,0,0);
vLayout->setSpacing(2);
// Add status filters
QListWidgetItem *all = new QListWidgetItem(statusFilters);
all->setData(Qt::DisplayRole, tr("All") + " (0)"); all->setData(Qt::DisplayRole, tr("All") + " (0)");
all->setData(Qt::DecorationRole, QIcon(":/Icons/skin/filterall.png")); all->setData(Qt::DecorationRole, QIcon(":/Icons/skin/filterall.png"));
QListWidgetItem *downloading = new QListWidgetItem(this); QListWidgetItem *downloading = new QListWidgetItem(statusFilters);
downloading->setData(Qt::DisplayRole, tr("Downloading") + " (0)"); downloading->setData(Qt::DisplayRole, tr("Downloading") + " (0)");
downloading->setData(Qt::DecorationRole, QIcon(":/Icons/skin/downloading.png")); downloading->setData(Qt::DecorationRole, QIcon(":/Icons/skin/downloading.png"));
QListWidgetItem *completed = new QListWidgetItem(this); QListWidgetItem *completed = new QListWidgetItem(statusFilters);
completed->setData(Qt::DisplayRole, tr("Completed") + " (0)"); completed->setData(Qt::DisplayRole, tr("Completed") + " (0)");
completed->setData(Qt::DecorationRole, QIcon(":/Icons/skin/uploading.png")); completed->setData(Qt::DecorationRole, QIcon(":/Icons/skin/uploading.png"));
QListWidgetItem *active = new QListWidgetItem(this); QListWidgetItem *active = new QListWidgetItem(statusFilters);
active->setData(Qt::DisplayRole, tr("Active") + " (0)"); active->setData(Qt::DisplayRole, tr("Active") + " (0)");
active->setData(Qt::DecorationRole, QIcon(":/Icons/skin/filteractive.png")); active->setData(Qt::DecorationRole, QIcon(":/Icons/skin/filteractive.png"));
QListWidgetItem *inactive = new QListWidgetItem(this); QListWidgetItem *inactive = new QListWidgetItem(statusFilters);
inactive->setData(Qt::DisplayRole, tr("Inactive") + " (0)"); inactive->setData(Qt::DisplayRole, tr("Inactive") + " (0)");
inactive->setData(Qt::DecorationRole, QIcon(":/Icons/skin/filterinactive.png")); inactive->setData(Qt::DecorationRole, QIcon(":/Icons/skin/filterinactive.png"));
// SIGNAL/SLOT // SIGNAL/SLOT
connect(this, SIGNAL(currentRowChanged(int)), transferList, SLOT(applyFilter(int))); connect(statusFilters, SIGNAL(currentRowChanged(int)), transferList, SLOT(applyStatusFilter(int)));
connect(transferList, SIGNAL(torrentStatusUpdate(uint,uint,uint,uint)), this, SLOT(updateTorrentNumbers(uint, uint, uint, uint))); connect(transferList, SIGNAL(torrentStatusUpdate(uint,uint,uint,uint)), this, SLOT(updateTorrentNumbers(uint, uint, uint, uint)));
connect(labelFilters, SIGNAL(currentRowChanged(int)), this, SLOT(applyLabelFilter(int)));
connect(transferList, SIGNAL(newLabel(QString)), this, SLOT(addLabel(QString)));
// Load settings // Load settings
loadSettings(); loadSettings();
// Add Label filters
QListWidgetItem *allLabels = new QListWidgetItem(labelFilters);
allLabels->setData(Qt::DisplayRole, tr("All labels") + " (0)");
QListWidgetItem *noLabel = new QListWidgetItem(labelFilters);
noLabel->setData(Qt::DisplayRole, tr("No label") + " (0)");
foreach(const QString& label, customLabels) {
QListWidgetItem *newLabel = new QListWidgetItem(labelFilters);
newLabel->setText(label + " (0)");
}
labelFilters->selectionModel()->select(labelFilters->model()->index(0,0), QItemSelectionModel::Select);
// Label menu
labelFilters->setContextMenuPolicy(Qt::CustomContextMenu);
connect(labelFilters, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showLabelMenu(QPoint)));
} }
~TransferListFiltersWidget() { ~TransferListFiltersWidget() {
saveSettings(); saveSettings();
delete statusFilters;
delete labelFilters;
delete vLayout;
} }
void saveSettings() const { void saveSettings() const {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
settings.beginGroup(QString::fromUtf8("TransferListFilters")); settings.beginGroup(QString::fromUtf8("TransferListFilters"));
settings.setValue("selectedFilterIndex", QVariant(currentRow())); settings.setValue("selectedFilterIndex", QVariant(statusFilters->currentRow()));
settings.setValue("customLabels", customLabels);
}
void saveCustomLabels() const {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
settings.beginGroup(QString::fromUtf8("TransferListFilters"));
settings.setValue("customLabels", customLabels);
} }
void loadSettings() { void loadSettings() {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
settings.beginGroup(QString::fromUtf8("TransferListFilters")); settings.beginGroup(QString::fromUtf8("TransferListFilters"));
setCurrentRow(settings.value("selectedFilterIndex", 0).toInt()); statusFilters->setCurrentRow(settings.value("selectedFilterIndex", 0).toInt());
customLabels = settings.value("customLabels", QStringList()).toStringList();
} }
protected slots: protected slots:
void updateTorrentNumbers(uint nb_downloading, uint nb_seeding, uint nb_active, uint nb_inactive) { void updateTorrentNumbers(uint nb_downloading, uint nb_seeding, uint nb_active, uint nb_inactive) {
item(FILTER_ALL)->setData(Qt::DisplayRole, tr("All")+" ("+QString::number(nb_active+nb_inactive)+")"); statusFilters->item(FILTER_ALL)->setData(Qt::DisplayRole, tr("All")+" ("+QString::number(nb_active+nb_inactive)+")");
item(FILTER_DOWNLOADING)->setData(Qt::DisplayRole, tr("Downloading")+" ("+QString::number(nb_downloading)+")"); statusFilters->item(FILTER_DOWNLOADING)->setData(Qt::DisplayRole, tr("Downloading")+" ("+QString::number(nb_downloading)+")");
item(FILTER_COMPLETED)->setData(Qt::DisplayRole, tr("Completed")+" ("+QString::number(nb_seeding)+")"); statusFilters->item(FILTER_COMPLETED)->setData(Qt::DisplayRole, tr("Completed")+" ("+QString::number(nb_seeding)+")");
item(FILTER_ACTIVE)->setData(Qt::DisplayRole, tr("Active")+" ("+QString::number(nb_active)+")"); statusFilters->item(FILTER_ACTIVE)->setData(Qt::DisplayRole, tr("Active")+" ("+QString::number(nb_active)+")");
item(FILTER_INACTIVE)->setData(Qt::DisplayRole, tr("Inactive")+" ("+QString::number(nb_inactive)+")"); statusFilters->item(FILTER_INACTIVE)->setData(Qt::DisplayRole, tr("Inactive")+" ("+QString::number(nb_inactive)+")");
}
void addLabel(QString label) {
if(label.trimmed().isEmpty()) return;
if(customLabels.contains(label)) return;
QListWidgetItem *newLabel = new QListWidgetItem(labelFilters);
newLabel->setText(label + " (0)");
customLabels << label;
saveCustomLabels();
}
void showLabelMenu(QPoint) {
QMenu labelMenu(labelFilters);
QAction *removeAct = 0;
if(!labelFilters->selectedItems().empty() && labelFilters->row(labelFilters->selectedItems().first()) > 1)
removeAct = labelMenu.addAction(QIcon(":/Icons/oxygen/list-remove.png"), tr("Remove label"));
QAction *addAct = labelMenu.addAction(QIcon(":/Icons/oxygen/list-add.png"), tr("Add label"));
QAction *act = 0;
act = labelMenu.exec(QCursor::pos());
if(act) {
if(act == removeAct) {
removeSelectedLabel();
return;
}
if(act == addAct) {
bool ok;
QString label = QInputDialog::getText(this, tr("New Label"), tr("Label:"), QLineEdit::Normal, "", &ok);
if (ok && !label.isEmpty()) {
addLabel(label);
}
return;
}
}
}
void removeSelectedLabel() {
int row = labelFilters->row(labelFilters->selectedItems().first());
Q_ASSERT(row > 1);
QString label = customLabels.takeAt(row - 2);
labelFilters->removeItemWidget(labelFilters->selectedItems().first());
transferList->removeLabelFromRows(label);
// Select first label
labelFilters->selectionModel()->select(labelFilters->model()->index(0,0), QItemSelectionModel::Select);
applyLabelFilter(0);
}
void applyLabelFilter(int row) {
switch(row) {
case 0:
transferList->applyLabelFilter("all");
break;
case 1:
transferList->applyLabelFilter("none");
break;
default:
transferList->applyLabelFilter(customLabels.at(row-2));
}
} }
}; };

137
src/transferlistwidget.cpp

@ -43,6 +43,7 @@
#include <QTimer> #include <QTimer>
#include <QSettings> #include <QSettings>
#include <QClipboard> #include <QClipboard>
#include <QInputDialog>
#include <QColor> #include <QColor>
#include <QUrl> #include <QUrl>
#include <QMenu> #include <QMenu>
@ -58,7 +59,7 @@ TransferListWidget::TransferListWidget(QWidget *parent, GUI *main_window, Bittor
setItemDelegate(listDelegate); setItemDelegate(listDelegate);
// Create transfer list model // Create transfer list model
listModel = new QStandardItemModel(0,12); listModel = new QStandardItemModel(0,13);
listModel->setHeaderData(TR_NAME, Qt::Horizontal, tr("Name", "i.e: torrent name")); listModel->setHeaderData(TR_NAME, Qt::Horizontal, tr("Name", "i.e: torrent name"));
listModel->setHeaderData(TR_PRIORITY, Qt::Horizontal, "#"); listModel->setHeaderData(TR_PRIORITY, Qt::Horizontal, "#");
listModel->horizontalHeaderItem(TR_PRIORITY)->setTextAlignment(Qt::AlignRight); listModel->horizontalHeaderItem(TR_PRIORITY)->setTextAlignment(Qt::AlignRight);
@ -78,15 +79,23 @@ TransferListWidget::TransferListWidget(QWidget *parent, GUI *main_window, Bittor
listModel->setHeaderData(TR_RATIO, Qt::Horizontal, tr("Ratio", "Share ratio")); listModel->setHeaderData(TR_RATIO, Qt::Horizontal, tr("Ratio", "Share ratio"));
listModel->horizontalHeaderItem(TR_RATIO)->setTextAlignment(Qt::AlignRight); listModel->horizontalHeaderItem(TR_RATIO)->setTextAlignment(Qt::AlignRight);
listModel->setHeaderData(TR_ETA, Qt::Horizontal, tr("ETA", "i.e: Estimated Time of Arrival / Time left")); listModel->setHeaderData(TR_ETA, Qt::Horizontal, tr("ETA", "i.e: Estimated Time of Arrival / Time left"));
listModel->setHeaderData(TR_LABEL, Qt::Horizontal, tr("Label"));
// Set Sort/Filter proxy // Set Sort/Filter proxy
labelFilterModel = new QSortFilterProxyModel();
labelFilterModel->setDynamicSortFilter(true);
labelFilterModel->setSourceModel(listModel);
labelFilterModel->setFilterKeyColumn(TR_LABEL);
labelFilterModel->setFilterRole(Qt::DisplayRole);
proxyModel = new QSortFilterProxyModel(); proxyModel = new QSortFilterProxyModel();
proxyModel->setDynamicSortFilter(true); proxyModel->setDynamicSortFilter(true);
proxyModel->setSourceModel(listModel); proxyModel->setSourceModel(labelFilterModel);
proxyModel->setFilterKeyColumn(TR_STATUS); proxyModel->setFilterKeyColumn(TR_STATUS);
proxyModel->setFilterRole(Qt::DisplayRole); proxyModel->setFilterRole(Qt::DisplayRole);
setModel(proxyModel); setModel(proxyModel);
// Visual settings // Visual settings
setRootIsDecorated(false); setRootIsDecorated(false);
setAllColumnsShowFocus(true); setAllColumnsShowFocus(true);
@ -96,6 +105,7 @@ TransferListWidget::TransferListWidget(QWidget *parent, GUI *main_window, Bittor
setAutoScroll(true); setAutoScroll(true);
hideColumn(TR_PRIORITY); hideColumn(TR_PRIORITY);
//hideColumn(TR_LABEL);
hideColumn(TR_HASH); hideColumn(TR_HASH);
loadHiddenColumns(); loadHiddenColumns();
// Load last columns width for transfer list // Load last columns width for transfer list
@ -132,6 +142,7 @@ TransferListWidget::~TransferListWidget() {
saveHiddenColumns(); saveHiddenColumns();
// Clean up // Clean up
delete refreshTimer; delete refreshTimer;
delete labelFilterModel;
delete proxyModel; delete proxyModel;
delete listModel; delete listModel;
delete listDelegate; delete listDelegate;
@ -151,6 +162,9 @@ void TransferListWidget::addTorrent(QTorrentHandle& h) {
listModel->setData(listModel->index(row, TR_ETA), QVariant((qlonglong)-1)); listModel->setData(listModel->index(row, TR_ETA), QVariant((qlonglong)-1));
listModel->setData(listModel->index(row, TR_SEEDS), QVariant((double)0.0)); listModel->setData(listModel->index(row, TR_SEEDS), QVariant((double)0.0));
listModel->setData(listModel->index(row, TR_PEERS), QVariant((double)0.0)); listModel->setData(listModel->index(row, TR_PEERS), QVariant((double)0.0));
QString label = TorrentPersistentData::getLabel(h.hash());
emit newLabel(label);
listModel->setData(listModel->index(row, TR_LABEL), QVariant(label));
if(BTSession->isQueueingEnabled()) if(BTSession->isQueueingEnabled())
listModel->setData(listModel->index(row, TR_PRIORITY), QVariant((int)h.queue_position())); listModel->setData(listModel->index(row, TR_PRIORITY), QVariant((int)h.queue_position()));
listModel->setData(listModel->index(row, TR_HASH), QVariant(h.hash())); listModel->setData(listModel->index(row, TR_HASH), QVariant(h.hash()));
@ -461,8 +475,18 @@ QString TransferListWidget::getHashFromRow(int row) const {
return listModel->data(listModel->index(row, TR_HASH)).toString(); return listModel->data(listModel->index(row, TR_HASH)).toString();
} }
QModelIndex TransferListWidget::mapToSource(QModelIndex index) const {
return labelFilterModel->mapToSource(proxyModel->mapToSource(index));
}
QStringList TransferListWidget::getCustomLabels() const {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
settings.beginGroup(QString::fromUtf8("TransferListFilters"));
return settings.value("customLabels", QStringList()).toStringList();
}
void TransferListWidget::torrentDoubleClicked(QModelIndex index) { void TransferListWidget::torrentDoubleClicked(QModelIndex index) {
int row = proxyModel->mapToSource(index).row(); int row = mapToSource(index).row();
QString hash = getHashFromRow(row); QString hash = getHashFromRow(row);
QTorrentHandle h = BTSession->getTorrentHandle(hash); QTorrentHandle h = BTSession->getTorrentHandle(hash);
if(!h.is_valid()) return; if(!h.is_valid()) return;
@ -494,7 +518,7 @@ void TransferListWidget::startSelectedTorrents() {
QModelIndexList selectedIndexes = selectionModel()->selectedRows(); QModelIndexList selectedIndexes = selectionModel()->selectedRows();
foreach(const QModelIndex &index, selectedIndexes) { foreach(const QModelIndex &index, selectedIndexes) {
// Get the file hash // Get the file hash
int row = proxyModel->mapToSource(index).row(); int row = mapToSource(index).row();
QString hash = getHashFromRow(row); QString hash = getHashFromRow(row);
QTorrentHandle h = BTSession->getTorrentHandle(hash); QTorrentHandle h = BTSession->getTorrentHandle(hash);
if(h.is_valid() && h.is_paused()) { if(h.is_valid() && h.is_paused()) {
@ -521,7 +545,7 @@ void TransferListWidget::pauseSelectedTorrents() {
QModelIndexList selectedIndexes = selectionModel()->selectedRows(); QModelIndexList selectedIndexes = selectionModel()->selectedRows();
foreach(const QModelIndex &index, selectedIndexes) { foreach(const QModelIndex &index, selectedIndexes) {
// Get the file hash // Get the file hash
int row = proxyModel->mapToSource(index).row(); int row = mapToSource(index).row();
QString hash = getHashFromRow(row); QString hash = getHashFromRow(row);
QTorrentHandle h = BTSession->getTorrentHandle(hash); QTorrentHandle h = BTSession->getTorrentHandle(hash);
if(h.is_valid() && !h.is_paused()) { if(h.is_valid() && !h.is_paused()) {
@ -553,7 +577,7 @@ void TransferListWidget::deleteSelectedTorrents() {
QStringList hashes; QStringList hashes;
foreach(const QModelIndex &index, selectedIndexes) { foreach(const QModelIndex &index, selectedIndexes) {
// Get the file hash // Get the file hash
hashes << getHashFromRow(proxyModel->mapToSource(index).row()); hashes << getHashFromRow(mapToSource(index).row());
} }
foreach(const QString &hash, hashes) { foreach(const QString &hash, hashes) {
deleteTorrent(getRowFromHash(hash), false); deleteTorrent(getRowFromHash(hash), false);
@ -568,7 +592,7 @@ void TransferListWidget::deleteSelectedTorrents() {
void TransferListWidget::increasePrioSelectedTorrents() { void TransferListWidget::increasePrioSelectedTorrents() {
QModelIndexList selectedIndexes = selectionModel()->selectedRows(); QModelIndexList selectedIndexes = selectionModel()->selectedRows();
foreach(const QModelIndex &index, selectedIndexes) { foreach(const QModelIndex &index, selectedIndexes) {
QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(proxyModel->mapToSource(index).row())); QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(mapToSource(index).row()));
if(h.is_valid() && !h.is_seed()) { if(h.is_valid() && !h.is_seed()) {
h.queue_position_up(); h.queue_position_up();
} }
@ -580,7 +604,7 @@ void TransferListWidget::increasePrioSelectedTorrents() {
void TransferListWidget::decreasePrioSelectedTorrents() { void TransferListWidget::decreasePrioSelectedTorrents() {
QModelIndexList selectedIndexes = selectionModel()->selectedRows(); QModelIndexList selectedIndexes = selectionModel()->selectedRows();
foreach(const QModelIndex &index, selectedIndexes) { foreach(const QModelIndex &index, selectedIndexes) {
QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(proxyModel->mapToSource(index).row())); QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(mapToSource(index).row()));
if(h.is_valid() && !h.is_seed()) { if(h.is_valid() && !h.is_seed()) {
h.queue_position_down(); h.queue_position_down();
} }
@ -591,7 +615,7 @@ void TransferListWidget::decreasePrioSelectedTorrents() {
void TransferListWidget::buySelectedTorrents() const { void TransferListWidget::buySelectedTorrents() const {
QModelIndexList selectedIndexes = selectionModel()->selectedRows(); QModelIndexList selectedIndexes = selectionModel()->selectedRows();
foreach(const QModelIndex &index, selectedIndexes) { foreach(const QModelIndex &index, selectedIndexes) {
QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(proxyModel->mapToSource(index).row())); QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(mapToSource(index).row()));
if(h.is_valid()) if(h.is_valid())
QDesktopServices::openUrl("http://match.sharemonkey.com/?info_hash="+h.hash()+"&n="+h.name()+"&cid=33"); QDesktopServices::openUrl("http://match.sharemonkey.com/?info_hash="+h.hash()+"&n="+h.name()+"&cid=33");
} }
@ -601,7 +625,7 @@ void TransferListWidget::copySelectedMagnetURIs() const {
QModelIndexList selectedIndexes = selectionModel()->selectedRows(); QModelIndexList selectedIndexes = selectionModel()->selectedRows();
QStringList magnet_uris; QStringList magnet_uris;
foreach(const QModelIndex &index, selectedIndexes) { foreach(const QModelIndex &index, selectedIndexes) {
QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(proxyModel->mapToSource(index).row())); QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(mapToSource(index).row()));
if(h.is_valid() && h.has_metadata()) if(h.is_valid() && h.has_metadata())
magnet_uris << misc::toQString(make_magnet_uri(h.get_torrent_info())); magnet_uris << misc::toQString(make_magnet_uri(h.get_torrent_info()));
} }
@ -616,7 +640,7 @@ void TransferListWidget::openSelectedTorrentsFolder() const {
QModelIndexList selectedIndexes = selectionModel()->selectedRows(); QModelIndexList selectedIndexes = selectionModel()->selectedRows();
QStringList pathsList; QStringList pathsList;
foreach(const QModelIndex &index, selectedIndexes) { foreach(const QModelIndex &index, selectedIndexes) {
QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(proxyModel->mapToSource(index).row())); QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(mapToSource(index).row()));
if(h.is_valid()) { if(h.is_valid()) {
QString savePath = h.save_path(); QString savePath = h.save_path();
if(!pathsList.contains(savePath)) { if(!pathsList.contains(savePath)) {
@ -631,7 +655,7 @@ void TransferListWidget::previewSelectedTorrents() {
QModelIndexList selectedIndexes = selectionModel()->selectedRows(); QModelIndexList selectedIndexes = selectionModel()->selectedRows();
QStringList pathsList; QStringList pathsList;
foreach(const QModelIndex &index, selectedIndexes) { foreach(const QModelIndex &index, selectedIndexes) {
QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(proxyModel->mapToSource(index).row())); QTorrentHandle h = BTSession->getTorrentHandle(getHashFromRow(mapToSource(index).row()));
if(h.is_valid() && h.has_metadata()) { if(h.is_valid() && h.has_metadata()) {
new previewSelect(this, h); new previewSelect(this, h);
} }
@ -646,7 +670,7 @@ void TransferListWidget::setDlLimitSelectedTorrents() {
bool all_same_limit = true; bool all_same_limit = true;
foreach(const QModelIndex &index, selectedIndexes) { foreach(const QModelIndex &index, selectedIndexes) {
// Get the file hash // Get the file hash
QString hash = getHashFromRow(proxyModel->mapToSource(index).row()); QString hash = getHashFromRow(mapToSource(index).row());
QTorrentHandle h = BTSession->getTorrentHandle(hash); QTorrentHandle h = BTSession->getTorrentHandle(hash);
if(h.is_valid() && !h.is_seed()) { if(h.is_valid() && !h.is_seed()) {
selected_torrents << h; selected_torrents << h;
@ -682,7 +706,7 @@ void TransferListWidget::setUpLimitSelectedTorrents() {
bool all_same_limit = true; bool all_same_limit = true;
foreach(const QModelIndex &index, selectedIndexes) { foreach(const QModelIndex &index, selectedIndexes) {
// Get the file hash // Get the file hash
QString hash = getHashFromRow(proxyModel->mapToSource(index).row()); QString hash = getHashFromRow(mapToSource(index).row());
QTorrentHandle h = BTSession->getTorrentHandle(hash); QTorrentHandle h = BTSession->getTorrentHandle(hash);
if(h.is_valid()) { if(h.is_valid()) {
selected_torrents << h; selected_torrents << h;
@ -713,7 +737,7 @@ void TransferListWidget::setUpLimitSelectedTorrents() {
void TransferListWidget::recheckSelectedTorrents() { void TransferListWidget::recheckSelectedTorrents() {
QModelIndexList selectedIndexes = selectionModel()->selectedRows(); QModelIndexList selectedIndexes = selectionModel()->selectedRows();
foreach(const QModelIndex &index, selectedIndexes){ foreach(const QModelIndex &index, selectedIndexes){
QString hash = getHashFromRow(proxyModel->mapToSource(index).row()); QString hash = getHashFromRow(mapToSource(index).row());
QTorrentHandle h = BTSession->getTorrentHandle(hash); QTorrentHandle h = BTSession->getTorrentHandle(hash);
if(h.is_valid() && h.has_metadata()) if(h.is_valid() && h.has_metadata())
h.force_recheck(); h.force_recheck();
@ -787,7 +811,7 @@ void TransferListWidget::toggleSelectedTorrentsSuperSeeding() {
QModelIndexList selectedIndexes = selectionModel()->selectedRows(); QModelIndexList selectedIndexes = selectionModel()->selectedRows();
foreach(const QModelIndex &index, selectedIndexes) { foreach(const QModelIndex &index, selectedIndexes) {
// Get the file hash // Get the file hash
QString hash = getHashFromRow(proxyModel->mapToSource(index).row()); QString hash = getHashFromRow(mapToSource(index).row());
QTorrentHandle h = BTSession->getTorrentHandle(hash); QTorrentHandle h = BTSession->getTorrentHandle(hash);
if(h.is_valid() && h.has_metadata()) { if(h.is_valid() && h.has_metadata()) {
h.super_seeding(!h.super_seeding()); h.super_seeding(!h.super_seeding());
@ -800,7 +824,7 @@ void TransferListWidget::toggleSelectedTorrentsSequentialDownload() {
QModelIndexList selectedIndexes = selectionModel()->selectedRows(); QModelIndexList selectedIndexes = selectionModel()->selectedRows();
foreach(const QModelIndex &index, selectedIndexes) { foreach(const QModelIndex &index, selectedIndexes) {
// Get the file hash // Get the file hash
QString hash = getHashFromRow(proxyModel->mapToSource(index).row()); QString hash = getHashFromRow(mapToSource(index).row());
QTorrentHandle h = BTSession->getTorrentHandle(hash); QTorrentHandle h = BTSession->getTorrentHandle(hash);
if(h.is_valid() && h.has_metadata()) { if(h.is_valid() && h.has_metadata()) {
h.set_sequential_download(!h.is_sequential_download()); h.set_sequential_download(!h.is_sequential_download());
@ -812,7 +836,7 @@ void TransferListWidget::toggleSelectedFirstLastPiecePrio() {
QModelIndexList selectedIndexes = selectionModel()->selectedRows(); QModelIndexList selectedIndexes = selectionModel()->selectedRows();
foreach(const QModelIndex &index, selectedIndexes) { foreach(const QModelIndex &index, selectedIndexes) {
// Get the file hash // Get the file hash
QString hash = getHashFromRow(proxyModel->mapToSource(index).row()); QString hash = getHashFromRow(mapToSource(index).row());
QTorrentHandle h = BTSession->getTorrentHandle(hash); QTorrentHandle h = BTSession->getTorrentHandle(hash);
if(h.is_valid() && h.has_metadata()) { if(h.is_valid() && h.has_metadata()) {
h.prioritize_first_last_piece(!h.first_last_piece_first()); h.prioritize_first_last_piece(!h.first_last_piece_first());
@ -820,6 +844,33 @@ void TransferListWidget::toggleSelectedFirstLastPiecePrio() {
} }
} }
void TransferListWidget::askNewLabelForSelection() {
// Ask for label
bool ok;
QString label = QInputDialog::getText(this, tr("New Label"), tr("Label:"), QLineEdit::Normal, "", &ok);
if (ok && !label.isEmpty()) {
emit newLabel(label);
// Assign label to selection
setSelectionLabel(label);
}
}
void TransferListWidget::setSelectionLabel(QString label) {
QModelIndexList selectedIndexes = selectionModel()->selectedRows();
foreach(const QModelIndex &index, selectedIndexes) {
QString hash = getHashFromRow(mapToSource(index).row());
proxyModel->setData(proxyModel->index(index.row(), TR_LABEL), QVariant(label));
TorrentPersistentData::saveLabel(hash, label);
}
}
void TransferListWidget::removeLabelFromRows(QString label) {
for(int i=0; i<listModel->rowCount(); ++i) {
if(label == listModel->data(listModel->index(i, TR_LABEL), Qt::DisplayRole))
listModel->setData(listModel->index(i, TR_LABEL), "", Qt::DisplayRole);
}
}
void TransferListWidget::displayListMenu(const QPoint&) { void TransferListWidget::displayListMenu(const QPoint&) {
// Create actions // Create actions
QAction actionStart(QIcon(QString::fromUtf8(":/Icons/skin/play.png")), tr("Start"), 0); QAction actionStart(QIcon(QString::fromUtf8(":/Icons/skin/play.png")), tr("Start"), 0);
@ -871,7 +922,7 @@ void TransferListWidget::displayListMenu(const QPoint&) {
qDebug("Displaying menu"); qDebug("Displaying menu");
foreach(const QModelIndex &index, selectedIndexes) { foreach(const QModelIndex &index, selectedIndexes) {
// Get the file name // Get the file name
QString hash = getHashFromRow(proxyModel->mapToSource(index).row()); QString hash = getHashFromRow(mapToSource(index).row());
// Get handle and pause the torrent // Get handle and pause the torrent
h = BTSession->getTorrentHandle(hash); h = BTSession->getTorrentHandle(hash);
if(!h.is_valid()) continue; if(!h.is_valid()) continue;
@ -926,6 +977,17 @@ void TransferListWidget::displayListMenu(const QPoint&) {
listMenu.addSeparator(); listMenu.addSeparator();
listMenu.addAction(&actionDelete); listMenu.addAction(&actionDelete);
listMenu.addSeparator(); listMenu.addSeparator();
// Label Menu
QStringList customLabels = getCustomLabels();
QList<QAction*> labelActions;
QMenu *labelMenu = listMenu.addMenu(QIcon(":/Icons/oxygen/feed-subscribe.png"), "Label");
labelActions << labelMenu->addAction(tr("New..."));
labelActions << labelMenu->addAction(tr("Reset"));
labelMenu->addSeparator();
foreach(const QString &label, customLabels) {
labelActions << labelMenu->addAction(label);
}
listMenu.addSeparator();
if(one_not_seed) if(one_not_seed)
listMenu.addAction(&actionSet_download_limit); listMenu.addAction(&actionSet_download_limit);
listMenu.addAction(&actionSet_upload_limit); listMenu.addAction(&actionSet_upload_limit);
@ -988,7 +1050,25 @@ void TransferListWidget::displayListMenu(const QPoint&) {
listMenu.addAction(&actionCopy_magnet_link); listMenu.addAction(&actionCopy_magnet_link);
listMenu.addAction(&actionBuy_it); listMenu.addAction(&actionBuy_it);
// Call menu // Call menu
listMenu.exec(QCursor::pos()); QAction *act = 0;
act = listMenu.exec(QCursor::pos());
if(act) {
// Parse label actions only (others have slots assigned)
int i = labelActions.indexOf(act);
if(i >= 0) {
// Label action
if(i == 0) {
// New Label
askNewLabelForSelection();
} else {
QString label = "";
if(i > 1)
label = customLabels.at(i-2);
// Update Label
setSelectionLabel(label);
}
}
}
} }
// Save columns width in a file to remember them // Save columns width in a file to remember them
@ -1092,7 +1172,7 @@ void TransferListWidget::loadLastSortedColumn() {
void TransferListWidget::currentChanged(const QModelIndex& current, const QModelIndex&) { void TransferListWidget::currentChanged(const QModelIndex& current, const QModelIndex&) {
QTorrentHandle h; QTorrentHandle h;
if(current.isValid()) { if(current.isValid()) {
int row = proxyModel->mapToSource(current).row(); int row = mapToSource(current).row();
h = BTSession->getTorrentHandle(getHashFromRow(row)); h = BTSession->getTorrentHandle(getHashFromRow(row));
// Scroll Fix // Scroll Fix
scrollTo(current); scrollTo(current);
@ -1100,7 +1180,20 @@ void TransferListWidget::currentChanged(const QModelIndex& current, const QModel
emit currentTorrentChanged(h); emit currentTorrentChanged(h);
} }
void TransferListWidget::applyFilter(int f) { void TransferListWidget::applyLabelFilter(QString label) {
if(label == "all") {
labelFilterModel->setFilterRegExp(QRegExp());
return;
}
if(label == "none") {
labelFilterModel->setFilterRegExp(QRegExp("^$"));
return;
}
qDebug("Applying Label filter: %s", label.toLocal8Bit().data());
labelFilterModel->setFilterRegExp(QRegExp("^"+label+"$", Qt::CaseSensitive));
}
void TransferListWidget::applyStatusFilter(int f) {
switch(f) { switch(f) {
case FILTER_DOWNLOADING: case FILTER_DOWNLOADING:
proxyModel->setFilterRegExp(QRegExp(QString::number(STATE_DOWNLOADING)+"|"+QString::number(STATE_STALLED_DL)+"|"+ proxyModel->setFilterRegExp(QRegExp(QString::number(STATE_DOWNLOADING)+"|"+QString::number(STATE_STALLED_DL)+"|"+

10
src/transferlistwidget.h

@ -50,6 +50,7 @@ private:
TransferListDelegate *listDelegate; TransferListDelegate *listDelegate;
QStandardItemModel *listModel; QStandardItemModel *listModel;
QSortFilterProxyModel *proxyModel; QSortFilterProxyModel *proxyModel;
QSortFilterProxyModel *labelFilterModel;
Bittorrent* BTSession; Bittorrent* BTSession;
QTimer *refreshTimer; QTimer *refreshTimer;
GUI *main_window; GUI *main_window;
@ -61,6 +62,8 @@ public:
protected: protected:
int getRowFromHash(QString hash) const; int getRowFromHash(QString hash) const;
QString getHashFromRow(int row) const; QString getHashFromRow(int row) const;
QModelIndex mapToSource(QModelIndex index) const;
QStringList getCustomLabels() const;
void saveColWidthList(); void saveColWidthList();
bool loadColWidthList(); bool loadColWidthList();
void saveLastSortedColumn(); void saveLastSortedColumn();
@ -84,6 +87,8 @@ protected slots:
#endif #endif
void toggleSelectedTorrentsSequentialDownload(); void toggleSelectedTorrentsSequentialDownload();
void toggleSelectedFirstLastPiecePrio(); void toggleSelectedFirstLastPiecePrio();
void setSelectionLabel(QString label);
void askNewLabelForSelection();
void setRowColor(int row, QColor color); void setRowColor(int row, QColor color);
public slots: public slots:
@ -107,12 +112,15 @@ public slots:
void previewSelectedTorrents(); void previewSelectedTorrents();
void hidePriorityColumn(bool hide); void hidePriorityColumn(bool hide);
void displayDLHoSMenu(const QPoint&); void displayDLHoSMenu(const QPoint&);
void applyFilter(int f); void applyStatusFilter(int f);
void applyLabelFilter(QString label);
void previewFile(QString filePath); void previewFile(QString filePath);
void removeLabelFromRows(QString label);
signals: signals:
void currentTorrentChanged(QTorrentHandle &h); void currentTorrentChanged(QTorrentHandle &h);
void torrentStatusUpdate(unsigned int nb_downloading, unsigned int nb_seeding, unsigned int nb_active, unsigned int nb_inactive); void torrentStatusUpdate(unsigned int nb_downloading, unsigned int nb_seeding, unsigned int nb_active, unsigned int nb_inactive);
void newLabel(QString label);
}; };

47
src/ui/torrentadditiondlg.ui

@ -14,9 +14,6 @@
<string>Torrent addition dialog</string> <string>Torrent addition dialog</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>3</number>
</property>
<item> <item>
<widget class="QLabel" name="fileNameLbl"> <widget class="QLabel" name="fileNameLbl">
<property name="text"> <property name="text">
@ -64,6 +61,8 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_2"> <layout class="QHBoxLayout" name="horizontalLayout_2">
<item> <item>
@ -133,6 +132,48 @@
</item> </item>
</layout> </layout>
</item> </item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Label:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboLabel">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>26</height>
</size>
</property>
<property name="editable">
<bool>true</bool>
</property>
<property name="frame">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>17</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item> <item>
<widget class="QLabel" name="torrentContentLbl"> <widget class="QLabel" name="torrentContentLbl">
<property name="font"> <property name="font">

Loading…
Cancel
Save