1/*
2 * This file Copyright (C) Mnemosyne LLC
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2
6 * as published by the Free Software Foundation.
7 *
8 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
9 *
10 * $Id: torrent-filter.cc 12653 2011-08-08 16:58:29Z jordan $
11 */
12
13#include <iostream>
14
15#include "filters.h"
16#include "hig.h"
17#include "prefs.h"
18#include "torrent.h"
19#include "torrent-filter.h"
20#include "torrent-model.h"
21#include "utils.h"
22
23TorrentFilter :: TorrentFilter( Prefs& prefs ):
24    myPrefs( prefs )
25{
26    // listen for changes to the preferences to know when to refilter / resort
27    connect( &myPrefs, SIGNAL(changed(int)), this, SLOT(refreshPref(int)));
28
29    setDynamicSortFilter( true );
30
31    // initialize our state from the current prefs
32    QList<int> initKeys;
33    initKeys << Prefs :: SORT_MODE
34             << Prefs :: FILTER_MODE
35             << Prefs :: FILTER_TRACKERS
36             << Prefs :: FILTER_TEXT;
37    foreach( int key, initKeys )
38        refreshPref( key );
39}
40
41TorrentFilter :: ~TorrentFilter( )
42{
43}
44
45void
46TorrentFilter :: refreshPref( int key )
47{
48    switch( key )
49    {
50        case Prefs :: FILTER_TEXT:
51        case Prefs :: FILTER_MODE:
52        case Prefs :: FILTER_TRACKERS:
53            invalidateFilter( );
54            /* force a re-sort */
55            sort( 0, !myPrefs.getBool(Prefs::SORT_REVERSED) ? Qt::AscendingOrder : Qt::DescendingOrder );
56
57        case Prefs :: SORT_MODE:
58        case Prefs :: SORT_REVERSED:
59            sort( 0, myPrefs.getBool(Prefs::SORT_REVERSED) ? Qt::AscendingOrder : Qt::DescendingOrder );
60            invalidate( );
61            break;
62    }
63}
64
65/***
66****
67***/
68
69namespace
70{
71    template <typename T> int compare( const T a, const T b )
72    {
73        if( a < b ) return -1;
74        if( b < a ) return 1;
75        return 0;
76    }
77}
78
79bool
80TorrentFilter :: lessThan( const QModelIndex& left, const QModelIndex& right ) const
81{
82    int val = 0;
83    const Torrent * a = sourceModel()->data( left, TorrentModel::TorrentRole ).value<const Torrent*>();
84    const Torrent * b = sourceModel()->data( right, TorrentModel::TorrentRole ).value<const Torrent*>();
85
86    switch( myPrefs.get<SortMode>(Prefs::SORT_MODE).mode() )
87    {
88        case SortMode :: SORT_BY_QUEUE:
89            if( !val ) val = -compare( a->queuePosition(), b->queuePosition() );
90            break;
91        case SortMode :: SORT_BY_SIZE:
92            if( !val ) val = compare( a->sizeWhenDone(), b->sizeWhenDone() );
93            break;
94        case SortMode :: SORT_BY_AGE:
95            val = compare( a->dateAdded().toTime_t(), b->dateAdded().toTime_t() );
96            break;
97        case SortMode :: SORT_BY_ID:
98            if( !val ) val = compare( a->id(), b->id() );
99            break;
100        case SortMode :: SORT_BY_ACTIVITY:
101            if( !val ) val = compare( a->downloadSpeed() + a->uploadSpeed(), b->downloadSpeed() + b->uploadSpeed() );
102            if( !val ) val = compare( a->uploadedEver(), b->uploadedEver() );
103            // fall through
104        case SortMode :: SORT_BY_STATE:
105            if( !val ) val = compare( a->hasError(), b->hasError() );
106            if( !val ) val = compare( a->getActivity(), b->getActivity() );
107            if( !val ) val = -compare( a->queuePosition(), b->queuePosition() );
108            // fall through
109        case SortMode :: SORT_BY_PROGRESS:
110            if( !val ) val = compare( a->percentComplete(), b->percentComplete() );
111            if( !val ) val = a->compareSeedRatio( *b );
112            if( !val ) val = -compare( a->queuePosition(), b->queuePosition() );
113        case SortMode :: SORT_BY_RATIO:
114            if( !val ) val = a->compareRatio( *b );
115            break;
116        case SortMode :: SORT_BY_ETA:
117            if( !val ) val = a->compareETA( *b );
118            break;
119        default:
120            break;
121    }
122    if( val == 0 )
123        val = -a->name().compare( b->name(), Qt::CaseInsensitive );
124    if( val == 0 )
125        val = compare( a->hashString(), b->hashString() );
126    return val < 0;
127}
128
129
130/***
131****
132***/
133
134bool
135TorrentFilter :: trackerFilterAcceptsTorrent( const Torrent * tor, const QString& tracker ) const
136{
137    return tracker.isEmpty() || tor->hasTrackerSubstring( tracker );
138}
139
140bool
141TorrentFilter :: activityFilterAcceptsTorrent( const Torrent * tor, const FilterMode& m ) const
142{
143    bool accepts;
144
145    switch( m.mode( ) )
146    {
147        case FilterMode::SHOW_ACTIVE:
148            accepts = tor->peersWeAreUploadingTo( ) > 0 || tor->peersWeAreDownloadingFrom( ) > 0 || tor->isVerifying( );
149            break;
150        case FilterMode::SHOW_DOWNLOADING:
151            accepts = tor->isDownloading( ) || tor->isWaitingToDownload( );
152            break;
153        case FilterMode::SHOW_SEEDING:
154            accepts = tor->isSeeding( ) || tor->isWaitingToSeed( );
155            break;
156        case FilterMode::SHOW_PAUSED:
157            accepts = tor->isPaused( );
158            break;
159        case FilterMode::SHOW_FINISHED:
160            accepts = tor->isFinished( );
161            break;
162        case FilterMode::SHOW_VERIFYING:
163            accepts = tor->isVerifying( ) || tor->isWaitingToVerify( );
164            break;
165        case FilterMode::SHOW_ERROR:
166            accepts = tor->hasError( );
167            break;
168        default: // FilterMode::SHOW_ALL
169            accepts = true;
170            break;
171    }
172
173    return accepts;
174}
175
176bool
177TorrentFilter :: filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const
178{
179    QModelIndex childIndex = sourceModel()->index( sourceRow, 0, sourceParent );
180    const Torrent * tor = childIndex.model()->data( childIndex, TorrentModel::TorrentRole ).value<const Torrent*>();
181    bool accepts = true;
182
183    if( accepts ) {
184        const FilterMode m = myPrefs.get<FilterMode>(Prefs::FILTER_MODE);
185        accepts = activityFilterAcceptsTorrent( tor, m );
186    }
187
188    if( accepts ) {
189        const QString trackers = myPrefs.getString(Prefs::FILTER_TRACKERS);
190        accepts = trackerFilterAcceptsTorrent( tor, trackers );
191    }
192
193    if( accepts ) {
194        const QString text = myPrefs.getString( Prefs::FILTER_TEXT );
195        if( !text.isEmpty( ) )
196            accepts = tor->name().contains( text, Qt::CaseInsensitive );
197    }
198
199    return accepts;
200}
201
202int
203TorrentFilter :: hiddenRowCount( ) const
204{
205    return sourceModel()->rowCount( ) - rowCount( );
206}
207
208int
209TorrentFilter :: count( const FilterMode& mode ) const
210{
211    int count = 0;
212
213    for( int row=0; ; ++row ) {
214        QModelIndex index = sourceModel()->index( row, 0 );
215        if( !index.isValid( ) )
216            break;
217        const Torrent * tor = index.data( TorrentModel::TorrentRole ).value<const Torrent*>();
218        if( activityFilterAcceptsTorrent( tor, mode ) )
219            ++count;
220    }
221
222    return count;
223}
224