Browse Source

Merge pull request #10895 from Chocobo1/tracker

Add dialog to mass edit torrent's tracker
adaptive-webui-19844
Mike Tzou 5 years ago committed by GitHub
parent
commit
24932f6cb6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      src/base/bittorrent/trackerentry.cpp
  2. 3
      src/base/bittorrent/trackerentry.h
  3. 3
      src/gui/CMakeLists.txt
  4. 3
      src/gui/gui.pri
  5. 112
      src/gui/trackerentriesdialog.cpp
  6. 64
      src/gui/trackerentriesdialog.h
  7. 43
      src/gui/trackerentriesdialog.ui
  8. 59
      src/gui/transferlistwidget.cpp
  9. 4
      src/gui/transferlistwidget.h

8
src/base/bittorrent/trackerentry.cpp

@ -154,5 +154,11 @@ const lt::announce_entry &TrackerEntry::nativeEntry() const
bool BitTorrent::operator==(const TrackerEntry &left, const TrackerEntry &right) bool BitTorrent::operator==(const TrackerEntry &left, const TrackerEntry &right)
{ {
return (QUrl(left.url()) == QUrl(right.url())); return ((left.tier() == right.tier())
&& QUrl(left.url()) == QUrl(right.url()));
}
uint BitTorrent::qHash(const TrackerEntry &key, const uint seed)
{
return (::qHash(key.url(), seed) ^ key.tier());
} }

3
src/base/bittorrent/trackerentry.h

@ -31,6 +31,8 @@
#include <libtorrent/announce_entry.hpp> #include <libtorrent/announce_entry.hpp>
#include <QtGlobal>
class QString; class QString;
namespace BitTorrent namespace BitTorrent
@ -70,6 +72,7 @@ namespace BitTorrent
}; };
bool operator==(const TrackerEntry &left, const TrackerEntry &right); bool operator==(const TrackerEntry &left, const TrackerEntry &right);
uint qHash(const TrackerEntry &key, uint seed);
} }
#endif // BITTORRENT_TRACKERENTRY_H #endif // BITTORRENT_TRACKERENTRY_H

3
src/gui/CMakeLists.txt

@ -52,6 +52,7 @@ torrentcontentmodelfolder.h
torrentcontentmodelitem.h torrentcontentmodelitem.h
torrentcontenttreeview.h torrentcontenttreeview.h
torrentcreatordialog.h torrentcreatordialog.h
trackerentriesdialog.h
transferlistdelegate.h transferlistdelegate.h
transferlistfilterswidget.h transferlistfilterswidget.h
transferlistmodel.h transferlistmodel.h
@ -98,6 +99,7 @@ torrentcontentmodelfolder.cpp
torrentcontentmodelitem.cpp torrentcontentmodelitem.cpp
torrentcontenttreeview.cpp torrentcontenttreeview.cpp
torrentcreatordialog.cpp torrentcreatordialog.cpp
trackerentriesdialog.cpp
transferlistdelegate.cpp transferlistdelegate.cpp
transferlistfilterswidget.cpp transferlistfilterswidget.cpp
transferlistmodel.cpp transferlistmodel.cpp
@ -125,6 +127,7 @@ speedlimitdialog.ui
statsdialog.ui statsdialog.ui
torrentcategorydialog.ui torrentcategorydialog.ui
torrentcreatordialog.ui torrentcreatordialog.ui
trackerentriesdialog.ui
updownratiodialog.ui updownratiodialog.ui
) )

3
src/gui/gui.pri

