#671 "torrent queuing" -- modify the queue implementation s.t. every torrent has a queuePosition, even if it's not currently in the queue.

This commit is contained in:
Jordan Lee 2011-08-02 03:59:54 +00:00
parent efd20bff04
commit 307754e807
21 changed files with 162 additions and 201 deletions

View File

@ -49,11 +49,12 @@ static GtkRadioActionEntry sort_radio_entries[] =
{ "sort-by-activity", NULL, N_( "Sort by _Activity" ), NULL, NULL, 0 },
{ "sort-by-name", NULL, N_( "Sort by _Name" ), NULL, NULL, 1 },
{ "sort-by-progress", NULL, N_( "Sort by _Progress" ), NULL, NULL, 2 },
{ "sort-by-ratio", NULL, N_( "Sort by Rati_o" ), NULL, NULL, 3 },
{ "sort-by-state", NULL, N_( "Sort by Stat_e" ), NULL, NULL, 4 },
{ "sort-by-age", NULL, N_( "Sort by A_ge" ), NULL, NULL, 5 },
{ "sort-by-time-left", NULL, N_( "Sort by Time _Left" ), NULL, NULL, 6 },
{ "sort-by-size", NULL, N_( "Sort by Si_ze" ), NULL, NULL, 7 }
{ "sort-by-queue", NULL, N_( "Sort by _Queue" ), NULL, NULL, 3 },
{ "sort-by-ratio", NULL, N_( "Sort by Rati_o" ), NULL, NULL, 4 },
{ "sort-by-state", NULL, N_( "Sort by Stat_e" ), NULL, NULL, 5 },
{ "sort-by-age", NULL, N_( "Sort by A_ge" ), NULL, NULL, 6 },
{ "sort-by-time-left", NULL, N_( "Sort by Time _Left" ), NULL, NULL, 7 },
{ "sort-by-size", NULL, N_( "Sort by Si_ze" ), NULL, NULL, 8 }
};
static void

View File

