mirror of
https://github.com/transmission/transmission
synced 2025-01-30 19:03:04 +00:00
feat: nicer add-torrent workflow in the qt client. (#1410)
* If you accidentally try to add a lot of duplicates -- for example, by starting up with a lot of duplicate torrents in the watchdir -- then coalesce all of them into a single error dialog instead of spamming the desktop with a different dialog for every duplicate. * Make the duplicate torrent dialog's error message slightly terser to make it accommodate a long list of torrents: omit the ".torrent" file suffixes and show an abbreviated form of the existing torrent's hash. * Support searching by torrent hash in the filterbar's text entry. This is useful when copy/pasting the hash from the duplicate torrent error dialog and is also consistent with the GTK client behavior. * Copy the GTK client's behavior of appending ".added" to the end of .torrent files after they've been added to the session.
This commit is contained in:
parent
1bb9e2eef2
commit
cf9b81eb7d
4 changed files with 56 additions and 12 deletions
|
@ -121,7 +121,7 @@ QString AddData::readableShortName() const
|
|||
switch (type)
|
||||
{
|
||||
case FILENAME:
|
||||
return QFileInfo(filename).fileName();
|
||||
return QFileInfo(filename).baseName();
|
||||
|
||||
case URL:
|
||||
return url.path().split(QLatin1Char('/')).last();
|
||||
|
|
|
@ -311,6 +311,9 @@ Session::Session(QString config_dir, Prefs& prefs) :
|
|||
connect(&rpc_, SIGNAL(dataSendProgress()), this, SIGNAL(dataSendProgress()));
|
||||
connect(&rpc_, SIGNAL(networkResponse(QNetworkReply::NetworkError, QString)), this,
|
||||
SIGNAL(networkResponse(QNetworkReply::NetworkError, QString)));
|
||||
|
||||
duplicates_timer_.setSingleShot(true);
|
||||
connect(&duplicates_timer_, &QTimer::timeout, this, &Session::onDuplicatesTimer);
|
||||
}
|
||||
|
||||
Session::~Session()
|
||||
|
@ -1100,23 +1103,30 @@ void Session::addTorrent(AddData const& add_me, tr_variant* args, bool trash_ori
|
|||
d->show();
|
||||
});
|
||||
|
||||
q->add([add_me](RpcResponse const& r)
|
||||
q->add([this, add_me](RpcResponse const& r)
|
||||
{
|
||||
tr_variant* dup;
|
||||
bool session_has_torrent = false;
|
||||
|
||||
if (!tr_variantDictFindDict(r.args.get(), TR_KEY_torrent_duplicate, &dup))
|
||||
if (tr_variantDictFindDict(r.args.get(), TR_KEY_torrent_added, &dup))
|
||||
{
|
||||
return;
|
||||
session_has_torrent = true;
|
||||
}
|
||||
else if (tr_variantDictFindDict(r.args.get(), TR_KEY_torrent_duplicate, &dup))
|
||||
{
|
||||
session_has_torrent = true;
|
||||
|
||||
auto const hash = dictFind<QString>(dup, TR_KEY_hashString);
|
||||
if (hash)
|
||||
{
|
||||
duplicates_.try_emplace(add_me.readableShortName(), *hash);
|
||||
duplicates_timer_.start(1000);
|
||||
}
|
||||
}
|
||||
|
||||
auto const name = dictFind<QString>(dup, TR_KEY_name);
|
||||
if (name)
|
||||
if (session_has_torrent && !add_me.filename.isEmpty())
|
||||
{
|
||||
auto* d = new QMessageBox(QMessageBox::Warning, tr("Add Torrent"),
|
||||
tr(R"(<p><b>Unable to add "%1".</b></p><p>It is a duplicate of "%2" which is already added.</p>)").
|
||||
arg(add_me.readableShortName()).arg(*name), QMessageBox::Close, qApp->activeWindow());
|
||||
QObject::connect(d, &QMessageBox::rejected, d, &QMessageBox::deleteLater);
|
||||
d->show();
|
||||
QFile(add_me.filename).rename(QStringLiteral("%1.added").arg(add_me.filename));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1133,6 +1143,32 @@ void Session::addTorrent(AddData const& add_me, tr_variant* args, bool trash_ori
|
|||
q->run();
|
||||
}
|
||||
|
||||
void Session::onDuplicatesTimer()
|
||||
{
|
||||
decltype(duplicates_) duplicates;
|
||||
duplicates.swap(duplicates_);
|
||||
|
||||
QStringList lines;
|
||||
for (auto it : duplicates_)
|
||||
{
|
||||
lines.push_back(tr("%1 (copy of %2)")
|
||||
.arg(it.first)
|
||||
.arg(it.second.left(7)));
|
||||
}
|
||||
|
||||
if (!lines.empty())
|
||||
{
|
||||
lines.sort(Qt::CaseInsensitive);
|
||||
auto* d = new QMessageBox(QMessageBox::Warning,
|
||||
tr("Unable to add Duplicate Torrent(s)", "", lines.size()),
|
||||
lines.join(QStringLiteral("\n")),
|
||||
QMessageBox::Close,
|
||||
qApp->activeWindow());
|
||||
QObject::connect(d, &QMessageBox::rejected, d, &QMessageBox::deleteLater);
|
||||
d->show();
|
||||
}
|
||||
}
|
||||
|
||||
void Session::addTorrent(AddData const& add_me)
|
||||
{
|
||||
tr_variant args;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QTimer>
|
||||
|
||||
#include <libtransmission/transmission.h>
|
||||
#include <libtransmission/quark.h>
|
||||
|
@ -24,6 +25,7 @@
|
|||
#include "RpcQueue.h"
|
||||
#include "Torrent.h"
|
||||
#include "Typedefs.h"
|
||||
#include "Utils.h" // std::hash<QString>
|
||||
|
||||
class AddData;
|
||||
class Prefs;
|
||||
|
@ -120,6 +122,7 @@ public:
|
|||
public slots:
|
||||
void addTorrent(AddData const& addme);
|
||||
void launchWebInterface();
|
||||
void onDuplicatesTimer();
|
||||
void queueMoveBottom(torrent_ids_t const& torrentIds = {});
|
||||
void queueMoveDown(torrent_ids_t const& torrentIds = {});
|
||||
void queueMoveTop(torrent_ids_t const& torrentIds = {});
|
||||
|
@ -176,4 +179,7 @@ private:
|
|||
bool is_definitely_local_session_ = true;
|
||||
RpcClient rpc_;
|
||||
torrent_ids_t const RecentlyActiveIDs = { -1 };
|
||||
|
||||
std::map<QString, QString> duplicates_;
|
||||
QTimer duplicates_timer_;
|
||||
};
|
||||
|
|
|
@ -253,7 +253,9 @@ bool TorrentFilter::filterAcceptsRow(int source_row, QModelIndex const& source_p
|
|||
if (accepts)
|
||||
{
|
||||
auto const text = prefs_.getString(Prefs::FILTER_TEXT);
|
||||
accepts = text.isEmpty() || tor.name().contains(text, Qt::CaseInsensitive);
|
||||
accepts = text.isEmpty() ||
|
||||
tor.name().contains(text, Qt::CaseInsensitive) ||
|
||||
tor.hashString().contains(text, Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
return accepts;
|
||||
|
|
Loading…
Reference in a new issue