@ -57,6 +57,7 @@ HEADERS += \
$$PWD/torrentcontentmodelitem.h \ $$PWD/torrentcontentmodelitem.h \
$$PWD/torrentcontenttreeview.h \ $$PWD/torrentcontenttreeview.h \
$$PWD/torrentcreatordialog.h \ $$PWD/torrentcreatordialog.h \
$$PWD/trackerentriesdialog.h \
$$PWD/transferlistdelegate.h \ $$PWD/transferlistdelegate.h \
$$PWD/transferlistfilterswidget.h \ $$PWD/transferlistfilterswidget.h \
$$PWD/transferlistmodel.h \ $$PWD/transferlistmodel.h \
@ -114,6 +115,7 @@ SOURCES += \
$$PWD/torrentcontentmodelitem.cpp \ $$PWD/torrentcontentmodelitem.cpp \
$$PWD/torrentcontenttreeview.cpp \ $$PWD/torrentcontenttreeview.cpp \
$$PWD/torrentcreatordialog.cpp \ $$PWD/torrentcreatordialog.cpp \
$$PWD/trackerentriesdialog.cpp \
$$PWD/transferlistdelegate.cpp \ $$PWD/transferlistdelegate.cpp \
$$PWD/transferlistfilterswidget.cpp \ $$PWD/transferlistfilterswidget.cpp \
$$PWD/transferlistmodel.cpp \ $$PWD/transferlistmodel.cpp \
@ -157,6 +159,7 @@ FORMS += \
$$PWD/statsdialog.ui \ $$PWD/statsdialog.ui \
$$PWD/torrentcategorydialog.ui \ $$PWD/torrentcategorydialog.ui \
$$PWD/torrentcreatordialog.ui \ $$PWD/torrentcreatordialog.ui \
$$PWD/trackerentriesdialog.ui \
$$PWD/updownratiodialog.ui $$PWD/updownratiodialog.ui
RESOURCES += $$PWD/about.qrc RESOURCES += $$PWD/about.qrc

112
src/gui/trackerentriesdialog.cpp