@ -247,7 +247,6 @@ show_details_dialog_for_selected_torrents( struct cbdata * data )
struct counts_data
{
int total_count;
int active_count;
int queued_count;
int stopped_count;
};
@ -257,27 +256,23 @@ get_selected_torrent_counts_foreach( GtkTreeModel * model, GtkTreePath * path UN
GtkTreeIter * iter, gpointer user_data )
{
int activity = 0;
int queuePosition = -1;
struct counts_data * counts = user_data;
++counts->total_count;
gtk_tree_model_get( model, iter, MC_ACTIVITY, &activity, -1 );
if( activity == TR_STATUS_DOWNLOAD_WAIT )
if( ( activity == TR_STATUS_DOWNLOAD_WAIT ) || ( activity == TR_STATUS_SEED_WAIT ) )
++counts->queued_count;
if( ( activity == TR_STATUS_STOPPED ) && ( queuePosition < 0 ) )
if( activity == TR_STATUS_STOPPED )
++counts->stopped_count;
else
++counts->active_count;
}
static void
get_selected_torrent_counts( struct cbdata * data, struct counts_data * counts )
{
counts->total_count = 0;
counts->active_count = 0;
counts->queued_count = 0;
counts->stopped_count = 0;
@ -302,30 +297,30 @@ refresh_actions( gpointer gdata )
const size_t total = gtr_core_get_torrent_count( data->core );
const size_t active = gtr_core_get_active_torrent_count( data->core );
const int torrent_count = gtk_tree_model_iter_n_children( gtr_core_model( data->core ), NULL );
const tr_session * session = gtr_core_session( data->core );
const bool queue_enabled = tr_sessionGetQueueEnabled( session, TR_DOWN )
|| tr_sessionGetQueueEnabled( session, TR_UP );
bool has_selection;
get_selected_torrent_counts( data, &sel_counts );
has_selection = sel_counts.total_count > 0;
gtr_action_set_sensitive( "select-all", torrent_count != 0 );
gtr_action_set_sensitive( "deselect-all", torrent_count != 0 );
gtr_action_set_sensitive( "pause-all-torrents", active != 0 );
gtr_action_set_sensitive( "start-all-torrents", active != total );
get_selected_torrent_counts( data, &sel_counts );
gtr_action_set_sensitive( "torrent-stop", ( sel_counts.active_count + sel_counts.queued_count ) > 0 );
gtr_action_set_sensitive( "torrent-stop", ( sel_counts.stopped_count < sel_counts.total_count ) );
gtr_action_set_sensitive( "torrent-start", ( sel_counts.stopped_count ) > 0 );
gtr_action_set_sensitive( "torrent-start-now", ( sel_counts.stopped_count + sel_counts.queued_count ) > 0 );
gtr_action_set_sensitive( "torrent-verify", sel_counts.total_count != 0 );
gtr_action_set_sensitive( "remove-torrent", sel_counts.total_count != 0 );
gtr_action_set_sensitive( "delete-torrent", sel_counts.total_count != 0 );
gtr_action_set_sensitive( "relocate-torrent", sel_counts.total_count != 0 );
gtr_action_set_sensitive( "show-torrent-properties", sel_counts.total_count != 0 );
gtr_action_set_sensitive( "torrent-verify", has_selection );
gtr_action_set_sensitive( "remove-torrent", has_selection );
gtr_action_set_sensitive( "delete-torrent", has_selection );
gtr_action_set_sensitive( "relocate-torrent", has_selection );
gtr_action_set_sensitive( "queue-move-top", has_selection );
gtr_action_set_sensitive( "queue-move-up", has_selection );
gtr_action_set_sensitive( "queue-move-down", has_selection );
gtr_action_set_sensitive( "queue-move-bottom", has_selection );
gtr_action_set_sensitive( "show-torrent-properties", has_selection );
gtr_action_set_sensitive( "open-torrent-folder", sel_counts.total_count == 1 );
gtr_action_set_sensitive( "copy-magnet-link-to-clipboard", sel_counts.total_count == 1 );
gtr_action_set_sensitive( "queue-move-top", queue_enabled && ( sel_counts.queued_count > 0 ) );
gtr_action_set_sensitive( "queue-move-up", queue_enabled && ( sel_counts.queued_count > 0 ) );
gtr_action_set_sensitive( "queue-move-down", queue_enabled && ( sel_counts.queued_count > 0 ) );
gtr_action_set_sensitive( "queue-move-bottom", queue_enabled && ( sel_counts.queued_count > 0 ) );
canUpdate = 0;
gtk_tree_selection_selected_foreach( data->sel, count_updatable_foreach, &canUpdate );

View File

@ -228,11 +228,10 @@ getShortStatusString( GString * gstr,
break;
case TR_STATUS_DOWNLOAD_WAIT:
g_string_append_printf( gstr, _( "Download queue #%d" ), st->queuePosition + 1 );
g_string_append( gstr, _( "Waiting to download" ) );
break;
case TR_STATUS_SEED_WAIT:
g_string_append_printf( gstr, _( "Seed queue #%d" ), st->queuePosition + 1 );
g_string_append( gstr, _( "Waiting to seed" ) );
break;
case TR_STATUS_DOWNLOAD:
@ -685,7 +684,7 @@ render_compact( TorrentCellRenderer * cell,
g_object_set( p->icon_renderer, "pixbuf", icon, "sensitive", sensitive, NULL );
gtr_cell_renderer_render( p->icon_renderer, window, widget, &icon_area, flags );
g_object_set( p->progress_renderer, "value", (int)(percentDone*100.0), "text", NULL,
"sensitive", sensitive || ( st->queuePosition >= 0 ),
"sensitive", sensitive,
#if GTK_CHECK_VERSION( 3,0,0 )
"inverted", seed,
#elif GTK_CHECK_VERSION( 2,6,0 )
@ -805,7 +804,7 @@ render_full( TorrentCellRenderer * cell,
gtr_cell_renderer_render( p->text_renderer, window, widget, &name_area, flags );
g_object_set( p->text_renderer, "text", gstr_prog->str, "scale", SMALL_SCALE, "weight", PANGO_WEIGHT_NORMAL, NULL );
gtr_cell_renderer_render( p->text_renderer, window, widget, &prog_area, flags );
g_object_set( p->progress_renderer, "value", (int)(percentDone*100.0), "text", "", "sensitive", ( sensitive || st->queuePosition >= 0 ),
g_object_set( p->progress_renderer, "value", (int)(percentDone*100.0), "text", "", "sensitive", sensitive,
#if GTK_CHECK_VERSION( 3,0,0 )
"inverted", seed,
#elif GTK_CHECK_VERSION( 2,6,0 )

View File

@ -459,12 +459,17 @@ compare_by_name( GtkTreeModel * m, GtkTreeIter * a, GtkTreeIter * b, gpointer us
}
static int
compare_by_queue( const tr_stat * a, const tr_stat * b )
compare_by_queue( GtkTreeModel * m, GtkTreeIter * a, GtkTreeIter * b, gpointer user_data UNUSED )
{
const bool a_is_queued = a->queuePosition >= 0;
const bool b_is_queued = b->queuePosition >= 0;
if( a_is_queued != b_is_queued ) return a_is_queued ? -1 : 1;
return b->queuePosition - a->queuePosition;
tr_torrent *ta, *tb;
const tr_stat *sa, *sb;
gtk_tree_model_get( m, a, MC_TORRENT, &ta, -1 );
sa = tr_torrentStatCached( ta );
gtk_tree_model_get( m, b, MC_TORRENT, &tb, -1 );
sb = tr_torrentStatCached( tb );
return sb->queuePosition - sa->queuePosition;
}
static int
@ -480,8 +485,7 @@ compare_by_ratio( GtkTreeModel* m, GtkTreeIter * a, GtkTreeIter * b, gpointer us
sb = tr_torrentStatCached( tb );
if( !ret ) ret = compare_ratio( sa->ratio, sb->ratio );
if( !ret ) ret = compare_by_queue( sa, sb );
if( !ret ) ret = compare_by_name( m, a, b, user_data );
if( !ret ) ret = compare_by_queue( m, a, b, user_data );
return ret;
}
@ -506,8 +510,7 @@ compare_by_activity( GtkTreeModel * m, GtkTreeIter * a, GtkTreeIter * b, gpointe
if( !ret ) ret = compare_double( aUp+aDown, bUp+bDown );
if( !ret ) ret = compare_uint64( sa->uploadedEver, sb->uploadedEver );
if( !ret ) ret = compare_by_queue( sa, sb );
if( !ret ) ret = compare_by_name( m, a, b, user_data );
if( !ret ) ret = compare_by_queue( m, a, b, user_data );
return ret;
}
@ -587,8 +590,7 @@ compare_by_state( GtkTreeModel * m, GtkTreeIter * a, GtkTreeIter * b, gpointer u
gtk_tree_model_get( m, b, MC_ACTIVITY, &sb, MC_TORRENT, &tb, -1 );
if( !ret ) ret = compare_int( sa, sb );
if( !ret ) ret = compare_by_queue( tr_torrentStatCached( ta ), tr_torrentStatCached( tb ) );
if( !ret ) ret = compare_by_progress( m, a, b, u );
if( !ret ) ret = compare_by_queue( m, a, b, u );
return ret;
}
@ -606,6 +608,8 @@ core_set_sort_mode( TrCore * core, const char * mode, gboolean is_reversed )
sort_func = compare_by_age;
else if( !strcmp( mode, "sort-by-progress" ) )
sort_func = compare_by_progress;
else if( !strcmp( mode, "sort-by-queue" ) )
sort_func = compare_by_queue;
else if( !strcmp( mode, "sort-by-time-left" ) )
sort_func = compare_by_eta;
else if( !strcmp( mode, "sort-by-ratio" ) )

View File

@ -50,6 +50,7 @@ static const char * fallback_ui_file =
" <menuitem action='sort-by-age'/>\n"
" <menuitem action='sort-by-name'/>\n"
" <menuitem action='sort-by-progress'/>\n"
" <menuitem action='sort-by-queue'/>\n"
" <menuitem action='sort-by-ratio'/>\n"
" <menuitem action='sort-by-size'/>\n"
" <menuitem action='sort-by-state'/>\n"

View File

@ -313,7 +313,7 @@ torrentStop( tr_session * session,
{
tr_torrent * tor = torrents[i];
if( tor->isRunning || ( tor->queuePosition >= 0 ) )
if( tor->isRunning || tr_torrentIsQueued( tor ) )
{
tor->isStopping = true;
notify( session, TR_RPC_TORRENT_STOPPED, tor );

View File

@ -2692,13 +2692,19 @@ tr_sessionGetNextQueuedTorrent( tr_session * session, tr_direction direction )
assert( tr_isSession( session ) );
assert( tr_isDirection( direction ) );
while(( tor = tr_torrentNext( session, tor ))) {
if( !tor->isRunning && ( direction == tr_torrentGetQueueDirection( tor ) ) ) {
const int position = tr_torrentGetQueuePosition( tor );
if( ( position >= 0 ) && ( best_position > position ) ) {
best_position = position;
best_tor = tor;
}
while(( tor = tr_torrentNext( session, tor )))
{
int position;
if( !tr_torrentIsQueued( tor ) )
continue;
if( direction != tr_torrentGetQueueDirection( tor ) )
continue;
position = tr_torrentGetQueuePosition( tor );
if( best_position > position ) {
best_position = position;
best_tor = tor;
}
}
@ -2711,7 +2717,7 @@ tr_sessionCountQueueFreeSlots( tr_session * session, tr_direction dir )
tr_torrent * tor;
int active_count;
const int max = tr_sessionGetQueueSize( session, dir );
const tr_torrent_activity activity = TR_UP ? TR_STATUS_SEED : TR_STATUS_DOWNLOAD;
const tr_torrent_activity activity = dir == TR_UP ? TR_STATUS_SEED : TR_STATUS_DOWNLOAD;
if( !tr_sessionGetQueueEnabled( session, dir ) )
return INT_MAX;

View File

@ -802,7 +802,7 @@ torrentInit( tr_torrent * tor, const tr_ctor * ctor )
tor->session = session;
tor->uniqueId = nextUniqueId++;
tor->magicNumber = TORRENT_MAGIC_NUMBER;
tor->queuePosition = -1;
tor->queuePosition = session->torrentCount;
tr_peerIdInit( tor->peer_id );
@ -870,7 +870,7 @@ torrentInit( tr_torrent * tor, const tr_ctor * ctor )
}
/* add the torrent to tr_session.torrentList */
++session->torrentCount;
session->torrentCount++;
if( session->torrentList == NULL )
session->torrentList = tor;
else {
@ -1105,7 +1105,7 @@ torrentGetActivity( const tr_torrent * tor )
if( tor->isRunning )
return is_seed ? TR_STATUS_SEED : TR_STATUS_DOWNLOAD;
if( tor->queuePosition >= 0 ) {
if( tr_torrentIsQueued( tor ) ) {
if( is_seed && tr_sessionGetQueueEnabled( tor->session, TR_UP ) )
return TR_STATUS_SEED_WAIT;
if( !is_seed && tr_sessionGetQueueEnabled( tor->session, TR_DOWN ) )
@ -1496,12 +1496,15 @@ tr_torrentSetHasPiece( tr_torrent * tor,
****
***/
static bool queueIsSequenced( tr_session * );
static void
freeTorrent( tr_torrent * tor )
{
tr_torrent * t;
tr_session * session = tor->session;
tr_info * inf = &tor->info;
const time_t now = tr_time( );
assert( !tor->isRunning );
@ -1525,9 +1528,20 @@ freeTorrent( tr_torrent * tor )
}
}
/* decrement the torrent count */
assert( session->torrentCount >= 1 );
session->torrentCount--;
/* resequence the queue positions */
t = NULL;
while(( t = tr_torrentNext( session, tor ))) {
if( t->queuePosition > tor->queuePosition ) {
t->queuePosition--;
t->anyDate = now;
}
}
assert( queueIsSequenced( session ) );
tr_bandwidthDestruct( &tor->bandwidth );
tr_metainfoFree( inf );
@ -1540,7 +1554,7 @@ freeTorrent( tr_torrent * tor )
*** Start/Stop Callback
**/
static void queueRemove( tr_torrent * tor );
static void torrentSetQueued( tr_torrent * tor, bool queued );
static void
torrentStartImpl( void * vtor )
@ -1553,7 +1567,7 @@ torrentStartImpl( void * vtor )
tr_sessionLock( tor->session );
tr_torrentRecheckCompleteness( tor );
queueRemove( tor );
torrentSetQueued( tor, false );
now = tr_time( );
tor->isRunning = true;
@ -1602,8 +1616,6 @@ torrentShouldQueue( const tr_torrent * tor )
return tr_sessionCountQueueFreeSlots( tor->session, dir ) == 0;
}
static void queueAppend( tr_torrent * tor );
static void
torrentStart( tr_torrent * tor, bool bypass_queue )
{
@ -1630,7 +1642,7 @@ torrentStart( tr_torrent * tor, bool bypass_queue )
case TR_STATUS_STOPPED:
if( !bypass_queue && torrentShouldQueue( tor ) ) {
queueAppend( tor );
torrentSetQueued( tor, true );
return;
}
break;
@ -1754,7 +1766,7 @@ stopTorrent( void * vtor )
tr_torrentLock( tor );
tr_verifyRemove( tor );
queueRemove( tor );
torrentSetQueued( tor, false );
tr_peerMgrStopTorrent( tor );
tr_announcerTorrentStopped( tor );
tr_cacheFlushTorrent( tor->session->cache, tor );
@ -3174,31 +3186,28 @@ compareTorrentByQueuePosition( const void * va, const void * vb )
}
static bool
queueIsSequenced( tr_torrent * tor )
queueIsSequenced( tr_session * session )
{
int i ;
int n ;
bool is_sequenced = true;
tr_session * session = tor->session;
tr_direction direction = tr_torrentGetQueueDirection( tor );
tr_torrent * tor;
tr_torrent ** tmp = tr_new( tr_torrent *, session->torrentCount );
/* get all the torrents in that queue */
/* get all the torrents */
n = 0;
tor = NULL;
while(( tor = tr_torrentNext( session, tor )))
if( tr_torrentIsQueued( tor ) && ( direction == tr_torrentGetQueueDirection( tor ) ) )
tmp[n++] = tor;
tmp[n++] = tor;
/* sort them by position */
qsort( tmp, n, sizeof( tr_torrent * ), compareTorrentByQueuePosition );
#if 0
/* print them */
fprintf( stderr, "sequence: " );
fprintf( stderr, "%s", "queue: " );
for( i=0; i<n; ++i )
fprintf( stderr, "%d ", tmp[i]->queuePosition );
fprintf( stderr, "\n" );
fputc( '\n', stderr );
#endif
/* test them */
@ -3219,48 +3228,41 @@ tr_torrentGetQueuePosition( const tr_torrent * tor )
void
tr_torrentSetQueuePosition( tr_torrent * tor, int pos )
{
if( tr_torrentIsQueued( tor ) )
int back = -1;
tr_torrent * walk;
const int old_pos = tor->queuePosition;
const time_t now = tr_time( );
if( pos < 0 )
pos = 0;
tor->queuePosition = -1;
walk = NULL;
while(( walk = tr_torrentNext( tor->session, walk )))
{
int back = -1;
tr_torrent * walk;
const tr_direction direction = tr_torrentGetQueueDirection( tor );
const int old_pos = tor->queuePosition;
const time_t now = tr_time( );
if( pos < 0 )
pos = 0;
tor->queuePosition = -1;
walk = NULL;
while(( walk = tr_torrentNext( tor->session, walk )))
{
if( tr_torrentIsQueued( walk ) && ( tr_torrentGetQueueDirection( walk ) == direction ) )
{
if( old_pos < pos ) {
if( ( old_pos <= walk->queuePosition ) && ( walk->queuePosition <= pos ) ) {
walk->queuePosition--;
walk->anyDate = now;
}
}
if( old_pos > pos ) {
if( ( pos <= walk->queuePosition ) && ( walk->queuePosition < old_pos ) ) {
walk->queuePosition++;
walk->anyDate = now;
}
}
if( back < walk->queuePosition )
back = walk->queuePosition;
if( old_pos < pos ) {
if( ( old_pos <= walk->queuePosition ) && ( walk->queuePosition <= pos ) ) {
walk->queuePosition--;
walk->anyDate = now;
}
}
tor->queuePosition = MIN( pos, (back+1) );
tor->anyDate = now;
if( old_pos > pos ) {
if( ( pos <= walk->queuePosition ) && ( walk->queuePosition < old_pos ) ) {
walk->queuePosition++;
walk->anyDate = now;
}
}
if( back < walk->queuePosition )
back = walk->queuePosition;
}
assert( queueIsSequenced( tor ) );
tor->queuePosition = MIN( pos, (back+1) );
tor->anyDate = now;
assert( queueIsSequenced( tor->session ) );
}
void
@ -3307,63 +3309,15 @@ tr_torrentsQueueMoveBottom( tr_torrent ** torrents_in, int n )
tr_free( torrents );
}
/* Ensure that the torrents queued for downloads have queuePositions contiguous from [0...n] */
static void
queueResequence( tr_session * session, tr_direction direction )
torrentSetQueued( tr_torrent * tor, bool queued )
{
int i;
int n;
tr_torrent * tor = NULL;
tr_torrent ** tmp = tr_new( tr_torrent *, session->torrentCount );
const time_t now = tr_time( );
assert( tr_isTorrent( tor ) );
assert( tr_isBool( queued ) );
assert( tr_isSession( session ) );
assert( tr_isDirection( direction ) );
/* get all the torrents in that queue */
n = 0;
while(( tor = tr_torrentNext( session, tor ))) {
if( direction == tr_torrentGetQueueDirection( tor )) {
const int position = tr_torrentGetQueuePosition( tor );
if( position >= 0 )
tmp[n++] = tor;
}
}
/* sort them by position */
qsort( tmp, n, sizeof( tr_torrent * ), compareTorrentByQueuePosition );
/* sequence them... */
for( i=0; i<n; ++i ) {
tr_torrent * tor = tmp[i];
if( tor->queuePosition != i ) {
tor->queuePosition = i;
tor->anyDate = now;
}
}
tr_free( tmp );
}
static void
queueRemove( tr_torrent * tor )
{
if( tr_torrentIsQueued( tor ) )
if( tr_torrentIsQueued( tor ) != queued )
{
tor->queuePosition = -1;
queueResequence( tor->session, tr_torrentGetQueueDirection( tor ) );
}
}
static void
queueAppend( tr_torrent * tor )
{
if( !tr_torrentIsQueued( tor ) )
{
/* tr_torrentSetQueuePosition() requres the torrent to be queued,
so init tor->queuePosition to the back... */
tor->queuePosition = INT_MAX;
tr_torrentSetQueuePosition( tor, INT_MAX );
tor->isQueued = queued;
tor->anyDate = tr_time( );
}
}

View File

@ -241,6 +241,7 @@ struct tr_torrent
bool isDeleting;
bool startAfterVerify;
bool isDirty;
bool isQueued;
bool infoDictOffsetIsCached;
@ -433,7 +434,7 @@ bool tr_torrentIsStalled( const tr_torrent * tor );
static inline bool
tr_torrentIsQueued( const tr_torrent * tor )
{
return tor->queuePosition >= 0;
return tor->isQueued;
}
static inline tr_direction

View File

@ -1997,8 +1997,8 @@ typedef struct tr_stat
As a result, only paused torrents can be finished. */
bool finished;
/** The position of this torrent in the download queue.
This will be >= 0 if the torrent is queued; -1 otherwise. */
/** This torrent's queue position.
All torrents have a queue position, even if it's not queued. */
int queuePosition;
/** True if the torrent is running, but has been idle for long enough

View File

@ -39,6 +39,7 @@ const QString SortMode::names[NUM_MODES] = {
"sort-by-eta",
"sort-by-name",
"sort-by-progress",
"sort-by-queue"
"sort-by-ratio",
"sort-by-size",
"sort-by-state",

View File

@ -42,7 +42,7 @@ class SortMode
SortMode( const QString& name ): myMode(modeFromName(name)) { }
static const QString names[];
enum { SORT_BY_ACTIVITY, SORT_BY_AGE, SORT_BY_ETA, SORT_BY_NAME,
SORT_BY_PROGRESS, SORT_BY_RATIO, SORT_BY_SIZE,
SORT_BY_PROGRESS, SORT_BY_QUEUE, SORT_BY_RATIO, SORT_BY_SIZE,
SORT_BY_STATE, SORT_BY_ID, NUM_MODES };
static int modeFromName( const QString& name );
static const QString& nameFromMode( int mode );

View File

@ -140,6 +140,7 @@ TrMainWindow :: TrMainWindow( Session& session, Prefs& prefs, TorrentModel& mode
connect( ui.action_SortByETA, SIGNAL(toggled(bool)), this, SLOT(onSortByETAToggled(bool)));
connect( ui.action_SortByName, SIGNAL(toggled(bool)), this, SLOT(onSortByNameToggled(bool)));
connect( ui.action_SortByProgress, SIGNAL(toggled(bool)), this, SLOT(onSortByProgressToggled(bool)));
connect( ui.action_SortByQueue, SIGNAL(toggled(bool)), this, SLOT(onSortByQueueToggled(bool)));
connect( ui.action_SortByRatio, SIGNAL(toggled(bool)), this, SLOT(onSortByRatioToggled(bool)));
connect( ui.action_SortBySize, SIGNAL(toggled(bool)), this, SLOT(onSortBySizeToggled(bool)));
connect( ui.action_SortByState, SIGNAL(toggled(bool)), this, SLOT(onSortByStateToggled(bool)));
@ -520,6 +521,7 @@ void TrMainWindow :: onSortByAgeToggled ( bool b ) { if( b ) setSortPref( S
void TrMainWindow :: onSortByETAToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_ETA ); }
void TrMainWindow :: onSortByNameToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_NAME ); }
void TrMainWindow :: onSortByProgressToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_PROGRESS ); }
void TrMainWindow :: onSortByQueueToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_QUEUE ); }
void TrMainWindow :: onSortByRatioToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_RATIO ); }
void TrMainWindow :: onSortBySizeToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_SIZE ); }
void TrMainWindow :: onSortByStateToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_STATE ); }
@ -758,10 +760,10 @@ TrMainWindow :: refreshActionSensitivity( )
ui.action_Pause->setEnabled( selectedAndPaused < selected );
ui.action_Announce->setEnabled( selected > 0 && ( canAnnounce == selected ) );
ui.action_QueueMoveTop->setEnabled( selectedAndQueued > 0 );
ui.action_QueueMoveUp->setEnabled( selectedAndQueued > 0 );
ui.action_QueueMoveDown->setEnabled( selectedAndQueued > 0 );
ui.action_QueueMoveBottom->setEnabled( selectedAndQueued > 0 );
ui.action_QueueMoveTop->setEnabled( haveSelection );
ui.action_QueueMoveUp->setEnabled( haveSelection );
ui.action_QueueMoveDown->setEnabled( haveSelection );
ui.action_QueueMoveBottom->setEnabled( haveSelection );
if( myDetailsDialog )
myDetailsDialog->setIds( getSelectedTorrents( ) );
@ -959,6 +961,7 @@ TrMainWindow :: refreshPref( int key )
ui.action_SortByETA->setChecked ( i == SortMode::SORT_BY_ETA );
ui.action_SortByName->setChecked ( i == SortMode::SORT_BY_NAME );
ui.action_SortByProgress->setChecked ( i == SortMode::SORT_BY_PROGRESS );
ui.action_SortByQueue->setChecked ( i == SortMode::SORT_BY_QUEUE );
ui.action_SortByRatio->setChecked ( i == SortMode::SORT_BY_RATIO );
ui.action_SortBySize->setChecked ( i == SortMode::SORT_BY_SIZE );
ui.action_SortByState->setChecked ( i == SortMode::SORT_BY_STATE );

View File

@ -138,6 +138,7 @@ class TrMainWindow: public QMainWindow
void onSortByETAToggled ( bool );
void onSortByNameToggled ( bool );
void onSortByProgressToggled ( bool );
void onSortByQueueToggled ( bool );
void onSortByRatioToggled ( bool );
void onSortBySizeToggled ( bool );
void onSortByStateToggled ( bool );

View File

@ -126,6 +126,7 @@
<addaction name="action_SortByAge"/>
<addaction name="action_SortByName"/>
<addaction name="action_SortByProgress"/>
<addaction name="action_SortByQueue"/>
<addaction name="action_SortByRatio"/>
<addaction name="action_SortBySize"/>
<addaction name="action_SortByState"/>
@ -632,6 +633,14 @@
<string>Move to &amp;Bottom</string>
</property>
</action>
<action name="action_SortByQueue">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Sort by &amp;Queue</string>
</property>
</action>
</widget>
<resources>
<include location="application.qrc"/>

View File

@ -85,6 +85,9 @@ TorrentFilter :: lessThan( const QModelIndex& left, const QModelIndex& right ) c
switch( myPrefs.get<SortMode>(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;
@ -101,12 +104,12 @@ TorrentFilter :: lessThan( const QModelIndex& left, const QModelIndex& right ) c
case SortMode :: SORT_BY_STATE:
if( !val ) val = compare( a->hasError(), b->hasError() );
if( !val ) val = compare( a->getActivity(), b->getActivity() );
if( !val ) val = a->compareQueue( *b );
if( !val ) val = -compare( a->queuePosition(), b->queuePosition() );
// fall through
case SortMode :: SORT_BY_PROGRESS:
if( !val ) val = compare( a->percentComplete(), b->percentComplete() );
if( !val ) val = a->compareSeedRatio( *b );
if( !val ) val = a->compareQueue( *b );
if( !val ) val = -compare( a->queuePosition(), b->queuePosition() );
case SortMode :: SORT_BY_RATIO:
if( !val ) val = a->compareRatio( *b );
break;

View File

@ -370,18 +370,6 @@ Torrent :: hasTrackerSubstring( const QString& substr ) const
return false;
}
int
Torrent :: compareQueue( const Torrent& that ) const
{
const bool a_is_queued = isQueued( );
const bool b_is_queued = that.isQueued( );
if( a_is_queued != b_is_queued )
return a_is_queued ? -1 : 1;
return that.queuePosition() - queuePosition();
}
int
Torrent :: compareSeedRatio( const Torrent& that ) const
{
@ -718,10 +706,10 @@ Torrent :: activityString( ) const
case TR_STATUS_STOPPED: str = isFinished() ? tr( "Finished" ): tr( "Paused" ); break;
case TR_STATUS_CHECK_WAIT: str = tr( "Waiting to verify local data" ); break;
case TR_STATUS_CHECK: str = tr( "Verifying local data" ); break;
case TR_STATUS_DOWNLOAD_WAIT: str = tr( "Download queue #%1" ).arg( queuePosition() + 1 ); break;
case TR_STATUS_DOWNLOAD: str = tr( "Downloading" );
case TR_STATUS_SEED_WAIT: str = tr( "Seed queue #%1" ).arg( queuePosition() + 1 ); break;
case TR_STATUS_SEED: str = tr( "Seeding" ); break;
case TR_STATUS_DOWNLOAD_WAIT: str = tr( "Waiting to download" ); break;
case TR_STATUS_DOWNLOAD: str = tr( "Downloading" ); break;
case TR_STATUS_SEED_WAIT: str = tr( "Queued" ); break;
case TR_STATUS_SEED: str = tr( "Waiting to seed" ); break;
}
return str;

View File

@ -273,7 +273,6 @@ class Torrent: public QObject
int compareTracker( const Torrent& ) const;
int compareSeedRatio( const Torrent& ) const;
int compareRatio( const Torrent& ) const;
int compareQueue( const Torrent& ) const;
int compareETA( const Torrent& ) const;
bool hasETA( ) const { return getETA( ) >= 0; }
int getETA( ) const { return getInt( ETA ); }
@ -308,7 +307,6 @@ class Torrent: public QObject
PeerList peers( ) const{ return myValues[PEERS].value<PeerList>(); }
const FileList& files( ) const { return myFiles; }
int queuePosition( ) const { return getInt( QUEUE_POSITION ); }
bool isQueued( ) const { return queuePosition( ) >= 0; }
bool isStalled( ) const { return getBool( IS_STALLED ); }
public:
@ -323,6 +321,7 @@ class Torrent: public QObject
bool isSeeding( ) const { return getActivity( ) == TR_STATUS_SEED; }
bool isWaitingToSeed( ) const { return getActivity( ) == TR_STATUS_SEED_WAIT; }
bool isReadyToTransfer( ) const { return getActivity()==TR_STATUS_DOWNLOAD || getActivity()==TR_STATUS_SEED; }
bool isQueued( ) const { return isWaitingToDownload() || isWaitingToSeed(); }
void notifyComplete( ) const;
public:

View File

@ -526,6 +526,7 @@
<li id="sort_by_name">Name</li>
<li id="sort_by_percent_completed">Progress</li>
<li id="sort_by_ratio">Ratio</li>
<li id="sort_by_queue_order">Queue Order</li>
<li id="sort_by_state">State</li>
<li class="separator"></li>
<li id="reverse_sort_order">Reverse Sort Order</li>

View File

@ -233,6 +233,7 @@ Prefs._SortMethod = 'sort_method';
Prefs._SortByAge = 'age';
Prefs._SortByActivity = 'activity';
Prefs._SortByName = 'name';
Prefs._SortByQueue = 'queue_order';
Prefs._SortByProgress = 'percent_completed';
Prefs._SortByRatio = 'ratio';
Prefs._SortByState = 'state';

View File

@ -252,7 +252,8 @@ Torrent.prototype =
isSeeding: function() { return this.state() == Torrent._StatusSeed; },
name: function() { return this._name; },
queuePosition: function() { return this._queue_position; },
isQueued: function() { return this.queuePosition() >= 0; },
isQueued: function() { return ( this.state() == Torrent._StatusSeedWait )
|| ( this.state() == Torrent._StatusDownloadWait ); },
webseedsSendingToUs: function() { return this._webseeds_sending_to_us; },
peersSendingToUs: function() { return this._peers_sending_to_us; },
peersGettingFromUs: function() { return this._peers_getting_from_us; },
@ -272,9 +273,9 @@ Torrent.prototype =
case Torrent._StatusStopped: return this.isFinished() ? 'Seeding complete' : 'Paused';
case Torrent._StatusCheckWait: return 'Waiting to verify local data';
case Torrent._StatusCheck: return 'Verifying local data';
case Torrent._StatusDownloadWait: return 'Waiting to download #' + (this.queuePosition()+1);
case Torrent._StatusDownloadWait: return 'Waiting to download';
case Torrent._StatusDownload: return 'Downloading';
case Torrent._StatusSeedWait: return 'Waiting to seed #' + (this.queuePosition()+1);
case Torrent._StatusSeedWait: return 'Waiting to seed';
case Torrent._StatusSeed: return 'Seeding';
default: return 'error';
}
@ -770,17 +771,7 @@ Torrent.compareByName = function( a, b ) {
/** Helper function for sortTorrents(). */
Torrent.compareByQueue = function( a, b )
{
var a_is_queued = a.isQueued( );
var b_is_queued = b.isQueued( );
if( a_is_queued != b_is_queued )
return a_is_queued ? -1 : 1;
var a_pos = a.queuePosition( );
var b_pos = b.queuePosition( );
if( a_pos != b_pos )
return a_pos - b_pos;
return Torrent.compareByName( a, b );
return a.queuePosition( ) - b.queuePosition();
};
/** Helper function for sortTorrents(). */
@ -846,6 +837,9 @@ Torrent.sortTorrents = function( torrents, sortMethod, sortDirection )
case Prefs._SortByAge:
torrents.sort( this.compareByAge );
break;
case Prefs._SortByQueue:
torrents.sort( this.compareByQueue );
break;
case Prefs._SortByProgress:
torrents.sort( this.compareByProgress );
break;