/* * This file Copyright (C) 2009-2015 Mnemosyne LLC * * It may be used under the GNU GPL versions 2 or 3 * or any future license endorsed by Mnemosyne LLC. * */ #include #include "Filters.h" #include "Prefs.h" #include "Torrent.h" #include "TorrentFilter.h" #include "TorrentModel.h" #include "Utils.h" TorrentFilter::TorrentFilter (const Prefs& prefs): myPrefs (prefs) { // listen for changes to the preferences to know when to refilter / resort connect (&myPrefs, SIGNAL(changed(int)), this, SLOT(refreshPref(int))); setDynamicSortFilter (true); // initialize our state from the current prefs QList initKeys; initKeys << Prefs::SORT_MODE << Prefs::FILTER_MODE << Prefs::FILTER_TRACKERS << Prefs::FILTER_TEXT; for (const int key: initKeys) refreshPref (key); } TorrentFilter::~TorrentFilter () { } void TorrentFilter::refreshPref (int key) { switch (key) { case Prefs::FILTER_TEXT: case Prefs::FILTER_MODE: case Prefs::FILTER_TRACKERS: invalidateFilter (); /* force a re-sort */ sort (0, !myPrefs.getBool(Prefs::SORT_REVERSED) ? Qt::AscendingOrder : Qt::DescendingOrder); case Prefs::SORT_MODE: case Prefs::SORT_REVERSED: sort (0, myPrefs.getBool(Prefs::SORT_REVERSED) ? Qt::AscendingOrder : Qt::DescendingOrder); invalidate (); break; } } /*** **** ***/ namespace { template int compare (const T a, const T b) { if (a < b) return -1; if (b < a) return 1; return 0; } } bool TorrentFilter::lessThan (const QModelIndex& left, const QModelIndex& right) const { int val = 0; const Torrent * a = sourceModel()->data (left, TorrentModel::TorrentRole).value(); const Torrent * b = sourceModel()->data (right, TorrentModel::TorrentRole).value(); switch (myPrefs.get(Prefs::SORT_MODE).mode()) { case SortMode::SORT_BY_QUEUE: if (!val) val = -compare (a->queuePosition(), b->queuePosition()); break; case SortMode::SORT_BY_SIZE: if (!val) val = compare (a->sizeWhenDone(), b->sizeWhenDone()); break; case SortMode::SORT_BY_AGE: val = compare (a->dateAdded().toTime_t(), b->dateAdded().toTime_t()); break; case SortMode::SORT_BY_ID: if (!val) val = compare (a->id(), b->id()); break; case SortMode::SORT_BY_ACTIVITY: if (!val) val = compare (a->downloadSpeed() + a->uploadSpeed(), b->downloadSpeed() + b->uploadSpeed()); if (!val) val = compare (a->peersWeAreUploadingTo() + a->webseedsWeAreDownloadingFrom(), b->peersWeAreUploadingTo() + b->webseedsWeAreDownloadingFrom()); // fall through case SortMode::SORT_BY_STATE: if (!val) val = -compare (a->isPaused(), b->isPaused()); if (!val) val = compare (a->getActivity(), b->getActivity()); if (!val) val = -compare (a->queuePosition(), b->queuePosition()); if (!val) val = compare (a->hasError(), b->hasError()); // fall through case SortMode::SORT_BY_PROGRESS: if (!val) val = compare (a->percentComplete(), b->percentComplete()); if (!val) val = a->compareSeedRatio (*b); if (!val) val = -compare (a->queuePosition(), b->queuePosition()); // fall through case SortMode::SORT_BY_RATIO: if (!val) val = a->compareRatio (*b); break; case SortMode::SORT_BY_ETA: if (!val) val = a->compareETA (*b); break; default: break; } if (val == 0) val = -a->name().compare (b->name(), Qt::CaseInsensitive); if (val == 0) val = compare (a->hashString(), b->hashString()); return val < 0; } /*** **** ***/ bool TorrentFilter::trackerFilterAcceptsTorrent (const Torrent * tor, const QString& tracker) const { return tracker.isEmpty() || tor->hasTrackerSubstring (tracker); } bool TorrentFilter::activityFilterAcceptsTorrent (const Torrent * tor, const FilterMode& m) const { bool accepts; switch (m.mode ()) { case FilterMode::SHOW_ACTIVE: accepts = tor->peersWeAreUploadingTo () > 0 || tor->peersWeAreDownloadingFrom () > 0 || tor->isVerifying (); break; case FilterMode::SHOW_DOWNLOADING: accepts = tor->isDownloading () || tor->isWaitingToDownload (); break; case FilterMode::SHOW_SEEDING: accepts = tor->isSeeding () || tor->isWaitingToSeed (); break; case FilterMode::SHOW_PAUSED: accepts = tor->isPaused (); break; case FilterMode::SHOW_FINISHED: accepts = tor->isFinished (); break; case FilterMode::SHOW_VERIFYING: accepts = tor->isVerifying () || tor->isWaitingToVerify (); break; case FilterMode::SHOW_ERROR: accepts = tor->hasError (); break; default: // FilterMode::SHOW_ALL accepts = true; break; } return accepts; } bool TorrentFilter::filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const { QModelIndex childIndex = sourceModel()->index (sourceRow, 0, sourceParent); const Torrent * tor = childIndex.model()->data (childIndex, TorrentModel::TorrentRole).value(); bool accepts = true; if (accepts) { const FilterMode m = myPrefs.get(Prefs::FILTER_MODE); accepts = activityFilterAcceptsTorrent (tor, m); } if (accepts) { const QString trackers = myPrefs.getString(Prefs::FILTER_TRACKERS); accepts = trackerFilterAcceptsTorrent (tor, trackers); } if (accepts) { const QString text = myPrefs.getString (Prefs::FILTER_TEXT); if (!text.isEmpty ()) accepts = tor->name().contains (text, Qt::CaseInsensitive); } return accepts; } int TorrentFilter::hiddenRowCount () const { return sourceModel()->rowCount () - rowCount (); } void TorrentFilter::countTorrentsPerMode (int * setmeCounts) const { std::fill_n (setmeCounts, static_cast(FilterMode::NUM_MODES), 0); for (int row(0); ; ++row) { QModelIndex index (sourceModel()->index(row, 0)); if (!index.isValid()) break; const Torrent * tor (index.data (TorrentModel::TorrentRole).value()); for (int mode(0); mode