From 307754e8075f8e6b097804439fdd1c80063a8cc9 Mon Sep 17 00:00:00 2001 From: Jordan Lee Date: Tue, 2 Aug 2011 03:59:54 +0000 Subject: [PATCH] #671 "torrent queuing" -- modify the queue implementation s.t. every torrent has a queuePosition, even if it's not currently in the queue. --- gtk/actions.c | 11 ++- gtk/main.c | 37 ++++---- gtk/torrent-cell-renderer.c | 9 +- gtk/tr-core.c | 26 +++--- gtk/ui.h | 1 + libtransmission/rpcimpl.c | 2 +- libtransmission/session.c | 22 +++-- libtransmission/torrent.c | 164 ++++++++++++--------------------- libtransmission/torrent.h | 3 +- libtransmission/transmission.h | 4 +- qt/filters.cc | 1 + qt/filters.h | 2 +- qt/mainwin.cc | 11 ++- qt/mainwin.h | 1 + qt/mainwin.ui | 9 ++ qt/torrent-filter.cc | 7 +- qt/torrent.cc | 20 +--- qt/torrent.h | 3 +- web/index.html | 1 + web/javascript/common.js | 1 + web/javascript/torrent.js | 22 ++--- 21 files changed, 159 insertions(+), 198 deletions(-) diff --git a/gtk/actions.c b/gtk/actions.c index b4c8cc921..50de23948 100644 --- a/gtk/actions.c +++ b/gtk/actions.c @@ -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 diff --git a/gtk/main.c b/gtk/main.c index 867959ba8..7909450d3 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -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 ); diff --git a/gtk/torrent-cell-renderer.c b/gtk/torrent-cell-renderer.c index 1b1bb18e4..56900a804 100644 --- a/gtk/torrent-cell-renderer.c +++ b/gtk/torrent-cell-renderer.c @@ -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 ) diff --git a/gtk/tr-core.c b/gtk/tr-core.c index 7c6849d9e..5bd8e71b6 100644 --- a/gtk/tr-core.c +++ b/gtk/tr-core.c @@ -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" ) ) diff --git a/gtk/ui.h b/gtk/ui.h index 3f998c559..2ea24c41a 100644 --- a/gtk/ui.h +++ b/gtk/ui.h @@ -50,6 +50,7 @@ static const char * fallback_ui_file = " \n" " \n" " \n" + " \n" " \n" " \n" " \n" diff --git a/libtransmission/rpcimpl.c b/libtransmission/rpcimpl.c index 2caa9a76c..a4b784f6b 100644 --- a/libtransmission/rpcimpl.c +++ b/libtransmission/rpcimpl.c @@ -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 ); diff --git a/libtransmission/session.c b/libtransmission/session.c index 148ab8631..430d233be 100644 --- a/libtransmission/session.c +++ b/libtransmission/session.c @@ -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; diff --git a/libtransmission/torrent.c b/libtransmission/torrent.c index a2278fb34..321f885b3 100644 --- a/libtransmission/torrent.c +++ b/libtransmission/torrent.c @@ -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; iqueuePosition ); - 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 tr_direction direction = tr_torrentGetQueueDirection( tor ); - const int old_pos = tor->queuePosition; - const time_t now = tr_time( ); - - if( pos < 0 ) - pos = 0; + int back = -1; + tr_torrent * walk; + const int old_pos = tor->queuePosition; + const time_t now = tr_time( ); - tor->queuePosition = -1; + if( pos < 0 ) + pos = 0; - 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; - } - } + tor->queuePosition = -1; - if( old_pos > pos ) { - if( ( pos <= walk->queuePosition ) && ( walk->queuePosition < old_pos ) ) { - walk->queuePosition++; - walk->anyDate = now; - } - } + walk = NULL; + while(( walk = tr_torrentNext( tor->session, walk ))) + { + if( old_pos < pos ) { + if( ( old_pos <= walk->queuePosition ) && ( walk->queuePosition <= pos ) ) { + walk->queuePosition--; + walk->anyDate = now; + } + } - if( back < walk->queuePosition ) - back = walk->queuePosition; + if( old_pos > pos ) { + if( ( pos <= walk->queuePosition ) && ( walk->queuePosition < old_pos ) ) { + walk->queuePosition++; + walk->anyDate = now; } } - tor->queuePosition = MIN( pos, (back+1) ); - tor->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 ) -{ - 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_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; iqueuePosition != i ) { - tor->queuePosition = i; - tor->anyDate = now; - } - } - - tr_free( tmp ); -} - static void -queueRemove( tr_torrent * tor ) +torrentSetQueued( tr_torrent * tor, bool queued ) { - if( tr_torrentIsQueued( tor ) ) - { - tor->queuePosition = -1; - queueResequence( tor->session, tr_torrentGetQueueDirection( tor ) ); - } -} + assert( tr_isTorrent( tor ) ); + assert( tr_isBool( queued ) ); -static void -queueAppend( tr_torrent * tor ) -{ - if( !tr_torrentIsQueued( tor ) ) + if( tr_torrentIsQueued( tor ) != queued ) { - /* 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( ); } } diff --git a/libtransmission/torrent.h b/libtransmission/torrent.h index 8732bc468..79112fb2d 100644 --- a/libtransmission/torrent.h +++ b/libtransmission/torrent.h @@ -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 diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h index 66fab0de1..16000557c 100644 --- a/libtransmission/transmission.h +++ b/libtransmission/transmission.h @@ -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 diff --git a/qt/filters.cc b/qt/filters.cc index 64e9855d0..d2122f638 100644 --- a/qt/filters.cc +++ b/qt/filters.cc @@ -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", diff --git a/qt/filters.h b/qt/filters.h index 2bb42aee1..f41317387 100644 --- a/qt/filters.h +++ b/qt/filters.h @@ -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 ); diff --git a/qt/mainwin.cc b/qt/mainwin.cc index ba6a87350..88873fb04 100644 --- a/qt/mainwin.cc +++ b/qt/mainwin.cc @@ -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 ); diff --git a/qt/mainwin.h b/qt/mainwin.h index 6147c164c..5218f6b6c 100644 --- a/qt/mainwin.h +++ b/qt/mainwin.h @@ -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 ); diff --git a/qt/mainwin.ui b/qt/mainwin.ui index 78e5bce76..1ebddd3e5 100644 --- a/qt/mainwin.ui +++ b/qt/mainwin.ui @@ -126,6 +126,7 @@ + @@ -632,6 +633,14 @@ Move to &Bottom + + + true + + + Sort by &Queue + + diff --git a/qt/torrent-filter.cc b/qt/torrent-filter.cc index 45f4ccace..c71d32114 100644 --- a/qt/torrent-filter.cc +++ b/qt/torrent-filter.cc @@ -85,6 +85,9 @@ TorrentFilter :: lessThan( const QModelIndex& left, const QModelIndex& right ) c 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; @@ -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; diff --git a/qt/torrent.cc b/qt/torrent.cc index 038f9cf04..d87902248 100644 --- a/qt/torrent.cc +++ b/qt/torrent.cc @@ -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; diff --git a/qt/torrent.h b/qt/torrent.h index 2e5796fd7..5e05de5d5 100644 --- a/qt/torrent.h +++ b/qt/torrent.h @@ -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(); } 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: diff --git a/web/index.html b/web/index.html index b8df0e961..bff9a4576 100755 --- a/web/index.html +++ b/web/index.html @@ -526,6 +526,7 @@
  • Name
  • Progress
  • Ratio
  • +
  • Queue Order
  • State
  • Reverse Sort Order
  • diff --git a/web/javascript/common.js b/web/javascript/common.js index bfb28a62b..d8be8497c 100644 --- a/web/javascript/common.js +++ b/web/javascript/common.js @@ -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'; diff --git a/web/javascript/torrent.js b/web/javascript/torrent.js index 8da271e89..d64be234e 100644 --- a/web/javascript/torrent.js +++ b/web/javascript/torrent.js @@ -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; -- 2.40.0