From ed803fb9946c1e49e4e767477b59352ea73738c6 Mon Sep 17 00:00:00 2001 From: Christophe Dumez Date: Tue, 15 Dec 2009 19:52:43 +0000 Subject: [PATCH] - Initiated work on torrent labeling/categorization (functional but not perfect yet --- src/Icons/oxygen/feed-subscribe.png | Bin 0 -> 1037 bytes src/bittorrent.cpp | 6 +- src/icons.qrc | 1 + src/torrentadditiondlg.h | 35 ++++--- src/torrentpersistentdata.h | 35 +++++++ src/transferlistdelegate.h | 2 +- src/transferlistfilterswidget.h | 135 +++++++++++++++++++++++---- src/transferlistwidget.cpp | 137 +++++++++++++++++++++++----- src/transferlistwidget.h | 10 +- src/ui/torrentadditiondlg.ui | 123 ++++++++++++++++--------- 10 files changed, 389 insertions(+), 95 deletions(-) create mode 100644 src/Icons/oxygen/feed-subscribe.png diff --git a/src/Icons/oxygen/feed-subscribe.png b/src/Icons/oxygen/feed-subscribe.png new file mode 100644 index 0000000000000000000000000000000000000000..6acc38b315ed777dacd32cd89dde85b89519d3e2 GIT binary patch literal 1037 zcmV+o1oHcdP))!uoVydb6umX=;WGkAV} z{;Ab!y~LdF($doQbvoTbB9U;M2|PVLZ7V7&+TbiNHa9oB!Qpf|f8&KBhR*@Cwzgi$ z&d$CQi^VSKIYctMySpeaFGqTMI!#Va+68!IWJJ$4RA*#lw0{y@TU-03(P(_Kx3{No znFxo&nz&r>LJt_;b$EDq%i(bRWwY6C9~>OGIyyRD=ud)HRaG^yZ%zg(7K;TwpAS1b zI~r7k-|x4rudhENq5@w0*Zlna$GyG1UxPz>oD#}io->=xN@r&$8XFriJ3EW1sVQ)V z$j!}#q9_nmusfoPb4yE0+j4$ND=I1~G^oPS)6;{NmKJStcXu~L<}))h;D$jal`6So zRK?2)EmP z2;dq69^r)eilw%h*ew z8+t0J1RsMB4i1vX<00Og#IHjM?U2u%8Z6-~l|MDaFCYo+6!*>omhh{rHI|3<&1ryA zI`PBh8v&SDSuBNRKDsu^(|MG6oE2k5SW$5;b#yO!G$#HBk7m6HGJZo!00000NkvXX Hu0mjfl=Rbr literal 0 HcmV?d00001 diff --git a/src/bittorrent.cpp b/src/bittorrent.cpp index b50f2ba84..e4d93b715 100644 --- a/src/bittorrent.cpp +++ b/src/bittorrent.cpp @@ -198,7 +198,7 @@ void Bittorrent::setUploadLimit(QString hash, long val) { void Bittorrent::handleDownloadFailure(QString url, QString reason) { emit downloadFromUrlFailure(url, reason); // Clean up - QUrl qurl = QUrl::fromEncoded(url.toLocal8Bit()); + QUrl qurl = QUrl::fromEncoded(url.toLocal8Bit()); int index = url_skippingDlg.indexOf(qurl); if(index >= 0) url_skippingDlg.removeAt(index); @@ -910,6 +910,10 @@ QTorrentHandle Bittorrent::addTorrent(QString path, bool fromScanDir, QString fr } // Save persistent data for new torrent TorrentPersistentData::saveTorrentPersistentData(h); + // Save Label + if(TorrentTempData::hasTempData(hash)) { + TorrentPersistentData::saveLabel(hash, TorrentTempData::getLabel(hash)); + } // Save save_path if(!defaultTempPath.isEmpty()) { qDebug("addTorrent: Saving save_path in persistent data: %s", savePath.toLocal8Bit().data()); diff --git a/src/icons.qrc b/src/icons.qrc index 6cadc6a6f..98a761a33 100644 --- a/src/icons.qrc +++ b/src/icons.qrc @@ -168,6 +168,7 @@ Icons/oxygen/urlseed.png Icons/oxygen/edit-cut.png Icons/oxygen/unsubscribe.png + Icons/oxygen/feed-subscribe.png Icons/oxygen/subscribe16.png \ No newline at end of file diff --git a/src/torrentadditiondlg.h b/src/torrentadditiondlg.h index 067482918..6fb1b4af3 100644 --- a/src/torrentadditiondlg.h +++ b/src/torrentadditiondlg.h @@ -126,21 +126,21 @@ public: } } -// Screen center point -QPoint screenCenter() const{ - int scrn = 0; - QWidget *w = this->topLevelWidget(); + // Screen center point + QPoint screenCenter() const{ + int scrn = 0; + QWidget *w = this->topLevelWidget(); - if(w) - scrn = QApplication::desktop()->screenNumber(w); - else if(QApplication::desktop()->isVirtualDesktop()) - scrn = QApplication::desktop()->screenNumber(QCursor::pos()); - else - scrn = QApplication::desktop()->screenNumber(this); + if(w) + scrn = QApplication::desktop()->screenNumber(w); + else if(QApplication::desktop()->isVirtualDesktop()) + scrn = QApplication::desktop()->screenNumber(QCursor::pos()); + else + scrn = QApplication::desktop()->screenNumber(this); - QRect desk(QApplication::desktop()->availableGeometry(scrn)); - return QPoint((desk.width() - this->frameGeometry().width()) / 2, (desk.height() - this->frameGeometry().height()) / 2); -} + QRect desk(QApplication::desktop()->availableGeometry(scrn)); + return QPoint((desk.width() - this->frameGeometry().width()) / 2, (desk.height() - this->frameGeometry().height()) / 2); + } void saveSettings() { QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); @@ -195,6 +195,14 @@ QPoint screenCenter() const{ //torrentContentList->expandAll(); connect(savePathTxt, SIGNAL(textChanged(QString)), this, SLOT(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(); } @@ -319,6 +327,7 @@ public slots: } // Save savepath TorrentTempData::setSavePath(hash, savePath.path()); + TorrentTempData::setLabel(hash, comboLabel->currentText().trimmed()); // Save last dir to remember it QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); settings.setValue(QString::fromUtf8("LastDirTorrentAdd"), savePathTxt->text()); diff --git a/src/torrentpersistentdata.h b/src/torrentpersistentdata.h index 97401a531..48ec93424 100644 --- a/src/torrentpersistentdata.h +++ b/src/torrentpersistentdata.h @@ -87,6 +87,15 @@ public: settings.setValue("torrents-tmp", all_data); } + static void setLabel(QString hash, QString label) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents-tmp", QHash()).toHash(); + QHash 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) { QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); QHash all_data = settings.value("torrents-tmp", QHash()).toHash(); @@ -136,6 +145,15 @@ public: return QString::null; } + static QString getLabel(QString hash) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents-tmp", QHash()).toHash(); + QHash data = all_data[hash].toHash(); + if(data.contains("label")) + return data["label"].toString(); + return ""; + } + static std::vector getFilesPriority(QString hash) { QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); QHash all_data = settings.value("torrents-tmp", QHash()).toHash(); @@ -211,6 +229,16 @@ public: 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 all_data = settings.value("torrents", QHash()).toHash(); + QHash data = all_data[hash].toHash(); + data["label"] = label; + all_data[hash] = data; + settings.setValue("torrents", all_data); + } + static void savePriority(QTorrentHandle h) { QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); QHash all_data = settings.value("torrents", QHash()).toHash(); @@ -238,6 +266,13 @@ public: return data["save_path"].toString(); } + static QString getLabel(QString hash) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents", QHash()).toHash(); + QHash data = all_data[hash].toHash(); + return data.value("label", "").toString(); + } + static int getPriority(QString hash) { QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); QHash all_data = settings.value("torrents", QHash()).toHash(); diff --git a/src/transferlistdelegate.h b/src/transferlistdelegate.h index f89a6707a..84eb9be8c 100644 --- a/src/transferlistdelegate.h +++ b/src/transferlistdelegate.h @@ -42,7 +42,7 @@ // 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 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 { Q_OBJECT diff --git a/src/transferlistfilterswidget.h b/src/transferlistfilterswidget.h index 026c6100a..c2bcf8f89 100644 --- a/src/transferlistfilterswidget.h +++ b/src/transferlistfilterswidget.h @@ -33,67 +33,170 @@ #include #include +#include #include #include +#include +#include +#include #include "transferlistwidget.h" -class TransferListFiltersWidget: public QListWidget { +class TransferListFiltersWidget: public QFrame { Q_OBJECT private: + QStringList customLabels; + QListWidget* statusFilters; + QListWidget* labelFilters; + QVBoxLayout* vLayout; TransferListWidget *transferList; public: - TransferListFiltersWidget(QWidget *parent, TransferListWidget *transferList): QListWidget(parent), transferList(transferList) { - // Add filters - QListWidgetItem *all = new QListWidgetItem(this); + TransferListFiltersWidget(QWidget *parent, TransferListWidget *transferList): QFrame(parent), transferList(transferList) { + // Construct lists + 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::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::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::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::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::DecorationRole, QIcon(":/Icons/skin/filterinactive.png")); // 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(labelFilters, SIGNAL(currentRowChanged(int)), this, SLOT(applyLabelFilter(int))); + connect(transferList, SIGNAL(newLabel(QString)), this, SLOT(addLabel(QString))); // Load settings 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() { saveSettings(); + delete statusFilters; + delete labelFilters; + delete vLayout; } void saveSettings() const { QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); 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() { QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); 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: 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)+")"); - item(FILTER_DOWNLOADING)->setData(Qt::DisplayRole, tr("Downloading")+" ("+QString::number(nb_downloading)+")"); - item(FILTER_COMPLETED)->setData(Qt::DisplayRole, tr("Completed")+" ("+QString::number(nb_seeding)+")"); - 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_ALL)->setData(Qt::DisplayRole, tr("All")+" ("+QString::number(nb_active+nb_inactive)+")"); + statusFilters->item(FILTER_DOWNLOADING)->setData(Qt::DisplayRole, tr("Downloading")+" ("+QString::number(nb_downloading)+")"); + statusFilters->item(FILTER_COMPLETED)->setData(Qt::DisplayRole, tr("Completed")+" ("+QString::number(nb_seeding)+")"); + statusFilters->item(FILTER_ACTIVE)->setData(Qt::DisplayRole, tr("Active")+" ("+QString::number(nb_active)+")"); + 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)); + } } }; diff --git a/src/transferlistwidget.cpp b/src/transferlistwidget.cpp index 8fc1c521b..a4e32bffc 100644 --- a/src/transferlistwidget.cpp +++ b/src/transferlistwidget.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -58,7 +59,7 @@ TransferListWidget::TransferListWidget(QWidget *parent, GUI *main_window, Bittor setItemDelegate(listDelegate); // 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_PRIORITY, Qt::Horizontal, "#"); 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->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_LABEL, Qt::Horizontal, tr("Label")); // 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->setDynamicSortFilter(true); - proxyModel->setSourceModel(listModel); + proxyModel->setSourceModel(labelFilterModel); proxyModel->setFilterKeyColumn(TR_STATUS); proxyModel->setFilterRole(Qt::DisplayRole); setModel(proxyModel); + // Visual settings setRootIsDecorated(false); setAllColumnsShowFocus(true); @@ -96,6 +105,7 @@ TransferListWidget::TransferListWidget(QWidget *parent, GUI *main_window, Bittor setAutoScroll(true); hideColumn(TR_PRIORITY); + //hideColumn(TR_LABEL); hideColumn(TR_HASH); loadHiddenColumns(); // Load last columns width for transfer list @@ -132,6 +142,7 @@ TransferListWidget::~TransferListWidget() { saveHiddenColumns(); // Clean up delete refreshTimer; + delete labelFilterModel; delete proxyModel; delete listModel; 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_SEEDS), 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()) listModel->setData(listModel->index(row, TR_PRIORITY), QVariant((int)h.queue_position())); 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(); } +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) { - int row = proxyModel->mapToSource(index).row(); + int row = mapToSource(index).row(); QString hash = getHashFromRow(row); QTorrentHandle h = BTSession->getTorrentHandle(hash); if(!h.is_valid()) return; @@ -494,7 +518,7 @@ void TransferListWidget::startSelectedTorrents() { QModelIndexList selectedIndexes = selectionModel()->selectedRows(); foreach(const QModelIndex &index, selectedIndexes) { // Get the file hash - int row = proxyModel->mapToSource(index).row(); + int row = mapToSource(index).row(); QString hash = getHashFromRow(row); QTorrentHandle h = BTSession->getTorrentHandle(hash); if(h.is_valid() && h.is_paused()) { @@ -521,7 +545,7 @@ void TransferListWidget::pauseSelectedTorrents() { QModelIndexList selectedIndexes = selectionModel()->selectedRows(); foreach(const QModelIndex &index, selectedIndexes) { // Get the file hash - int row = proxyModel->mapToSource(index).row(); + int row = mapToSource(index).row(); QString hash = getHashFromRow(row); QTorrentHandle h = BTSession->getTorrentHandle(hash); if(h.is_valid() && !h.is_paused()) { @@ -553,7 +577,7 @@ void TransferListWidget::deleteSelectedTorrents() { QStringList hashes; foreach(const QModelIndex &index, selectedIndexes) { // Get the file hash - hashes << getHashFromRow(proxyModel->mapToSource(index).row()); + hashes << getHashFromRow(mapToSource(index).row()); } foreach(const QString &hash, hashes) { deleteTorrent(getRowFromHash(hash), false); @@ -568,7 +592,7 @@ void TransferListWidget::deleteSelectedTorrents() { void TransferListWidget::increasePrioSelectedTorrents() { QModelIndexList selectedIndexes = selectionModel()->selectedRows(); 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()) { h.queue_position_up(); } @@ -580,7 +604,7 @@ void TransferListWidget::increasePrioSelectedTorrents() { void TransferListWidget::decreasePrioSelectedTorrents() { QModelIndexList selectedIndexes = selectionModel()->selectedRows(); 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()) { h.queue_position_down(); } @@ -591,7 +615,7 @@ void TransferListWidget::decreasePrioSelectedTorrents() { void TransferListWidget::buySelectedTorrents() const { QModelIndexList selectedIndexes = selectionModel()->selectedRows(); 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()) 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(); QStringList magnet_uris; 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()) magnet_uris << misc::toQString(make_magnet_uri(h.get_torrent_info())); } @@ -616,7 +640,7 @@ void TransferListWidget::openSelectedTorrentsFolder() const { QModelIndexList selectedIndexes = selectionModel()->selectedRows(); QStringList pathsList; 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()) { QString savePath = h.save_path(); if(!pathsList.contains(savePath)) { @@ -631,7 +655,7 @@ void TransferListWidget::previewSelectedTorrents() { QModelIndexList selectedIndexes = selectionModel()->selectedRows(); QStringList pathsList; 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()) { new previewSelect(this, h); } @@ -646,7 +670,7 @@ void TransferListWidget::setDlLimitSelectedTorrents() { bool all_same_limit = true; foreach(const QModelIndex &index, selectedIndexes) { // Get the file hash - QString hash = getHashFromRow(proxyModel->mapToSource(index).row()); + QString hash = getHashFromRow(mapToSource(index).row()); QTorrentHandle h = BTSession->getTorrentHandle(hash); if(h.is_valid() && !h.is_seed()) { selected_torrents << h; @@ -682,7 +706,7 @@ void TransferListWidget::setUpLimitSelectedTorrents() { bool all_same_limit = true; foreach(const QModelIndex &index, selectedIndexes) { // Get the file hash - QString hash = getHashFromRow(proxyModel->mapToSource(index).row()); + QString hash = getHashFromRow(mapToSource(index).row()); QTorrentHandle h = BTSession->getTorrentHandle(hash); if(h.is_valid()) { selected_torrents << h; @@ -713,7 +737,7 @@ void TransferListWidget::setUpLimitSelectedTorrents() { void TransferListWidget::recheckSelectedTorrents() { QModelIndexList selectedIndexes = selectionModel()->selectedRows(); foreach(const QModelIndex &index, selectedIndexes){ - QString hash = getHashFromRow(proxyModel->mapToSource(index).row()); + QString hash = getHashFromRow(mapToSource(index).row()); QTorrentHandle h = BTSession->getTorrentHandle(hash); if(h.is_valid() && h.has_metadata()) h.force_recheck(); @@ -787,7 +811,7 @@ void TransferListWidget::toggleSelectedTorrentsSuperSeeding() { QModelIndexList selectedIndexes = selectionModel()->selectedRows(); foreach(const QModelIndex &index, selectedIndexes) { // Get the file hash - QString hash = getHashFromRow(proxyModel->mapToSource(index).row()); + QString hash = getHashFromRow(mapToSource(index).row()); QTorrentHandle h = BTSession->getTorrentHandle(hash); if(h.is_valid() && h.has_metadata()) { h.super_seeding(!h.super_seeding()); @@ -800,7 +824,7 @@ void TransferListWidget::toggleSelectedTorrentsSequentialDownload() { QModelIndexList selectedIndexes = selectionModel()->selectedRows(); foreach(const QModelIndex &index, selectedIndexes) { // Get the file hash - QString hash = getHashFromRow(proxyModel->mapToSource(index).row()); + QString hash = getHashFromRow(mapToSource(index).row()); QTorrentHandle h = BTSession->getTorrentHandle(hash); if(h.is_valid() && h.has_metadata()) { h.set_sequential_download(!h.is_sequential_download()); @@ -812,7 +836,7 @@ void TransferListWidget::toggleSelectedFirstLastPiecePrio() { QModelIndexList selectedIndexes = selectionModel()->selectedRows(); foreach(const QModelIndex &index, selectedIndexes) { // Get the file hash - QString hash = getHashFromRow(proxyModel->mapToSource(index).row()); + QString hash = getHashFromRow(mapToSource(index).row()); QTorrentHandle h = BTSession->getTorrentHandle(hash); if(h.is_valid() && h.has_metadata()) { 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; irowCount(); ++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&) { // Create actions QAction actionStart(QIcon(QString::fromUtf8(":/Icons/skin/play.png")), tr("Start"), 0); @@ -871,7 +922,7 @@ void TransferListWidget::displayListMenu(const QPoint&) { qDebug("Displaying menu"); foreach(const QModelIndex &index, selectedIndexes) { // Get the file name - QString hash = getHashFromRow(proxyModel->mapToSource(index).row()); + QString hash = getHashFromRow(mapToSource(index).row()); // Get handle and pause the torrent h = BTSession->getTorrentHandle(hash); if(!h.is_valid()) continue; @@ -926,6 +977,17 @@ void TransferListWidget::displayListMenu(const QPoint&) { listMenu.addSeparator(); listMenu.addAction(&actionDelete); listMenu.addSeparator(); + // Label Menu + QStringList customLabels = getCustomLabels(); + QList 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) listMenu.addAction(&actionSet_download_limit); listMenu.addAction(&actionSet_upload_limit); @@ -988,7 +1050,25 @@ void TransferListWidget::displayListMenu(const QPoint&) { listMenu.addAction(&actionCopy_magnet_link); listMenu.addAction(&actionBuy_it); // 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 @@ -1092,7 +1172,7 @@ void TransferListWidget::loadLastSortedColumn() { void TransferListWidget::currentChanged(const QModelIndex& current, const QModelIndex&) { QTorrentHandle h; if(current.isValid()) { - int row = proxyModel->mapToSource(current).row(); + int row = mapToSource(current).row(); h = BTSession->getTorrentHandle(getHashFromRow(row)); // Scroll Fix scrollTo(current); @@ -1100,7 +1180,20 @@ void TransferListWidget::currentChanged(const QModelIndex& current, const QModel 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) { case FILTER_DOWNLOADING: proxyModel->setFilterRegExp(QRegExp(QString::number(STATE_DOWNLOADING)+"|"+QString::number(STATE_STALLED_DL)+"|"+ diff --git a/src/transferlistwidget.h b/src/transferlistwidget.h index d40f685f8..132870753 100644 --- a/src/transferlistwidget.h +++ b/src/transferlistwidget.h @@ -50,6 +50,7 @@ private: TransferListDelegate *listDelegate; QStandardItemModel *listModel; QSortFilterProxyModel *proxyModel; + QSortFilterProxyModel *labelFilterModel; Bittorrent* BTSession; QTimer *refreshTimer; GUI *main_window; @@ -61,6 +62,8 @@ public: protected: int getRowFromHash(QString hash) const; QString getHashFromRow(int row) const; + QModelIndex mapToSource(QModelIndex index) const; + QStringList getCustomLabels() const; void saveColWidthList(); bool loadColWidthList(); void saveLastSortedColumn(); @@ -84,6 +87,8 @@ protected slots: #endif void toggleSelectedTorrentsSequentialDownload(); void toggleSelectedFirstLastPiecePrio(); + void setSelectionLabel(QString label); + void askNewLabelForSelection(); void setRowColor(int row, QColor color); public slots: @@ -107,12 +112,15 @@ public slots: void previewSelectedTorrents(); void hidePriorityColumn(bool hide); void displayDLHoSMenu(const QPoint&); - void applyFilter(int f); + void applyStatusFilter(int f); + void applyLabelFilter(QString label); void previewFile(QString filePath); + void removeLabelFromRows(QString label); signals: void currentTorrentChanged(QTorrentHandle &h); void torrentStatusUpdate(unsigned int nb_downloading, unsigned int nb_seeding, unsigned int nb_active, unsigned int nb_inactive); + void newLabel(QString label); }; diff --git a/src/ui/torrentadditiondlg.ui b/src/ui/torrentadditiondlg.ui index 91a791ec9..245ce30e4 100644 --- a/src/ui/torrentadditiondlg.ui +++ b/src/ui/torrentadditiondlg.ui @@ -14,9 +14,6 @@ Torrent addition dialog - - 3 - @@ -65,68 +62,112 @@ - + - - - Torrent size: - - + + + + + Torrent size: + + + + + + + Unknown + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - - Unknown - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - + + + + + Free disk space: + + + + + + + Unknown + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - + - + - Free disk space: + Label: - - - Unknown + + + + 16777215 + 26 + - - - - - - + + true + + + true - + Qt::Horizontal 40 - 20 + 17