@ -0,0 +1,112 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2019 Mike Tzou (Chocobo1)
*
* 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 "trackerentriesdialog.h"
#include <algorithm>
#include <QHash>
#include "base/bittorrent/trackerentry.h"
#include "ui_trackerentriesdialog.h"
#include "utils.h"
#define SETTINGS_KEY(name) "TrackerEntriesDialog/" name
TrackerEntriesDialog::TrackerEntriesDialog(QWidget *parent)
: QDialog(parent)
, m_ui(new Ui::TrackerEntriesDialog)
, m_storeDialogSize(SETTINGS_KEY("Dimension"))
{
m_ui->setupUi(this);
connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(m_ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
loadSettings();
}
TrackerEntriesDialog::~TrackerEntriesDialog()
{
saveSettings();
delete m_ui;
}
void TrackerEntriesDialog::setTrackers(const QVector<BitTorrent::TrackerEntry> &trackers)
{
int maxTier = -1;
QHash<int, QString> tiers; // <tier, tracker URLs>
for (const BitTorrent::TrackerEntry &entry : trackers) {
tiers[entry.tier()] += (entry.url() + '\n');
maxTier = std::max(maxTier, entry.tier());
}
QString text = tiers.value(0);
for (int i = 1; i <= maxTier; ++i)
text += ('\n' + tiers.value(i));
m_ui->plainTextEdit->setPlainText(text);
}
QVector<BitTorrent::TrackerEntry> TrackerEntriesDialog::trackers() const
{
const QString plainText = m_ui->plainTextEdit->toPlainText();
const QVector<QStringRef> lines = plainText.splitRef('\n');
QVector<BitTorrent::TrackerEntry> entries;
entries.reserve(lines.size());
int tier = 0;
for (QStringRef line : lines) {
line = line.trimmed();
if (line.isEmpty()) {
++tier;
continue;
}
BitTorrent::TrackerEntry entry {line.toString()};
entry.setTier(tier);
entries.append(entry);
}
return entries;
}
void TrackerEntriesDialog::saveSettings()
{
m_storeDialogSize = size();
}
void TrackerEntriesDialog::loadSettings()
{
Utils::Gui::resize(this, m_storeDialogSize);
}

64
src/gui/trackerentriesdialog.h

@ -0,0 +1,64 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2019 Mike Tzou (Chocobo1)
*
* 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
#include <QDialog>
#include <QVector>
#include "base/settingvalue.h"
namespace BitTorrent
{
class TrackerEntry;
}
namespace Ui
{
class TrackerEntriesDialog;
}
class TrackerEntriesDialog : public QDialog
{
Q_OBJECT
Q_DISABLE_COPY(TrackerEntriesDialog)
public:
explicit TrackerEntriesDialog(QWidget *parent);
~TrackerEntriesDialog() override;
void setTrackers(const QVector<BitTorrent::TrackerEntry> &trackers);
QVector<BitTorrent::TrackerEntry> trackers() const;
private:
void saveSettings();
void loadSettings();
Ui::TrackerEntriesDialog *m_ui;
CachedSettingValue<QSize> m_storeDialogSize;
};

43
src/gui/trackerentriesdialog.ui

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TrackerEntriesDialog</class>
<widget class="QDialog" name="TrackerEntriesDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>506</width>
<height>500</height>
</rect>
</property>
<property name="windowTitle">
<string>Edit trackers</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>One tracker URL per line.
- You can split the trackers into groups by inserting blank lines.
- All trackers within the same group will belong to the same tier.
- The group on top will be tier 0, the next group tier 1 and so on.
- Below will show the common subset of trackers of the selected torrents.</string>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="plainTextEdit"/>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

59
src/gui/transferlistwidget.cpp

@ -28,6 +28,8 @@
#include "transferlistwidget.h" #include "transferlistwidget.h"
#include <algorithm>
#include <QClipboard> #include <QClipboard>
#include <QDebug> #include <QDebug>
#include <QFileDialog> #include <QFileDialog>
@ -36,6 +38,7 @@
#include <QMessageBox> #include <QMessageBox>
#include <QRegExp> #include <QRegExp>
#include <QRegularExpression> #include <QRegularExpression>
#include <QSet>
#include <QShortcut> #include <QShortcut>
#include <QStylePainter> #include <QStylePainter>
#include <QTableView> #include <QTableView>
@ -44,6 +47,7 @@
#include "base/bittorrent/session.h" #include "base/bittorrent/session.h"
#include "base/bittorrent/torrenthandle.h" #include "base/bittorrent/torrenthandle.h"
#include "base/bittorrent/trackerentry.h"
#include "base/global.h" #include "base/global.h"
#include "base/logger.h" #include "base/logger.h"
#include "base/preferences.h" #include "base/preferences.h"
@ -59,6 +63,7 @@
#include "previewselectdialog.h" #include "previewselectdialog.h"
#include "speedlimitdialog.h" #include "speedlimitdialog.h"
#include "torrentcategorydialog.h" #include "torrentcategorydialog.h"
#include "trackerentriesdialog.h"
#include "transferlistdelegate.h" #include "transferlistdelegate.h"
#include "transferlistmodel.h" #include "transferlistmodel.h"
#include "transferlistsortmodel.h" #include "transferlistsortmodel.h"
@ -73,7 +78,7 @@ namespace
{ {
using ToggleFn = std::function<void (Qt::CheckState)>; using ToggleFn = std::function<void (Qt::CheckState)>;
QStringList extractHashes(const QList<BitTorrent::TorrentHandle *> &torrents) QStringList extractHashes(const QVector<BitTorrent::TorrentHandle *> &torrents)
{ {
QStringList hashes; QStringList hashes;
for (BitTorrent::TorrentHandle *const torrent : torrents) for (BitTorrent::TorrentHandle *const torrent : torrents)
@ -395,9 +400,9 @@ void TransferListWidget::torrentDoubleClicked()
} }
} }
QList<BitTorrent::TorrentHandle *> TransferListWidget::getSelectedTorrents() const QVector<BitTorrent::TorrentHandle *> TransferListWidget::getSelectedTorrents() const
{ {
QList<BitTorrent::TorrentHandle *> torrents; QVector<BitTorrent::TorrentHandle *> torrents;
for (const QModelIndex &index : asConst(selectionModel()->selectedRows())) for (const QModelIndex &index : asConst(selectionModel()->selectedRows()))
torrents << m_listModel->torrentHandle(mapToSource(index)); torrents << m_listModel->torrentHandle(mapToSource(index));
@ -406,7 +411,7 @@ QList<BitTorrent::TorrentHandle *> TransferListWidget::getSelectedTorrents() con
void TransferListWidget::setSelectedTorrentsLocation() void TransferListWidget::setSelectedTorrentsLocation()
{ {
const QList<BitTorrent::TorrentHandle *> torrents = getSelectedTorrents(); const QVector<BitTorrent::TorrentHandle *> torrents = getSelectedTorrents();
if (torrents.isEmpty()) return; if (torrents.isEmpty()) return;
const QString oldLocation = torrents[0]->savePath(); const QString oldLocation = torrents[0]->savePath();
@ -489,7 +494,7 @@ void TransferListWidget::deleteSelectedTorrents(bool deleteLocalFiles)
{ {
if (m_mainWindow->currentTabWidget() != this) return; if (m_mainWindow->currentTabWidget() != this) return;
const QList<BitTorrent::TorrentHandle *> torrents = getSelectedTorrents(); const QVector<BitTorrent::TorrentHandle *> torrents = getSelectedTorrents();
if (torrents.empty()) return; if (torrents.empty()) return;
if (Preferences::instance()->confirmTorrentDeletion() if (Preferences::instance()->confirmTorrentDeletion()
@ -503,7 +508,7 @@ void TransferListWidget::deleteVisibleTorrents()
{ {
if (m_sortFilterModel->rowCount() <= 0) return; if (m_sortFilterModel->rowCount() <= 0) return;
QList<BitTorrent::TorrentHandle *> torrents; QVector<BitTorrent::TorrentHandle *> torrents;
for (int i = 0; i < m_sortFilterModel->rowCount(); ++i) for (int i = 0; i < m_sortFilterModel->rowCount(); ++i)
torrents << m_listModel->torrentHandle(mapToSource(m_sortFilterModel->index(i, 0))); torrents << m_listModel->torrentHandle(mapToSource(m_sortFilterModel->index(i, 0)));
@ -617,7 +622,7 @@ void TransferListWidget::previewSelectedTorrents()
void TransferListWidget::setDlLimitSelectedTorrents() void TransferListWidget::setDlLimitSelectedTorrents()
{ {
QList<BitTorrent::TorrentHandle *> torrentsList; QVector<BitTorrent::TorrentHandle *> torrentsList;
for (BitTorrent::TorrentHandle *const torrent : asConst(getSelectedTorrents())) { for (BitTorrent::TorrentHandle *const torrent : asConst(getSelectedTorrents())) {
if (torrent->isSeed()) if (torrent->isSeed())
continue; continue;
@ -647,7 +652,7 @@ void TransferListWidget::setDlLimitSelectedTorrents()
void TransferListWidget::setUpLimitSelectedTorrents() void TransferListWidget::setUpLimitSelectedTorrents()
{ {
QList<BitTorrent::TorrentHandle *> torrentsList = getSelectedTorrents(); QVector<BitTorrent::TorrentHandle *> torrentsList = getSelectedTorrents();
if (torrentsList.empty()) return; if (torrentsList.empty()) return;
int oldLimit = torrentsList.first()->uploadLimit(); int oldLimit = torrentsList.first()->uploadLimit();
@ -672,7 +677,7 @@ void TransferListWidget::setUpLimitSelectedTorrents()
void TransferListWidget::setMaxRatioSelectedTorrents() void TransferListWidget::setMaxRatioSelectedTorrents()
{ {
const QList<BitTorrent::TorrentHandle *> torrents = getSelectedTorrents(); const QVector<BitTorrent::TorrentHandle *> torrents = getSelectedTorrents();
if (torrents.isEmpty()) return; if (torrents.isEmpty()) return;
qreal currentMaxRatio = BitTorrent::Session::instance()->globalMaxRatio(); qreal currentMaxRatio = BitTorrent::Session::instance()->globalMaxRatio();
@ -807,6 +812,39 @@ void TransferListWidget::askAddTagsForSelection()
addSelectionTag(tag); addSelectionTag(tag);
} }
void TransferListWidget::editTorrentTrackers()
{
const QVector<BitTorrent::TorrentHandle *> torrents = getSelectedTorrents();
QVector<BitTorrent::TrackerEntry> commonTrackers;
if (!torrents.empty()) {
commonTrackers = torrents[0]->trackers();
for (const BitTorrent::TorrentHandle *torrent : torrents) {
QSet<BitTorrent::TrackerEntry> trackerSet;
for (const BitTorrent::TrackerEntry &entry : asConst(torrent->trackers()))
trackerSet.insert(entry);
commonTrackers.erase(std::remove_if(commonTrackers.begin(), commonTrackers.end()
, [&trackerSet](const BitTorrent::TrackerEntry &entry) { return !trackerSet.contains(entry); })
, commonTrackers.end());
}
}
auto trackerDialog = new TrackerEntriesDialog(this);
trackerDialog->setAttribute(Qt::WA_DeleteOnClose);
trackerDialog->setTrackers(commonTrackers);
connect(trackerDialog, &QDialog::accepted, this, [torrents, trackerDialog]()
{
for (BitTorrent::TorrentHandle *torrent : torrents)
torrent->replaceTrackers(trackerDialog->trackers());
});
trackerDialog->open();
}
void TransferListWidget::confirmRemoveAllTagsForSelection() void TransferListWidget::confirmRemoveAllTagsForSelection()
{ {
QMessageBox::StandardButton response = QMessageBox::question( QMessageBox::StandardButton response = QMessageBox::question(
@ -951,6 +989,8 @@ void TransferListWidget::displayListMenu(const QPoint &)
actionAutoTMM->setCheckable(true); actionAutoTMM->setCheckable(true);
actionAutoTMM->setToolTip(tr("Automatic mode means that various torrent properties(eg save path) will be decided by the associated category")); actionAutoTMM->setToolTip(tr("Automatic mode means that various torrent properties(eg save path) will be decided by the associated category"));
connect(actionAutoTMM, &QAction::triggered, this, &TransferListWidget::setSelectedAutoTMMEnabled); connect(actionAutoTMM, &QAction::triggered, this, &TransferListWidget::setSelectedAutoTMMEnabled);
QAction *actionEditTracker = new QAction(GuiIconProvider::instance()->getIcon("edit-rename"), tr("Edit trackers..."), listMenu);
connect(actionEditTracker, &QAction::triggered, this, &TransferListWidget::editTorrentTrackers);
// End of actions // End of actions
// Enable/disable pause/start action given the DL state // Enable/disable pause/start action given the DL state
@ -1046,6 +1086,7 @@ void TransferListWidget::displayListMenu(const QPoint &)
listMenu->addAction(actionSetTorrentPath); listMenu->addAction(actionSetTorrentPath);
if (selectedIndexes.size() == 1) if (selectedIndexes.size() == 1)
listMenu->addAction(actionRename); listMenu->addAction(actionRename);
listMenu->addAction(actionEditTracker);
// Category Menu // Category Menu
QStringList categories = BitTorrent::Session::instance()->categories().keys(); QStringList categories = BitTorrent::Session::instance()->categories().keys();

4
src/gui/transferlistwidget.h

@ -31,6 +31,7 @@
#include <functional> #include <functional>
#include <QTreeView> #include <QTreeView>
#include <QVector>
namespace BitTorrent namespace BitTorrent
{ {
@ -99,7 +100,7 @@ protected:
QModelIndex mapToSource(const QModelIndex &index) const; QModelIndex mapToSource(const QModelIndex &index) const;
QModelIndex mapFromSource(const QModelIndex &index) const; QModelIndex mapFromSource(const QModelIndex &index) const;
bool loadSettings(); bool loadSettings();
QList<BitTorrent::TorrentHandle *> getSelectedTorrents() const; QVector<BitTorrent::TorrentHandle *> getSelectedTorrents() const;
protected slots: protected slots:
void torrentDoubleClicked(); void torrentDoubleClicked();
@ -118,6 +119,7 @@ signals:
private: private:
void wheelEvent(QWheelEvent *event) override; void wheelEvent(QWheelEvent *event) override;
void askAddTagsForSelection(); void askAddTagsForSelection();
void editTorrentTrackers();
void confirmRemoveAllTagsForSelection(); void confirmRemoveAllTagsForSelection();
QStringList askTagsForSelection(const QString &dialogTitle); QStringList askTagsForSelection(const QString &dialogTitle);
void applyToSelectedTorrents(const std::function<void (BitTorrent::TorrentHandle *const)> &fn); void applyToSelectedTorrents(const std::function<void (BitTorrent::TorrentHandle *const)> &fn);

Loading…
Cancel
Save