transmission/qt/TorrentFilter.cc

336 lines
7.3 KiB
C++
Raw Normal View History

2009-04-09 18:55:47 +00:00
/*
* This file Copyright (C) 2009-2015 Mnemosyne LLC
2009-04-09 18:55:47 +00:00
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
2009-04-09 18:55:47 +00:00
*
*/
#include <algorithm>
#include <optional>
2009-04-09 18:55:47 +00:00
#include "Filters.h"
#include "Prefs.h"
#include "Torrent.h"
#include "TorrentFilter.h"
#include "TorrentModel.h"
#include "Utils.h"
2009-04-09 18:55:47 +00:00
TorrentFilter::TorrentFilter(Prefs const& prefs) :
myPrefs(prefs)
2009-04-09 18:55:47 +00:00
{
connect(&myPrefs, &Prefs::changed, this, &TorrentFilter::onPrefChanged);
connect(&myRefilterTimer, &QTimer::timeout, this, &TorrentFilter::refilter);
setDynamicSortFilter(true);
refilter();
2009-04-09 18:55:47 +00:00
}
TorrentFilter::~TorrentFilter()
2009-04-09 18:55:47 +00:00
{
}
/***
****
***/
void TorrentFilter::onPrefChanged(int key)
2009-04-09 18:55:47 +00:00
{
// For refiltering nearly immediately. Used to debounce batched prefs changes.
static int const fast_msec = 50;
// For waiting a little longer. Useful when user is typing the filter text.
static int const slow_msec = 500;
std::optional<int> msec;
switch (key)
2009-04-09 18:55:47 +00:00
{
case Prefs::FILTER_TEXT:
// special case for isEmpty: user probably hit the 'clear' button
msec = myPrefs.getString(key).isEmpty() ? fast_msec : slow_msec;
break;
case Prefs::FILTER_MODE:
case Prefs::FILTER_TRACKERS:
case Prefs::SORT_MODE:
case Prefs::SORT_REVERSED:
msec = fast_msec;
2013-09-14 22:45:04 +00:00
break;
2009-04-09 18:55:47 +00:00
}
// if this pref change affects filtering, ensure that a refilter is queued
if (msec && !myRefilterTimer.isActive())
{
myRefilterTimer.setSingleShot(true);
myRefilterTimer.start(*msec);
}
}
void TorrentFilter::refilter()
{
invalidate();
sort(0, myPrefs.getBool(Prefs::SORT_REVERSED) ? Qt::AscendingOrder : Qt::DescendingOrder);
2009-04-09 18:55:47 +00:00
}
/***
****
***/
namespace
{
template<typename T>
int compare(T const a, T const b)
{
if (a < b)
{
2013-09-14 22:45:04 +00:00
return -1;
}
2013-09-14 22:45:04 +00:00
if (b < a)
{
2013-09-14 22:45:04 +00:00
return 1;
}
return 0;
}
} // namespace
bool TorrentFilter::lessThan(QModelIndex const& left, QModelIndex const& right) const
2009-04-09 18:55:47 +00:00
{
int val = 0;
Torrent const* a = sourceModel()->data(left, TorrentModel::TorrentRole).value<Torrent const*>();
Torrent const* b = sourceModel()->data(right, TorrentModel::TorrentRole).value<Torrent const*>();
2009-04-09 18:55:47 +00:00
switch (myPrefs.get<SortMode>(Prefs::SORT_MODE).mode())
2009-04-09 18:55:47 +00:00
{
case SortMode::SORT_BY_QUEUE:
if (val == 0)
{
val = -compare(a->queuePosition(), b->queuePosition());
}
2013-09-14 22:45:04 +00:00
break;
case SortMode::SORT_BY_SIZE:
if (val == 0)
{
val = compare(a->sizeWhenDone(), b->sizeWhenDone());
}
2013-09-14 22:45:04 +00:00
break;
case SortMode::SORT_BY_AGE:
if (val == 0)
{
val = compare(a->dateAdded(), b->dateAdded());
}
2013-09-14 22:45:04 +00:00
break;
case SortMode::SORT_BY_ID:
if (val == 0)
{
val = compare(a->id(), b->id());
}
2013-09-14 22:45:04 +00:00
break;
case SortMode::SORT_BY_ACTIVITY:
if (val == 0)
{
val = compare(a->downloadSpeed() + a->uploadSpeed(), b->downloadSpeed() + b->uploadSpeed());
}
if (val == 0)
{
val = compare(a->peersWeAreUploadingTo() + a->webseedsWeAreDownloadingFrom(),
b->peersWeAreUploadingTo() + b->webseedsWeAreDownloadingFrom());
}
2013-09-14 22:45:04 +00:00
// fall through
case SortMode::SORT_BY_STATE:
if (val == 0)
{
val = -compare(a->isPaused(), b->isPaused());
}
if (val == 0)
{
val = compare(a->getActivity(), b->getActivity());
}
if (val == 0)
{
val = -compare(a->queuePosition(), b->queuePosition());
}
if (val == 0)
{
val = compare(a->hasError(), b->hasError());
}
// fall through
2013-09-14 22:45:04 +00:00
case SortMode::SORT_BY_PROGRESS:
if (val == 0)
{
val = compare(a->metadataPercentDone(), b->metadataPercentDone());
}
if (val == 0)
{
val = compare(a->percentComplete(), b->percentComplete());
}
if (val == 0)
{
val = a->compareSeedRatio(*b);
}
if (val == 0)
{
val = -compare(a->queuePosition(), b->queuePosition());
}
2013-09-14 22:45:04 +00:00
// fall through
case SortMode::SORT_BY_RATIO:
if (val == 0)
{
val = a->compareRatio(*b);
}
2013-09-14 22:45:04 +00:00
break;
case SortMode::SORT_BY_ETA:
if (val == 0)
{
val = a->compareETA(*b);
}
2013-09-14 22:45:04 +00:00
break;
default:
2013-09-14 22:45:04 +00:00
break;
2009-04-09 18:55:47 +00:00
}
2013-09-14 22:45:04 +00:00
if (val == 0)
{
val = -a->name().compare(b->name(), Qt::CaseInsensitive);
}
2013-09-14 22:45:04 +00:00
if (val == 0)
{
val = compare(a->hashString(), b->hashString());
}
2013-09-14 22:45:04 +00:00
return val < 0;
2009-04-09 18:55:47 +00:00
}
/***
****
***/
bool TorrentFilter::trackerFilterAcceptsTorrent(Torrent const* tor, QString const& tracker) const
2010-07-30 22:24:48 +00:00
{
return tracker.isEmpty() || tor->hasTrackerSubstring(tracker);
2010-07-30 22:24:48 +00:00
}
bool TorrentFilter::activityFilterAcceptsTorrent(Torrent const* tor, FilterMode const& m) const
{
bool accepts;
switch (m.mode())
{
case FilterMode::SHOW_ACTIVE:
accepts = tor->peersWeAreUploadingTo() > 0 || tor->peersWeAreDownloadingFrom() > 0 || tor->isVerifying();
2013-09-14 22:45:04 +00:00
break;
case FilterMode::SHOW_DOWNLOADING:
accepts = tor->isDownloading() || tor->isWaitingToDownload();
2013-09-14 22:45:04 +00:00
break;
case FilterMode::SHOW_SEEDING:
accepts = tor->isSeeding() || tor->isWaitingToSeed();
2013-09-14 22:45:04 +00:00
break;
case FilterMode::SHOW_PAUSED:
accepts = tor->isPaused();
2013-09-14 22:45:04 +00:00
break;
case FilterMode::SHOW_FINISHED:
accepts = tor->isFinished();
2013-09-14 22:45:04 +00:00
break;
case FilterMode::SHOW_VERIFYING:
accepts = tor->isVerifying() || tor->isWaitingToVerify();
2013-09-14 22:45:04 +00:00
break;
case FilterMode::SHOW_ERROR:
accepts = tor->hasError();
2013-09-14 22:45:04 +00:00
break;
default: // FilterMode::SHOW_ALL
2013-09-14 22:45:04 +00:00
accepts = true;
break;
2010-07-30 22:24:48 +00:00
}
return accepts;
2010-07-30 22:24:48 +00:00
}
bool TorrentFilter::filterAcceptsRow(int sourceRow, QModelIndex const& sourceParent) const
2010-07-30 22:24:48 +00:00
{
QModelIndex childIndex = sourceModel()->index(sourceRow, 0, sourceParent);
Torrent const* tor = childIndex.model()->data(childIndex, TorrentModel::TorrentRole).value<Torrent const*>();
bool accepts = true;
2010-07-30 22:24:48 +00:00
if (accepts)
2013-09-14 22:45:04 +00:00
{
FilterMode const m = myPrefs.get<FilterMode>(Prefs::FILTER_MODE);
accepts = activityFilterAcceptsTorrent(tor, m);
2010-07-30 22:24:48 +00:00
}
if (accepts)
2013-09-14 22:45:04 +00:00
{
QString const trackers = myPrefs.getString(Prefs::FILTER_TRACKERS);
accepts = trackerFilterAcceptsTorrent(tor, trackers);
}
if (accepts)
2013-09-14 22:45:04 +00:00
{
QString const text = myPrefs.getString(Prefs::FILTER_TEXT);
if (!text.isEmpty())
{
accepts = tor->name().contains(text, Qt::CaseInsensitive);
}
2010-07-30 22:24:48 +00:00
}
return accepts;
}
int TorrentFilter::hiddenRowCount() const
2009-04-09 18:55:47 +00:00
{
return sourceModel()->rowCount() - rowCount();
2009-04-09 18:55:47 +00:00
}
2010-07-30 22:24:48 +00:00
void TorrentFilter::countTorrentsPerMode(int* setmeCounts) const
2010-07-30 22:24:48 +00:00
{
std::fill_n(setmeCounts, static_cast<std::size_t>(FilterMode::NUM_MODES), 0);
for (auto const& tor : dynamic_cast<TorrentModel*>(sourceModel())->torrents())
{
for (int mode = 0; mode < FilterMode::NUM_MODES; ++mode)
{
if (activityFilterAcceptsTorrent(tor, mode))
{
++setmeCounts[mode];
}
}
2010-07-30 22:24:48 +00:00
}
}