2008-02-10 22:25:42 +00:00
/*
2009-01-10 23:09:07 +00:00
* This file Copyright ( C ) 2007 - 2009 Charles Kerr < charles @ transmissionbt . com >
2007-06-06 00:30:13 +00:00
*
2008-02-10 22:25:42 +00:00
* This file is licensed by the GPL version 2. Works owned by the
* Transmission project are granted a special exemption to clause 2 ( b )
2008-09-23 19:11:04 +00:00
* so that the bulk of its code can remain under the MIT license .
2008-02-10 22:25:42 +00:00
* This exemption does not extend to derived works not owned by
* the Transmission project .
2008-09-23 19:11:04 +00:00
*
2008-02-10 22:25:42 +00:00
* $ Id $
*/
2007-06-06 00:30:13 +00:00
2009-04-24 01:37:04 +00:00
# include <assert.h>
2009-01-12 19:30:34 +00:00
# include <math.h> /* ceil() */
2007-06-06 00:30:13 +00:00
# include <stddef.h>
2009-04-24 12:05:53 +00:00
# include <stdio.h> /* sscanf */
2007-06-06 00:30:13 +00:00
# include <stdlib.h>
# include <glib/gi18n.h>
# include <gtk/gtk.h>
2007-06-18 03:40:41 +00:00
2007-07-18 23:04:26 +00:00
# include <libtransmission/transmission.h>
2009-04-24 12:05:53 +00:00
# include <libtransmission/utils.h> /* tr_free */
2007-06-18 03:40:41 +00:00
# include "actions.h"
2008-02-19 03:57:03 +00:00
# include "details.h"
2008-02-10 22:25:42 +00:00
# include "file-list.h"
2007-06-06 00:30:13 +00:00
# include "hig.h"
2009-09-25 21:05:59 +00:00
# include "tr-prefs.h"
2007-06-06 00:30:13 +00:00
# include "util.h"
2009-04-24 01:37:04 +00:00
# define DETAILS_KEY "details-data"
2008-12-22 05:39:03 +00:00
# define UPDATE_INTERVAL_SECONDS 2
2009-03-05 17:18:36 +00:00
2009-04-24 01:37:04 +00:00
struct DetailsImpl
2009-02-13 18:23:56 +00:00
{
2009-04-24 01:37:04 +00:00
GtkWidget * peersPage ;
GtkWidget * trackerPage ;
GtkWidget * activityPage ;
GtkWidget * honorLimitsCheck ;
GtkWidget * upLimitedCheck ;
GtkWidget * upLimitSpin ;
GtkWidget * downLimitedCheck ;
GtkWidget * downLimitSpin ;
GtkWidget * bandwidthCombo ;
GtkWidget * seedGlobalRadio ;
GtkWidget * seedForeverRadio ;
GtkWidget * seedCustomRadio ;
GtkWidget * seedCustomSpin ;
GtkWidget * maxPeersSpin ;
guint honorLimitsCheckTag ;
guint upLimitedCheckTag ;
guint downLimitedCheckTag ;
guint downLimitSpinTag ;
guint upLimitSpinTag ;
guint bandwidthComboTag ;
guint seedForeverRadioTag ;
guint seedGlobalRadioTag ;
guint seedCustomRadioTag ;
guint seedCustomSpinTag ;
2009-04-25 14:08:40 +00:00
guint maxPeersSpinTag ;
2007-06-06 00:30:13 +00:00
2009-06-23 00:24:37 +00:00
GtkWidget * size_lb ;
2009-04-24 01:37:04 +00:00
GtkWidget * state_lb ;
GtkWidget * have_lb ;
GtkWidget * dl_lb ;
GtkWidget * ul_lb ;
GtkWidget * ratio_lb ;
GtkWidget * error_lb ;
2009-06-23 00:24:37 +00:00
GtkWidget * date_started_lb ;
2009-04-24 01:37:04 +00:00
GtkWidget * last_activity_lb ;
2007-06-06 00:30:13 +00:00
2009-04-24 01:37:04 +00:00
GtkWidget * hash_lb ;
GtkWidget * privacy_lb ;
2009-06-23 00:24:37 +00:00
GtkWidget * origin_lb ;
2009-04-24 01:37:04 +00:00
GtkWidget * destination_lb ;
GtkTextBuffer * comment_buffer ;
GHashTable * peer_hash ;
GHashTable * webseed_hash ;
GtkListStore * peer_store ;
GtkListStore * webseed_store ;
GtkWidget * webseed_view ;
2009-09-25 21:05:59 +00:00
GtkListStore * trackers ;
GtkTreeModel * trackers_filtered ;
GtkWidget * tracker_view ;
GtkWidget * scrape_check ;
GtkWidget * all_check ;
2009-09-26 00:48:07 +00:00
GtkTextBuffer * tracker_buffer ;
2009-04-24 01:37:04 +00:00
GtkWidget * file_list ;
GSList * ids ;
TrCore * core ;
guint periodic_refresh_tag ;
2008-06-10 02:36:52 +00:00
} ;
2009-04-24 01:37:04 +00:00
static tr_torrent * *
getTorrents ( struct DetailsImpl * d , int * setmeCount )
2008-06-10 02:36:52 +00:00
{
2009-04-24 01:37:04 +00:00
int n = g_slist_length ( d - > ids ) ;
int torrentCount = 0 ;
tr_session * session = tr_core_session ( d - > core ) ;
2009-06-15 00:01:38 +00:00
tr_torrent * * torrents = NULL ;
if ( session ! = NULL )
{
GSList * l ;
torrents = g_new ( tr_torrent * , n ) ;
for ( l = d - > ids ; l ! = NULL ; l = l - > next ) {
const int id = GPOINTER_TO_INT ( l - > data ) ;
tr_torrent * tor = tr_torrentFindFromId ( session , id ) ;
if ( tor )
torrents [ torrentCount + + ] = tor ;
}
2009-04-24 01:37:04 +00:00
}
* setmeCount = torrentCount ;
return torrents ;
}
2008-06-10 02:36:52 +00:00
2009-04-24 01:37:04 +00:00
/****
* * * * *
* * * * * OPTIONS TAB
* * * * *
* * * */
static void
set_togglebutton_if_different ( GtkWidget * w , guint tag , gboolean value )
2008-06-10 02:36:52 +00:00
{
2009-04-24 01:37:04 +00:00
GtkToggleButton * toggle = GTK_TOGGLE_BUTTON ( w ) ;
const gboolean currentValue = gtk_toggle_button_get_active ( toggle ) ;
if ( currentValue ! = value )
2008-06-10 02:36:52 +00:00
{
2009-04-24 01:37:04 +00:00
g_signal_handler_block ( toggle , tag ) ;
gtk_toggle_button_set_active ( toggle , value ) ;
g_signal_handler_unblock ( toggle , tag ) ;
2008-06-10 02:36:52 +00:00
}
}
2009-04-24 01:37:04 +00:00
static void
set_int_spin_if_different ( GtkWidget * w , guint tag , int value )
2007-06-06 00:30:13 +00:00
{
2009-04-24 01:37:04 +00:00
GtkSpinButton * spin = GTK_SPIN_BUTTON ( w ) ;
const int currentValue = gtk_spin_button_get_value_as_int ( spin ) ;
if ( currentValue ! = value )
{
g_signal_handler_block ( spin , tag ) ;
gtk_spin_button_set_value ( spin , value ) ;
g_signal_handler_unblock ( spin , tag ) ;
}
}
2007-06-06 00:30:13 +00:00
2009-04-24 01:37:04 +00:00
static void
set_double_spin_if_different ( GtkWidget * w , guint tag , double value )
2007-06-06 00:30:13 +00:00
{
2009-04-24 01:37:04 +00:00
GtkSpinButton * spin = GTK_SPIN_BUTTON ( w ) ;
const double currentValue = gtk_spin_button_get_value ( spin ) ;
if ( ( ( int ) ( currentValue * 100 ) ! = ( int ) ( value * 100 ) ) )
{
g_signal_handler_block ( spin , tag ) ;
gtk_spin_button_set_value ( spin , value ) ;
g_signal_handler_unblock ( spin , tag ) ;
}
}
2007-06-06 00:30:13 +00:00
2009-04-24 01:37:04 +00:00
static void
set_int_combo_if_different ( GtkWidget * w , guint tag , int column , int value )
2007-06-06 00:30:13 +00:00
{
2009-04-24 01:37:04 +00:00
int i ;
int currentValue ;
2009-04-24 15:24:43 +00:00
GtkTreeIter iter ;
GtkComboBox * combobox = GTK_COMBO_BOX ( w ) ;
GtkTreeModel * model = gtk_combo_box_get_model ( combobox ) ;
2008-09-23 19:11:04 +00:00
2009-04-24 01:37:04 +00:00
/* do the value and current value match? */
if ( gtk_combo_box_get_active_iter ( combobox , & iter ) ) {
gtk_tree_model_get ( model , & iter , column , & currentValue , - 1 ) ;
if ( currentValue = = value )
return ;
}
/* find the one to select */
i = 0 ;
while ( ( gtk_tree_model_iter_nth_child ( model , & iter , NULL , i + + ) ) ) {
gtk_tree_model_get ( model , & iter , column , & currentValue , - 1 ) ;
if ( currentValue = = value ) {
g_signal_handler_block ( combobox , tag ) ;
gtk_combo_box_set_active_iter ( combobox , & iter ) ;
g_signal_handler_unblock ( combobox , tag ) ;
return ;
}
}
2007-06-06 00:30:13 +00:00
}
2008-09-23 19:11:04 +00:00
2009-04-24 01:37:04 +00:00
static void
unset_combo ( GtkWidget * w , guint tag )
2007-06-06 00:30:13 +00:00
{
2009-04-24 01:37:04 +00:00
GtkComboBox * combobox = GTK_COMBO_BOX ( w ) ;
2008-09-23 19:11:04 +00:00
2009-04-24 01:37:04 +00:00
g_signal_handler_block ( combobox , tag ) ;
gtk_combo_box_set_active ( combobox , - 1 ) ;
g_signal_handler_unblock ( combobox , tag ) ;
2007-06-06 00:30:13 +00:00
}
static void
2009-04-24 01:37:04 +00:00
refreshOptions ( struct DetailsImpl * di , tr_torrent * * torrents , int n )
2007-06-06 00:30:13 +00:00
{
2009-04-24 01:37:04 +00:00
/***
* * * * Options Page
* * */
/* honorLimitsCheck */
if ( n ) {
2009-04-24 15:24:43 +00:00
const tr_bool baseline = tr_torrentUsesSessionLimits ( torrents [ 0 ] ) ;
2009-04-24 01:37:04 +00:00
int i ;
for ( i = 1 ; i < n ; + + i )
if ( baseline ! = tr_torrentUsesSessionLimits ( torrents [ i ] ) )
break ;
if ( i = = n )
2009-04-24 12:05:53 +00:00
set_togglebutton_if_different ( di - > honorLimitsCheck ,
di - > honorLimitsCheckTag , baseline ) ;
2009-04-24 01:37:04 +00:00
}
2009-08-10 20:04:08 +00:00
2009-04-24 01:37:04 +00:00
/* downLimitedCheck */
if ( n ) {
2009-04-24 15:24:43 +00:00
const tr_bool baseline = tr_torrentUsesSpeedLimit ( torrents [ 0 ] , TR_DOWN ) ;
2009-04-24 01:37:04 +00:00
int i ;
for ( i = 1 ; i < n ; + + i )
if ( baseline ! = tr_torrentUsesSpeedLimit ( torrents [ i ] , TR_DOWN ) )
break ;
if ( i = = n )
2009-04-24 12:05:53 +00:00
set_togglebutton_if_different ( di - > downLimitedCheck ,
di - > downLimitedCheckTag , baseline ) ;
2009-04-24 01:37:04 +00:00
}
2008-09-23 19:11:04 +00:00
2009-04-24 01:37:04 +00:00
/* downLimitSpin */
if ( n ) {
const int baseline = tr_torrentGetSpeedLimit ( torrents [ 0 ] , TR_DOWN ) ;
int i ;
for ( i = 1 ; i < n ; + + i )
if ( baseline ! = tr_torrentGetSpeedLimit ( torrents [ i ] , TR_DOWN ) )
break ;
if ( i = = n )
2009-04-24 12:05:53 +00:00
set_int_spin_if_different ( di - > downLimitSpin ,
di - > downLimitSpinTag , baseline ) ;
2009-04-24 01:37:04 +00:00
}
2009-08-10 20:04:08 +00:00
2009-04-24 01:37:04 +00:00
/* upLimitedCheck */
if ( n ) {
2009-04-24 15:24:43 +00:00
const tr_bool baseline = tr_torrentUsesSpeedLimit ( torrents [ 0 ] , TR_UP ) ;
2009-04-24 01:37:04 +00:00
int i ;
for ( i = 1 ; i < n ; + + i )
if ( baseline ! = tr_torrentUsesSpeedLimit ( torrents [ i ] , TR_UP ) )
break ;
if ( i = = n )
2009-04-24 12:05:53 +00:00
set_togglebutton_if_different ( di - > upLimitedCheck ,
di - > upLimitedCheckTag , baseline ) ;
2009-04-24 01:37:04 +00:00
}
2008-09-23 19:11:04 +00:00
2009-04-24 01:37:04 +00:00
/* upLimitSpin */
if ( n ) {
const int baseline = tr_torrentGetSpeedLimit ( torrents [ 0 ] , TR_UP ) ;
int i ;
for ( i = 1 ; i < n ; + + i )
if ( baseline ! = tr_torrentGetSpeedLimit ( torrents [ i ] , TR_UP ) )
break ;
if ( i = = n )
2009-04-24 12:05:53 +00:00
set_int_spin_if_different ( di - > upLimitSpin ,
di - > upLimitSpinTag , baseline ) ;
2009-04-24 01:37:04 +00:00
}
2009-04-16 16:35:00 +00:00
2009-04-24 01:37:04 +00:00
/* bandwidthCombo */
if ( n ) {
const int baseline = tr_torrentGetPriority ( torrents [ 0 ] ) ;
int i ;
for ( i = 1 ; i < n ; + + i )
if ( baseline ! = tr_torrentGetPriority ( torrents [ i ] ) )
break ;
if ( i = = n )
2009-04-24 12:05:53 +00:00
set_int_combo_if_different ( di - > bandwidthCombo ,
di - > bandwidthComboTag , 0 , baseline ) ;
2009-04-24 01:37:04 +00:00
else
unset_combo ( di - > bandwidthCombo , di - > bandwidthComboTag ) ;
}
2007-06-06 00:30:13 +00:00
2009-04-24 01:37:04 +00:00
/* seedGlobalRadio */
/* seedForeverRadio */
/* seedCustomRadio */
if ( n ) {
2009-04-24 15:24:43 +00:00
guint t ;
2009-04-24 01:37:04 +00:00
const int baseline = tr_torrentGetRatioMode ( torrents [ 0 ] ) ;
int i ;
for ( i = 1 ; i < n ; + + i )
if ( baseline ! = ( int ) tr_torrentGetRatioMode ( torrents [ i ] ) )
break ;
if ( i = = n ) {
GtkWidget * w ;
switch ( baseline ) {
2009-04-24 15:24:43 +00:00
case TR_RATIOLIMIT_SINGLE : w = di - > seedCustomRadio ;
t = di - > seedCustomRadioTag ; break ;
case TR_RATIOLIMIT_UNLIMITED : w = di - > seedForeverRadio ;
t = di - > seedForeverRadioTag ; break ;
2009-05-12 20:58:30 +00:00
default /*TR_RATIOLIMIT_GLOBAL*/ : w = di - > seedGlobalRadio ;
t = di - > seedGlobalRadioTag ; break ;
2009-04-24 01:37:04 +00:00
}
2009-04-24 15:24:43 +00:00
set_togglebutton_if_different ( w , t , TRUE ) ;
2009-04-24 01:37:04 +00:00
}
}
2008-09-23 19:11:04 +00:00
2009-04-24 01:37:04 +00:00
/* seedCustomSpin */
if ( n ) {
const double baseline = tr_torrentGetRatioLimit ( torrents [ 0 ] ) ;
2009-04-25 14:08:40 +00:00
set_double_spin_if_different ( di - > seedCustomSpin ,
di - > seedCustomSpinTag , baseline ) ;
}
/* maxPeersSpin */
if ( n ) {
const int baseline = tr_torrentGetPeerLimit ( torrents [ 0 ] ) ;
set_int_spin_if_different ( di - > maxPeersSpin ,
di - > maxPeersSpinTag , baseline ) ;
2008-09-23 19:11:04 +00:00
}
2007-06-06 00:30:13 +00:00
}
2009-04-24 01:37:04 +00:00
static void
torrent_set_bool ( struct DetailsImpl * di , const char * key , gboolean value )
2007-06-06 00:30:13 +00:00
{
2009-04-24 01:37:04 +00:00
GSList * l ;
tr_benc top , * args , * ids ;
tr_bencInitDict ( & top , 2 ) ;
tr_bencDictAddStr ( & top , " method " , " torrent-set " ) ;
args = tr_bencDictAddDict ( & top , " arguments " , 2 ) ;
tr_bencDictAddBool ( args , key , value ) ;
ids = tr_bencDictAddList ( args , " ids " , g_slist_length ( di - > ids ) ) ;
for ( l = di - > ids ; l ; l = l - > next )
tr_bencListAddInt ( ids , GPOINTER_TO_INT ( l - > data ) ) ;
tr_core_exec ( di - > core , & top ) ;
tr_bencFree ( & top ) ;
2007-06-06 00:30:13 +00:00
}
2007-09-20 16:32:01 +00:00
static void
2009-04-24 01:37:04 +00:00
torrent_set_int ( struct DetailsImpl * di , const char * key , int value )
2007-09-20 16:32:01 +00:00
{
2009-04-24 01:37:04 +00:00
GSList * l ;
tr_benc top , * args , * ids ;
tr_bencInitDict ( & top , 2 ) ;
tr_bencDictAddStr ( & top , " method " , " torrent-set " ) ;
args = tr_bencDictAddDict ( & top , " arguments " , 2 ) ;
tr_bencDictAddInt ( args , key , value ) ;
ids = tr_bencDictAddList ( args , " ids " , g_slist_length ( di - > ids ) ) ;
for ( l = di - > ids ; l ; l = l - > next )
tr_bencListAddInt ( ids , GPOINTER_TO_INT ( l - > data ) ) ;
tr_core_exec ( di - > core , & top ) ;
tr_bencFree ( & top ) ;
2007-09-20 16:32:01 +00:00
}
2007-06-06 00:30:13 +00:00
static void
2009-04-24 01:37:04 +00:00
torrent_set_real ( struct DetailsImpl * di , const char * key , double value )
2007-06-06 00:30:13 +00:00
{
2009-04-24 01:37:04 +00:00
GSList * l ;
tr_benc top , * args , * ids ;
tr_bencInitDict ( & top , 2 ) ;
tr_bencDictAddStr ( & top , " method " , " torrent-set " ) ;
args = tr_bencDictAddDict ( & top , " arguments " , 2 ) ;
tr_bencDictAddReal ( args , key , value ) ;
ids = tr_bencDictAddList ( args , " ids " , g_slist_length ( di - > ids ) ) ;
for ( l = di - > ids ; l ; l = l - > next )
tr_bencListAddInt ( ids , GPOINTER_TO_INT ( l - > data ) ) ;
tr_core_exec ( di - > core , & top ) ;
tr_bencFree ( & top ) ;
2007-06-06 00:30:13 +00:00
}
static void
2009-04-24 12:05:53 +00:00
up_speed_toggled_cb ( GtkToggleButton * tb , gpointer d )
2007-06-06 00:30:13 +00:00
{
2009-04-24 12:05:53 +00:00
torrent_set_bool ( d , " uploadLimited " , gtk_toggle_button_get_active ( tb ) ) ;
2009-03-05 17:18:36 +00:00
}
2008-09-23 19:11:04 +00:00
2009-03-05 17:18:36 +00:00
static void
2009-04-24 12:05:53 +00:00
down_speed_toggled_cb ( GtkToggleButton * tb , gpointer d )
2009-03-05 17:18:36 +00:00
{
2009-04-24 12:05:53 +00:00
torrent_set_bool ( d , " downloadLimited " , gtk_toggle_button_get_active ( tb ) ) ;
2007-06-06 00:30:13 +00:00
}
static void
2009-04-24 12:05:53 +00:00
global_speed_toggled_cb ( GtkToggleButton * tb , gpointer d )
2007-06-06 00:30:13 +00:00
{
2009-04-24 12:05:53 +00:00
torrent_set_bool ( d , " honorsSessionLimits " , gtk_toggle_button_get_active ( tb ) ) ;
2007-06-06 00:30:13 +00:00
}
2009-04-24 12:05:53 +00:00
# define RATIO_KEY "ratio-mode"
2007-06-06 00:30:13 +00:00
static void
2009-04-24 12:05:53 +00:00
ratio_mode_changed_cb ( GtkToggleButton * tb , struct DetailsImpl * d )
2007-06-06 00:30:13 +00:00
{
2009-04-24 01:37:04 +00:00
if ( gtk_toggle_button_get_active ( tb ) )
2008-09-23 19:11:04 +00:00
{
2009-04-24 12:05:53 +00:00
GObject * o = G_OBJECT ( tb ) ;
const int mode = GPOINTER_TO_INT ( g_object_get_data ( o , RATIO_KEY ) ) ;
torrent_set_int ( d , " seedRatioMode " , mode ) ;
2008-09-23 19:11:04 +00:00
}
2007-06-06 00:30:13 +00:00
}
static void
2009-04-24 12:05:53 +00:00
up_speed_spun_cb ( GtkSpinButton * s , struct DetailsImpl * di )
2007-06-06 00:30:13 +00:00
{
2009-04-24 12:05:53 +00:00
torrent_set_int ( di , " uploadLimit " , gtk_spin_button_get_value_as_int ( s ) ) ;
2009-04-24 01:37:04 +00:00
}
2007-06-06 00:30:13 +00:00
2009-04-24 01:37:04 +00:00
static void
2009-04-24 12:05:53 +00:00
down_speed_spun_cb ( GtkSpinButton * s , struct DetailsImpl * di )
2009-04-24 01:37:04 +00:00
{
2009-04-24 12:05:53 +00:00
torrent_set_int ( di , " downloadLimit " , gtk_spin_button_get_value_as_int ( s ) ) ;
2009-04-24 01:37:04 +00:00
}
2008-09-23 19:11:04 +00:00
2009-04-24 01:37:04 +00:00
static void
2009-04-24 12:05:53 +00:00
ratio_spun_cb ( GtkSpinButton * s , struct DetailsImpl * di )
2009-04-24 01:37:04 +00:00
{
2009-04-24 12:05:53 +00:00
torrent_set_real ( di , " seedRatioLimit " , gtk_spin_button_get_value ( s ) ) ;
2009-04-24 01:37:04 +00:00
}
2008-09-23 19:11:04 +00:00
2009-04-24 01:37:04 +00:00
static void
2009-04-24 12:05:53 +00:00
max_peers_spun_cb ( GtkSpinButton * s , struct DetailsImpl * di )
2009-04-24 01:37:04 +00:00
{
2009-04-24 12:05:53 +00:00
torrent_set_int ( di , " peer-limit " , gtk_spin_button_get_value ( s ) ) ;
2009-04-24 01:37:04 +00:00
}
2008-09-23 19:11:04 +00:00
2009-04-24 01:37:04 +00:00
static void
2009-04-24 15:24:43 +00:00
onPriorityChanged ( GtkComboBox * w , struct DetailsImpl * di )
2009-04-24 01:37:04 +00:00
{
GtkTreeIter iter ;
2008-11-23 17:10:40 +00:00
2009-04-24 01:37:04 +00:00
if ( gtk_combo_box_get_active_iter ( w , & iter ) )
{
int val = 0 ;
gtk_tree_model_get ( gtk_combo_box_get_model ( w ) , & iter , 0 , & val , - 1 ) ;
torrent_set_int ( di , " bandwidthPriority " , val ) ;
}
2007-06-06 00:30:13 +00:00
}
2009-04-24 01:37:04 +00:00
static GtkWidget *
new_priority_combo ( struct DetailsImpl * di )
2008-04-12 01:36:31 +00:00
{
2009-04-24 01:37:04 +00:00
int i ;
guint tag ;
GtkWidget * w ;
GtkCellRenderer * r ;
GtkListStore * store ;
const struct {
int value ;
const char * text ;
} items [ ] = {
2009-06-29 06:49:35 +00:00
{ TR_PRI_HIGH , N_ ( " High " ) } ,
2009-04-24 01:37:04 +00:00
{ TR_PRI_NORMAL , N_ ( " Normal " ) } ,
2009-06-29 06:49:35 +00:00
{ TR_PRI_LOW , N_ ( " Low " ) }
2009-04-24 01:37:04 +00:00
} ;
2008-04-12 01:36:31 +00:00
2009-04-24 01:37:04 +00:00
store = gtk_list_store_new ( 2 , G_TYPE_INT , G_TYPE_STRING ) ;
for ( i = 0 ; i < ( int ) G_N_ELEMENTS ( items ) ; + + i ) {
GtkTreeIter iter ;
gtk_list_store_append ( store , & iter ) ;
2009-04-24 12:05:53 +00:00
gtk_list_store_set ( store , & iter , 0 , items [ i ] . value ,
1 , _ ( items [ i ] . text ) ,
- 1 ) ;
2008-04-12 01:36:31 +00:00
}
2009-04-24 01:37:04 +00:00
w = gtk_combo_box_new_with_model ( GTK_TREE_MODEL ( store ) ) ;
r = gtk_cell_renderer_text_new ( ) ;
gtk_cell_layout_pack_start ( GTK_CELL_LAYOUT ( w ) , r , TRUE ) ;
gtk_cell_layout_set_attributes ( GTK_CELL_LAYOUT ( w ) , r , " text " , 1 , NULL ) ;
2009-04-24 15:24:43 +00:00
tag = g_signal_connect ( w , " changed " , G_CALLBACK ( onPriorityChanged ) , di ) ;
2009-04-24 01:37:04 +00:00
di - > bandwidthComboTag = tag ;
/* cleanup */
2009-04-25 15:41:10 +00:00
g_object_unref ( store ) ;
2009-04-24 01:37:04 +00:00
return w ;
2008-04-12 01:36:31 +00:00
}
2008-09-23 19:11:04 +00:00
2008-04-12 01:36:31 +00:00
static GtkWidget *
2009-04-24 01:37:04 +00:00
options_page_new ( struct DetailsImpl * d )
2007-06-06 00:30:13 +00:00
{
2009-04-24 01:37:04 +00:00
guint tag ;
2009-05-12 20:58:30 +00:00
int row ;
2009-06-23 14:15:23 +00:00
const char * s ;
2009-04-24 01:37:04 +00:00
GSList * group ;
GtkWidget * t , * w , * tb , * h ;
2008-09-23 19:11:04 +00:00
2009-04-24 01:37:04 +00:00
row = 0 ;
t = hig_workarea_create ( ) ;
hig_workarea_add_section_title ( t , & row , _ ( " Speed " ) ) ;
2008-09-23 19:11:04 +00:00
2009-04-24 15:24:43 +00:00
tb = hig_workarea_add_wide_checkbutton ( t , & row , _ ( " Honor global _limits " ) , 0 ) ;
2009-04-24 12:05:53 +00:00
d - > honorLimitsCheck = tb ;
tag = g_signal_connect ( tb , " toggled " , G_CALLBACK ( global_speed_toggled_cb ) , d ) ;
d - > honorLimitsCheckTag = tag ;
tb = gtk_check_button_new_with_mnemonic ( _ ( " Limit _download speed (KB/s): " ) ) ;
gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON ( tb ) , FALSE ) ;
d - > downLimitedCheck = tb ;
tag = g_signal_connect ( tb , " toggled " , G_CALLBACK ( down_speed_toggled_cb ) , d ) ;
d - > downLimitedCheckTag = tag ;
w = gtk_spin_button_new_with_range ( 1 , INT_MAX , 5 ) ;
tag = g_signal_connect ( w , " value-changed " , G_CALLBACK ( down_speed_spun_cb ) , d ) ;
d - > downLimitSpinTag = tag ;
hig_workarea_add_row_w ( t , & row , tb , w , NULL ) ;
d - > downLimitSpin = w ;
tb = gtk_check_button_new_with_mnemonic ( _ ( " Limit _upload speed (KB/s): " ) ) ;
d - > upLimitedCheck = tb ;
tag = g_signal_connect ( tb , " toggled " , G_CALLBACK ( up_speed_toggled_cb ) , d ) ;
d - > upLimitedCheckTag = tag ;
w = gtk_spin_button_new_with_range ( 1 , INT_MAX , 5 ) ;
tag = g_signal_connect ( w , " value-changed " , G_CALLBACK ( up_speed_spun_cb ) , d ) ;
d - > upLimitSpinTag = tag ;
hig_workarea_add_row_w ( t , & row , tb , w , NULL ) ;
d - > upLimitSpin = w ;
w = new_priority_combo ( d ) ;
2009-06-23 00:24:37 +00:00
hig_workarea_add_row ( t , & row , _ ( " Torrent _priority: " ) , w , NULL ) ;
2009-04-24 12:05:53 +00:00
d - > bandwidthCombo = w ;
2008-09-23 19:11:04 +00:00
2009-04-24 01:37:04 +00:00
hig_workarea_add_section_divider ( t , & row ) ;
hig_workarea_add_section_title ( t , & row , _ ( " Seed-Until Ratio " ) ) ;
2008-09-23 19:11:04 +00:00
2009-04-24 12:05:53 +00:00
group = NULL ;
2009-06-23 03:40:32 +00:00
s = _ ( " Use _global settings " ) ;
2009-04-24 12:05:53 +00:00
w = gtk_radio_button_new_with_mnemonic ( group , s ) ;
group = gtk_radio_button_get_group ( GTK_RADIO_BUTTON ( w ) ) ;
hig_workarea_add_wide_control ( t , & row , w ) ;
g_object_set_data ( G_OBJECT ( w ) , RATIO_KEY , GINT_TO_POINTER ( TR_RATIOLIMIT_GLOBAL ) ) ;
tag = g_signal_connect ( w , " toggled " , G_CALLBACK ( ratio_mode_changed_cb ) , d ) ;
d - > seedGlobalRadio = w ;
d - > seedGlobalRadioTag = tag ;
w = gtk_radio_button_new_with_mnemonic ( group , _ ( " Seed _regardless of ratio " ) ) ;
group = gtk_radio_button_get_group ( GTK_RADIO_BUTTON ( w ) ) ;
hig_workarea_add_wide_control ( t , & row , w ) ;
g_object_set_data ( G_OBJECT ( w ) , RATIO_KEY , GINT_TO_POINTER ( TR_RATIOLIMIT_UNLIMITED ) ) ;
tag = g_signal_connect ( w , " toggled " , G_CALLBACK ( ratio_mode_changed_cb ) , d ) ;
d - > seedForeverRadio = w ;
d - > seedForeverRadioTag = tag ;
h = gtk_hbox_new ( FALSE , GUI_PAD ) ;
2009-06-23 00:24:37 +00:00
s = _ ( " _Seed torrent until its ratio reaches: " ) ;
w = gtk_radio_button_new_with_mnemonic ( group , s ) ;
2009-04-24 12:05:53 +00:00
d - > seedCustomRadio = w ;
g_object_set_data ( G_OBJECT ( w ) , RATIO_KEY , GINT_TO_POINTER ( TR_RATIOLIMIT_SINGLE ) ) ;
tag = g_signal_connect ( w , " toggled " , G_CALLBACK ( ratio_mode_changed_cb ) , d ) ;
d - > seedCustomRadioTag = tag ;
group = gtk_radio_button_get_group ( GTK_RADIO_BUTTON ( w ) ) ;
gtk_box_pack_start ( GTK_BOX ( h ) , w , FALSE , FALSE , 0 ) ;
2009-04-24 15:24:43 +00:00
w = gtk_spin_button_new_with_range ( 0 , INT_MAX , .05 ) ;
2009-04-24 12:05:53 +00:00
gtk_spin_button_set_digits ( GTK_SPIN_BUTTON ( w ) , 2 ) ;
tag = g_signal_connect ( w , " value-changed " , G_CALLBACK ( ratio_spun_cb ) , d ) ;
gtk_box_pack_start ( GTK_BOX ( h ) , w , FALSE , FALSE , 0 ) ;
hig_workarea_add_wide_control ( t , & row , h ) ;
d - > seedCustomSpin = w ;
d - > seedCustomSpinTag = tag ;
2009-08-10 20:04:08 +00:00
2009-04-24 01:37:04 +00:00
hig_workarea_add_section_divider ( t , & row ) ;
hig_workarea_add_section_title ( t , & row , _ ( " Peer Connections " ) ) ;
2007-06-06 00:30:13 +00:00
2009-04-24 12:05:53 +00:00
w = gtk_spin_button_new_with_range ( 1 , 3000 , 5 ) ;
hig_workarea_add_row ( t , & row , _ ( " _Maximum peers: " ) , w , w ) ;
2009-04-25 14:08:40 +00:00
tag = g_signal_connect ( w , " value-changed " , G_CALLBACK ( max_peers_spun_cb ) , d ) ;
2009-04-24 12:05:53 +00:00
d - > maxPeersSpin = w ;
2009-04-25 14:08:40 +00:00
d - > maxPeersSpinTag = tag ;
2008-09-23 19:11:04 +00:00
2009-04-24 01:37:04 +00:00
hig_workarea_finish ( t , & row ) ;
return t ;
2007-06-06 00:30:13 +00:00
}
/****
2009-04-24 01:37:04 +00:00
* * * * *
2009-06-23 00:24:37 +00:00
* * * * * INFO TAB
2009-04-24 01:37:04 +00:00
* * * * *
2007-06-06 00:30:13 +00:00
* * * */
2009-04-24 01:37:04 +00:00
static const char * activityString ( int activity )
2008-05-23 20:04:41 +00:00
{
2009-04-24 01:37:04 +00:00
switch ( activity )
2008-09-23 19:11:04 +00:00
{
2009-04-24 01:37:04 +00:00
case TR_STATUS_CHECK_WAIT : return _ ( " Waiting to verify local data " ) ; break ;
case TR_STATUS_CHECK : return _ ( " Verifying local data " ) ; break ;
case TR_STATUS_DOWNLOAD : return _ ( " Downloading " ) ; break ;
case TR_STATUS_SEED : return _ ( " Seeding " ) ; break ;
case TR_STATUS_STOPPED : return _ ( " Paused " ) ; break ;
2008-05-23 20:04:41 +00:00
}
2009-04-24 01:37:04 +00:00
return " " ;
2008-05-23 20:04:41 +00:00
}
2009-04-24 01:37:04 +00:00
static void
2009-06-23 00:24:37 +00:00
refreshInfo ( struct DetailsImpl * di , tr_torrent * * torrents , int n )
2007-06-06 00:30:13 +00:00
{
2009-04-24 01:37:04 +00:00
int i ;
const char * str ;
const char * none = _ ( " None " ) ;
const char * mixed = _ ( " Mixed " ) ;
char buf [ 512 ] ;
const tr_stat * * stats = g_new ( const tr_stat * , n ) ;
2009-06-23 00:24:37 +00:00
const tr_info * * infos = g_new ( const tr_info * , n ) ;
for ( i = 0 ; i < n ; + + i ) {
2009-04-24 01:37:04 +00:00
stats [ i ] = tr_torrentStatCached ( torrents [ i ] ) ;
2009-06-23 00:24:37 +00:00
infos [ i ] = tr_torrentInfo ( torrents [ i ] ) ;
}
/* privacy_lb */
if ( n < = 0 )
str = none ;
else {
const tr_bool baseline = infos [ 0 ] - > isPrivate ;
for ( i = 1 ; i < n ; + + i )
if ( baseline ! = infos [ i ] - > isPrivate )
break ;
if ( i ! = n )
str = mixed ;
else if ( baseline )
str = _ ( " Private to this tracker -- DHT and PEX disabled " ) ;
else
str = _ ( " Public torrent " ) ;
}
gtk_label_set_text ( GTK_LABEL ( di - > privacy_lb ) , str ) ;
/* origin_lb */
if ( n < = 0 )
str = none ;
else {
char datestr [ 64 ] ;
const char * creator = infos [ 0 ] - > creator ? infos [ 0 ] - > creator : " " ;
const time_t date = infos [ 0 ] - > dateCreated ;
gboolean mixed_creator = FALSE ;
gboolean mixed_date = FALSE ;
gtr_localtime2 ( datestr , date , sizeof ( datestr ) ) ;
for ( i = 1 ; i < n ; + + i ) {
mixed_creator | = strcmp ( creator , infos [ i ] - > creator ? infos [ i ] - > creator : " " ) ;
mixed_date | = ( date ! = infos [ i ] - > dateCreated ) ;
}
if ( mixed_date & & mixed_creator )
str = mixed ;
2009-08-04 03:10:35 +00:00
else {
if ( mixed_date )
g_snprintf ( buf , sizeof ( buf ) , _ ( " Created by %1$s " ) , creator ) ;
else if ( mixed_creator | | ! * creator )
g_snprintf ( buf , sizeof ( buf ) , _ ( " Created on %1$s " ) , datestr ) ;
else
g_snprintf ( buf , sizeof ( buf ) , _ ( " Created by %1$s on %2$s " ) , creator , datestr ) ;
str = buf ;
}
2009-06-23 00:24:37 +00:00
}
gtk_label_set_text ( GTK_LABEL ( di - > origin_lb ) , str ) ;
/* comment_buffer */
if ( n < = 0 )
str = " " ;
else {
const char * baseline = infos [ 0 ] - > comment ? infos [ 0 ] - > comment : " " ;
for ( i = 1 ; i < n ; + + i )
if ( strcmp ( baseline , infos [ i ] - > comment ? infos [ i ] - > comment : " " ) )
break ;
if ( i = = n )
str = baseline ;
else
str = mixed ;
}
gtk_text_buffer_set_text ( di - > comment_buffer , str , - 1 ) ;
2009-08-10 20:04:08 +00:00
/* destination_lb */
2009-06-23 00:24:37 +00:00
if ( n < = 0 )
str = none ;
else {
const char * baseline = tr_torrentGetDownloadDir ( torrents [ 0 ] ) ;
for ( i = 1 ; i < n ; + + i )
if ( strcmp ( baseline , tr_torrentGetDownloadDir ( torrents [ i ] ) ) )
break ;
if ( i = = n )
str = baseline ;
else
str = mixed ;
}
gtk_label_set_text ( GTK_LABEL ( di - > destination_lb ) , str ) ;
2009-04-24 01:37:04 +00:00
/* state_lb */
if ( n < = 0 )
str = none ;
else {
const int baseline = stats [ 0 ] - > activity ;
for ( i = 1 ; i < n ; + + i )
if ( baseline ! = ( int ) stats [ i ] - > activity )
break ;
2009-04-24 15:24:43 +00:00
if ( i = = n )
str = activityString ( baseline ) ;
else
str = mixed ;
2009-04-24 01:37:04 +00:00
}
gtk_label_set_text ( GTK_LABEL ( di - > state_lb ) , str ) ;
2007-06-06 00:30:13 +00:00
2009-03-05 17:18:36 +00:00
2009-06-23 00:24:37 +00:00
/* date started */
2009-04-24 01:37:04 +00:00
if ( n < = 0 )
str = none ;
else {
2009-06-23 00:24:37 +00:00
const time_t baseline = stats [ 0 ] - > startDate ;
for ( i = 1 ; i < n ; + + i )
if ( baseline ! = stats [ i ] - > startDate )
break ;
if ( i ! = n )
str = mixed ;
else if ( ( baseline < = 0 ) | | ( stats [ 0 ] - > activity = = TR_STATUS_STOPPED ) )
str = activityString ( TR_STATUS_STOPPED ) ;
else
str = tr_strltime ( buf , time ( NULL ) - baseline , sizeof ( buf ) ) ;
}
gtk_label_set_text ( GTK_LABEL ( di - > date_started_lb ) , str ) ;
/* size_lb */
{
char sizebuf [ 128 ] ;
uint64_t size = 0 ;
int pieces = 0 ;
int32_t pieceSize = 0 ;
2009-04-24 01:37:04 +00:00
for ( i = 0 ; i < n ; + + i ) {
2009-06-23 00:24:37 +00:00
size + = infos [ i ] - > totalSize ;
pieces + = infos [ i ] - > pieceCount ;
if ( ! pieceSize )
pieceSize = infos [ i ] - > pieceSize ;
else if ( pieceSize ! = ( int ) infos [ i ] - > pieceSize )
pieceSize = - 1 ;
2009-04-24 01:37:04 +00:00
}
2009-06-23 00:24:37 +00:00
tr_strlsize ( sizebuf , size , sizeof ( sizebuf ) ) ;
if ( ! size )
str = none ;
else if ( pieceSize > = 0 ) {
char piecebuf [ 128 ] ;
tr_strlsize ( piecebuf , ( uint64_t ) pieceSize , sizeof ( piecebuf ) ) ;
g_snprintf ( buf , sizeof ( buf ) ,
ngettext ( " %1$s (%2$'d piece @ %3$s) " ,
" %1$s (%2$'d pieces @ %3$s) " , pieces ) ,
sizebuf , pieces , piecebuf ) ;
str = buf ;
} else {
g_snprintf ( buf , sizeof ( buf ) ,
ngettext ( " %1$s (%2$'d piece) " ,
" %1$s (%2$'d pieces) " , pieces ) ,
sizebuf , pieces ) ;
str = buf ;
}
gtk_label_set_text ( GTK_LABEL ( di - > size_lb ) , str ) ;
2009-04-24 01:37:04 +00:00
}
2009-03-05 17:18:36 +00:00
2007-06-06 00:30:13 +00:00
2009-04-24 01:37:04 +00:00
/* have_lb */
if ( n < = 0 )
str = none ;
else {
2009-06-23 00:24:37 +00:00
double sizeWhenDone = 0 ;
double leftUntilDone = 0 ;
2009-04-24 01:37:04 +00:00
double haveUnchecked = 0 ;
double haveValid = 0 ;
double verifiedPieces = 0 ;
for ( i = 0 ; i < n ; + + i ) {
2009-04-24 15:24:43 +00:00
const double v = stats [ i ] - > haveValid ;
2009-04-24 01:37:04 +00:00
haveUnchecked + = stats [ i ] - > haveUnchecked ;
2009-04-24 15:24:43 +00:00
haveValid + = v ;
verifiedPieces + = v / tr_torrentInfo ( torrents [ i ] ) - > pieceSize ;
2009-06-23 00:24:37 +00:00
sizeWhenDone + = stats [ i ] - > sizeWhenDone ;
leftUntilDone + = stats [ i ] - > leftUntilDone ;
}
if ( ! haveValid & & ! haveUnchecked )
str = none ;
else {
2009-06-28 16:21:47 +00:00
char unver [ 64 ] , total [ 64 ] ;
2009-07-18 01:04:27 +00:00
const double ratio = 100.0 * ( leftUntilDone ? ( haveValid + haveUnchecked ) / sizeWhenDone : 1 ) ;
2009-06-28 16:21:47 +00:00
tr_strlsize ( total , haveUnchecked + haveValid , sizeof ( total ) ) ;
tr_strlsize ( unver , haveUnchecked , sizeof ( unver ) ) ;
if ( haveUnchecked )
2009-07-14 20:09:46 +00:00
g_snprintf ( buf , sizeof ( buf ) , _ ( " %1$s (%2$.1f%%); %3$s Unverified " ) , total , tr_truncd ( ratio , 1 ) , unver ) ;
2009-06-28 16:21:47 +00:00
else
2009-07-14 20:09:46 +00:00
g_snprintf ( buf , sizeof ( buf ) , _ ( " %1$s (%2$.1f%%) " ) , total , tr_truncd ( ratio , 1 ) ) ;
2009-06-23 00:24:37 +00:00
str = buf ;
2009-04-24 01:37:04 +00:00
}
}
gtk_label_set_text ( GTK_LABEL ( di - > have_lb ) , str ) ;
2007-06-06 00:30:13 +00:00
2009-08-10 20:04:08 +00:00
2009-04-24 01:37:04 +00:00
/* dl_lb */
if ( n < = 0 )
str = none ;
else {
2009-06-23 00:24:37 +00:00
char dbuf [ 64 ] , fbuf [ 64 ] ;
uint64_t d = 0 , f = 0 ;
for ( i = 0 ; i < n ; + + i ) {
d + = stats [ i ] - > downloadedEver ;
f + = stats [ i ] - > corruptEver ;
}
tr_strlsize ( dbuf , d , sizeof ( dbuf ) ) ;
tr_strlsize ( fbuf , f , sizeof ( fbuf ) ) ;
if ( f )
g_snprintf ( buf , sizeof ( buf ) , _ ( " %1$s (+%2$s corrupt) " ) , dbuf , fbuf ) ;
else
tr_strlcpy ( buf , dbuf , sizeof ( buf ) ) ;
str = buf ;
2009-04-24 01:37:04 +00:00
}
gtk_label_set_text ( GTK_LABEL ( di - > dl_lb ) , str ) ;
2007-06-06 00:30:13 +00:00
2009-08-10 20:04:08 +00:00
2009-04-24 01:37:04 +00:00
/* ul_lb */
if ( n < = 0 )
str = none ;
else {
uint64_t sum = 0 ;
for ( i = 0 ; i < n ; + + i ) sum + = stats [ i ] - > uploadedEver ;
2009-04-24 15:24:43 +00:00
str = tr_strlsize ( buf , sum , sizeof ( buf ) ) ;
2009-04-24 01:37:04 +00:00
}
gtk_label_set_text ( GTK_LABEL ( di - > ul_lb ) , str ) ;
2007-06-06 00:30:13 +00:00
2009-04-24 01:37:04 +00:00
/* ratio */
if ( n < = 0 )
str = none ;
else {
2009-04-24 12:05:53 +00:00
uint64_t up = 0 ;
uint64_t down = 0 ;
2009-04-24 01:37:04 +00:00
for ( i = 0 ; i < n ; + + i ) {
2009-04-24 12:05:53 +00:00
up + = stats [ i ] - > uploadedEver ;
down + = stats [ i ] - > downloadedEver ;
2009-04-24 01:37:04 +00:00
}
2009-04-24 15:24:43 +00:00
str = tr_strlratio ( buf , tr_getRatio ( up , down ) , sizeof ( buf ) ) ;
2009-04-24 01:37:04 +00:00
}
gtk_label_set_text ( GTK_LABEL ( di - > ratio_lb ) , str ) ;
2007-06-06 00:30:13 +00:00
2009-06-23 00:24:37 +00:00
/* hash_lb */
if ( n < = 0 )
2009-04-24 01:37:04 +00:00
str = none ;
2009-06-23 00:24:37 +00:00
else if ( n = = 1 )
2009-08-10 20:04:08 +00:00
str = infos [ 0 ] - > hashString ;
2009-06-23 00:24:37 +00:00
else
str = mixed ;
gtk_label_set_text ( GTK_LABEL ( di - > hash_lb ) , str ) ;
2008-09-23 19:11:04 +00:00
2009-04-24 01:37:04 +00:00
/* error */
if ( n < = 0 )
str = none ;
else {
const char * baseline = stats [ 0 ] - > errorString ;
for ( i = 1 ; i < n ; + + i )
if ( strcmp ( baseline , stats [ i ] - > errorString ) )
break ;
2009-04-24 15:24:43 +00:00
if ( i = = n )
str = baseline ;
else
str = mixed ;
2009-04-24 01:37:04 +00:00
}
if ( ! str | | ! * str )
str = none ;
gtk_label_set_text ( GTK_LABEL ( di - > error_lb ) , str ) ;
2008-09-23 19:11:04 +00:00
2009-04-24 01:37:04 +00:00
/* activity date */
if ( n < = 0 )
str = none ;
else {
2009-06-23 00:24:37 +00:00
time_t latest = 0 ;
for ( i = 0 ; i < n ; + + i )
if ( latest < stats [ i ] - > activityDate )
latest = stats [ i ] - > activityDate ;
if ( latest < = 0 )
str = none ;
else {
const int period = time ( NULL ) - latest ;
if ( period < 5 )
tr_strlcpy ( buf , _ ( " Active now " ) , sizeof ( buf ) ) ;
else {
char tbuf [ 128 ] ;
tr_strltime ( tbuf , period , sizeof ( tbuf ) ) ;
g_snprintf ( buf , sizeof ( buf ) , _ ( " %1$s ago " ) , tbuf ) ;
}
str = buf ;
}
2009-04-24 01:37:04 +00:00
}
gtk_label_set_text ( GTK_LABEL ( di - > last_activity_lb ) , str ) ;
2008-09-23 19:11:04 +00:00
2009-04-24 01:37:04 +00:00
g_free ( stats ) ;
2009-06-23 00:24:37 +00:00
g_free ( infos ) ;
2007-06-06 00:30:13 +00:00
}
static GtkWidget *
2009-06-23 00:24:37 +00:00
info_page_new ( struct DetailsImpl * di )
2007-06-06 00:30:13 +00:00
{
2009-06-23 00:24:37 +00:00
int row = 0 ;
GtkTextBuffer * b ;
GtkWidget * l , * w , * fr , * sw ;
GtkWidget * t = hig_workarea_create ( ) ;
2007-06-06 00:30:13 +00:00
2009-06-23 00:24:37 +00:00
hig_workarea_add_section_title ( t , & row , _ ( " Activity " ) ) ;
2007-09-26 01:55:04 +00:00
2009-06-23 00:24:37 +00:00
/* size */
l = di - > size_lb = gtk_label_new ( NULL ) ;
hig_workarea_add_row ( t , & row , _ ( " Torrent size: " ) , l , NULL ) ;
2007-06-06 00:30:13 +00:00
2009-06-23 00:24:37 +00:00
/* have */
l = di - > have_lb = gtk_label_new ( NULL ) ;
hig_workarea_add_row ( t , & row , _ ( " Have: " ) , l , NULL ) ;
2007-06-06 00:30:13 +00:00
2009-06-23 00:24:37 +00:00
/* downloaded */
l = di - > dl_lb = gtk_label_new ( NULL ) ;
hig_workarea_add_row ( t , & row , _ ( " Downloaded: " ) , l , NULL ) ;
2007-06-06 00:30:13 +00:00
2009-06-23 00:24:37 +00:00
/* uploaded */
l = di - > ul_lb = gtk_label_new ( NULL ) ;
hig_workarea_add_row ( t , & row , _ ( " Uploaded: " ) , l , NULL ) ;
2007-06-06 00:30:13 +00:00
2009-06-23 00:24:37 +00:00
/* ratio */
l = di - > ratio_lb = gtk_label_new ( NULL ) ;
hig_workarea_add_row ( t , & row , _ ( " Ratio: " ) , l , NULL ) ;
2007-06-06 00:30:13 +00:00
2009-06-23 00:24:37 +00:00
/* state */
l = di - > state_lb = gtk_label_new ( NULL ) ;
hig_workarea_add_row ( t , & row , _ ( " State: " ) , l , NULL ) ;
2007-06-06 00:30:13 +00:00
2009-06-23 00:24:37 +00:00
/* running for */
l = di - > date_started_lb = gtk_label_new ( NULL ) ;
hig_workarea_add_row ( t , & row , _ ( " Running time: " ) , l , NULL ) ;
2007-06-06 00:30:13 +00:00
2009-06-23 00:24:37 +00:00
/* last activity */
l = di - > last_activity_lb = gtk_label_new ( NULL ) ;
hig_workarea_add_row ( t , & row , _ ( " Last activity: " ) , l , NULL ) ;
2007-06-06 00:30:13 +00:00
2009-06-23 00:24:37 +00:00
/* error */
l = di - > error_lb = gtk_label_new ( NULL ) ;
hig_workarea_add_row ( t , & row , _ ( " Error: " ) , l , NULL ) ;
2007-06-06 00:30:13 +00:00
2009-03-05 17:18:36 +00:00
hig_workarea_add_section_divider ( t , & row ) ;
2009-04-24 01:37:04 +00:00
hig_workarea_add_section_title ( t , & row , _ ( " Details " ) ) ;
2009-06-23 00:24:37 +00:00
/* destination */
l = g_object_new ( GTK_TYPE_LABEL , " selectable " , TRUE ,
" ellipsize " , PANGO_ELLIPSIZE_END ,
NULL ) ;
hig_workarea_add_row ( t , & row , _ ( " Location: " ) , l , NULL ) ;
di - > destination_lb = l ;
2009-04-24 01:37:04 +00:00
/* hash */
l = g_object_new ( GTK_TYPE_LABEL , " selectable " , TRUE ,
" ellipsize " , PANGO_ELLIPSIZE_END ,
NULL ) ;
hig_workarea_add_row ( t , & row , _ ( " Hash: " ) , l , NULL ) ;
di - > hash_lb = l ;
/* privacy */
l = gtk_label_new ( NULL ) ;
hig_workarea_add_row ( t , & row , _ ( " Privacy: " ) , l , NULL ) ;
di - > privacy_lb = l ;
2009-06-23 00:24:37 +00:00
/* origins */
l = gtk_label_new ( NULL ) ;
hig_workarea_add_row ( t , & row , _ ( " Origin: " ) , l , NULL ) ;
di - > origin_lb = l ;
2009-04-24 01:37:04 +00:00
/* comment */
b = di - > comment_buffer = gtk_text_buffer_new ( NULL ) ;
w = gtk_text_view_new_with_buffer ( b ) ;
2009-06-23 00:24:37 +00:00
gtk_widget_set_size_request ( w , 350u , 50u ) ;
2009-04-24 01:37:04 +00:00
gtk_text_view_set_wrap_mode ( GTK_TEXT_VIEW ( w ) , GTK_WRAP_WORD ) ;
gtk_text_view_set_editable ( GTK_TEXT_VIEW ( w ) , FALSE ) ;
2009-05-19 18:36:28 +00:00
sw = gtk_scrolled_window_new ( NULL , NULL ) ;
gtk_scrolled_window_set_policy ( GTK_SCROLLED_WINDOW ( sw ) ,
GTK_POLICY_AUTOMATIC ,
GTK_POLICY_AUTOMATIC ) ;
gtk_container_add ( GTK_CONTAINER ( sw ) , w ) ;
2009-04-24 01:37:04 +00:00
fr = gtk_frame_new ( NULL ) ;
gtk_frame_set_shadow_type ( GTK_FRAME ( fr ) , GTK_SHADOW_IN ) ;
2009-05-19 18:36:28 +00:00
gtk_container_add ( GTK_CONTAINER ( fr ) , sw ) ;
2009-04-24 01:37:04 +00:00
w = hig_workarea_add_row ( t , & row , _ ( " Comment: " ) , fr , NULL ) ;
gtk_misc_set_alignment ( GTK_MISC ( w ) , 0.0f , 0.0f ) ;
hig_workarea_add_section_divider ( t , & row ) ;
2009-06-23 00:24:37 +00:00
hig_workarea_finish ( t , & row ) ;
return t ;
2009-04-24 01:37:04 +00:00
hig_workarea_finish ( t , & row ) ;
return t ;
2007-06-06 00:30:13 +00:00
}
2009-04-24 01:37:04 +00:00
/****
* * * * *
* * * * * PEERS TAB
* * * * *
* * * */
2009-02-13 18:23:56 +00:00
2009-04-24 01:37:04 +00:00
enum
2009-02-13 18:23:56 +00:00
{
2009-04-24 12:05:53 +00:00
WEBSEED_COL_KEY ,
WEBSEED_COL_WAS_UPDATED ,
2009-04-24 01:37:04 +00:00
WEBSEED_COL_URL ,
2009-05-02 16:16:23 +00:00
WEBSEED_COL_DOWNLOAD_RATE_DOUBLE ,
WEBSEED_COL_DOWNLOAD_RATE_STRING ,
2009-04-24 01:37:04 +00:00
N_WEBSEED_COLS
} ;
static const char *
getWebseedColumnNames ( int column )
{
switch ( column )
2009-02-13 18:23:56 +00:00
{
2009-04-24 01:37:04 +00:00
case WEBSEED_COL_URL : return _ ( " Webseeds " ) ;
2009-05-02 16:16:23 +00:00
case WEBSEED_COL_DOWNLOAD_RATE_DOUBLE :
case WEBSEED_COL_DOWNLOAD_RATE_STRING : return _ ( " Down " ) ;
2009-04-24 01:37:04 +00:00
default : return " " ;
2009-02-13 18:23:56 +00:00
}
}
2009-04-24 01:37:04 +00:00
static GtkListStore *
webseed_model_new ( void )
{
return gtk_list_store_new ( N_WEBSEED_COLS ,
2009-04-24 12:05:53 +00:00
G_TYPE_STRING , /* key */
G_TYPE_BOOLEAN , /* was-updated */
G_TYPE_STRING , /* url */
2009-05-02 16:16:23 +00:00
G_TYPE_DOUBLE , /* download rate double */
G_TYPE_STRING ) ; /* download rate string */
2009-04-24 01:37:04 +00:00
}
enum
{
2009-04-24 12:05:53 +00:00
PEER_COL_KEY ,
PEER_COL_WAS_UPDATED ,
2009-04-24 01:37:04 +00:00
PEER_COL_ADDRESS ,
PEER_COL_ADDRESS_COLLATED ,
PEER_COL_DOWNLOAD_RATE_DOUBLE ,
PEER_COL_DOWNLOAD_RATE_STRING ,
PEER_COL_UPLOAD_RATE_DOUBLE ,
PEER_COL_UPLOAD_RATE_STRING ,
PEER_COL_CLIENT ,
PEER_COL_PROGRESS ,
2009-04-26 14:38:46 +00:00
PEER_COL_ENCRYPTION_STOCK_ID ,
2009-04-24 01:37:04 +00:00
PEER_COL_STATUS ,
N_PEER_COLS
} ;
static const char *
getPeerColumnName ( int column )
{
switch ( column )
{
case PEER_COL_ADDRESS : return _ ( " Address " ) ;
case PEER_COL_DOWNLOAD_RATE_STRING :
case PEER_COL_DOWNLOAD_RATE_DOUBLE : return _ ( " Down " ) ;
case PEER_COL_UPLOAD_RATE_STRING :
case PEER_COL_UPLOAD_RATE_DOUBLE : return _ ( " Up " ) ;
case PEER_COL_CLIENT : return _ ( " Client " ) ;
case PEER_COL_PROGRESS : return _ ( " % " ) ;
case PEER_COL_STATUS : return _ ( " Status " ) ;
default : return " " ;
}
}
static GtkListStore *
peer_store_new ( void )
{
return gtk_list_store_new ( N_PEER_COLS ,
2009-04-24 12:05:53 +00:00
G_TYPE_STRING , /* key */
G_TYPE_BOOLEAN , /* was-updated */
2009-04-24 01:37:04 +00:00
G_TYPE_STRING , /* address */
G_TYPE_STRING , /* collated address */
G_TYPE_FLOAT , /* download speed float */
G_TYPE_STRING , /* download speed string */
G_TYPE_FLOAT , /* upload speed float */
G_TYPE_STRING , /* upload speed string */
G_TYPE_STRING , /* client */
G_TYPE_INT , /* progress [0..100] */
2009-04-26 14:38:46 +00:00
G_TYPE_STRING , /* encryption stock id */
2009-04-24 12:05:53 +00:00
G_TYPE_STRING ) ; /* flagString */
2009-04-24 01:37:04 +00:00
}
2007-06-06 00:30:13 +00:00
static void
2009-04-24 15:24:43 +00:00
initPeerRow ( GtkListStore * store ,
GtkTreeIter * iter ,
const char * key ,
const tr_peer_stat * peer )
2007-06-06 00:30:13 +00:00
{
2009-04-24 12:05:53 +00:00
int q [ 4 ] ;
char up_speed [ 128 ] ;
char down_speed [ 128 ] ;
2009-04-24 01:37:04 +00:00
char collated_name [ 128 ] ;
const char * client = peer - > client ;
if ( ! client | | ! strcmp ( client , " Unknown Client " ) )
client = " " ;
2009-04-24 12:05:53 +00:00
tr_strlspeed ( up_speed , peer - > rateToPeer , sizeof ( up_speed ) ) ;
tr_strlspeed ( down_speed , peer - > rateToClient , sizeof ( down_speed ) ) ;
if ( sscanf ( peer - > addr , " %d.%d.%d.%d " , q , q + 1 , q + 2 , q + 3 ) ! = 4 )
2009-04-24 01:37:04 +00:00
g_strlcpy ( collated_name , peer - > addr , sizeof ( collated_name ) ) ;
else
g_snprintf ( collated_name , sizeof ( collated_name ) ,
2009-04-24 12:05:53 +00:00
" %03d.%03d.%03d.%03d " , q [ 0 ] , q [ 1 ] , q [ 2 ] , q [ 3 ] ) ;
2009-04-24 01:37:04 +00:00
gtk_list_store_set ( store , iter ,
PEER_COL_ADDRESS , peer - > addr ,
PEER_COL_ADDRESS_COLLATED , collated_name ,
PEER_COL_CLIENT , client ,
2009-04-26 14:38:46 +00:00
PEER_COL_ENCRYPTION_STOCK_ID , peer - > isEncrypted ? " transmission-lock " : NULL ,
2009-04-24 01:37:04 +00:00
PEER_COL_KEY , key ,
- 1 ) ;
2007-06-06 00:30:13 +00:00
}
static void
2009-04-24 12:05:53 +00:00
refreshPeerRow ( GtkListStore * store ,
GtkTreeIter * iter ,
const tr_peer_stat * peer )
2007-06-06 00:30:13 +00:00
{
2009-04-24 12:05:53 +00:00
char up_speed [ 128 ] ;
char down_speed [ 128 ] ;
2009-04-24 01:37:04 +00:00
if ( peer - > rateToPeer > 0.01 )
2009-04-24 12:05:53 +00:00
tr_strlspeed ( up_speed , peer - > rateToPeer , sizeof ( up_speed ) ) ;
2009-04-24 01:37:04 +00:00
else
2009-04-24 12:05:53 +00:00
* up_speed = ' \0 ' ;
2009-04-24 01:37:04 +00:00
if ( peer - > rateToClient > 0.01 )
2009-04-24 12:05:53 +00:00
tr_strlspeed ( down_speed , peer - > rateToClient , sizeof ( down_speed ) ) ;
2009-04-24 01:37:04 +00:00
else
2009-04-24 12:05:53 +00:00
* down_speed = ' \0 ' ;
2009-04-24 01:37:04 +00:00
gtk_list_store_set ( store , iter ,
PEER_COL_PROGRESS , ( int ) ( 100.0 * peer - > progress ) ,
PEER_COL_DOWNLOAD_RATE_DOUBLE , peer - > rateToClient ,
2009-04-24 12:05:53 +00:00
PEER_COL_DOWNLOAD_RATE_STRING , down_speed ,
2009-04-24 01:37:04 +00:00
PEER_COL_UPLOAD_RATE_DOUBLE , peer - > rateToPeer ,
2009-04-24 12:05:53 +00:00
PEER_COL_UPLOAD_RATE_STRING , up_speed ,
2009-04-24 01:37:04 +00:00
PEER_COL_STATUS , peer - > flagStr ,
PEER_COL_WAS_UPDATED , TRUE ,
- 1 ) ;
2007-06-06 00:30:13 +00:00
}
2008-09-23 19:11:04 +00:00
2007-06-06 00:30:13 +00:00
static void
2009-04-24 01:37:04 +00:00
refreshPeerList ( struct DetailsImpl * di , tr_torrent * * torrents , int n )
2007-06-06 00:30:13 +00:00
{
2009-04-24 01:37:04 +00:00
int i ;
int * peerCount ;
GtkTreeIter iter ;
2009-04-24 12:05:53 +00:00
GHashTable * hash = di - > peer_hash ;
GtkListStore * store = di - > peer_store ;
GtkTreeModel * model = GTK_TREE_MODEL ( store ) ;
2009-04-24 01:37:04 +00:00
struct tr_peer_stat * * peers ;
/* step 1: get all the peers */
peers = g_new ( struct tr_peer_stat * , n ) ;
peerCount = g_new ( int , n ) ;
for ( i = 0 ; i < n ; + + i )
peers [ i ] = tr_torrentPeers ( torrents [ i ] , & peerCount [ i ] ) ;
/* step 2: mark all the peers in the list as not-updated */
2009-04-24 12:05:53 +00:00
model = GTK_TREE_MODEL ( store ) ;
2009-04-24 01:37:04 +00:00
if ( gtk_tree_model_get_iter_first ( model , & iter ) ) do
2009-04-24 12:05:53 +00:00
gtk_list_store_set ( store , & iter , PEER_COL_WAS_UPDATED , FALSE , - 1 ) ;
2009-04-24 01:37:04 +00:00
while ( gtk_tree_model_iter_next ( model , & iter ) ) ;
/* step 3: add any new peers */
for ( i = 0 ; i < n ; + + i ) {
int j ;
const tr_torrent * tor = torrents [ i ] ;
for ( j = 0 ; j < peerCount [ i ] ; + + j ) {
const tr_peer_stat * s = & peers [ i ] [ j ] ;
char key [ 128 ] ;
2009-04-24 15:24:43 +00:00
g_snprintf ( key , sizeof ( key ) , " %d.%s " , tr_torrentId ( tor ) , s - > addr ) ;
2009-04-24 12:05:53 +00:00
if ( g_hash_table_lookup ( hash , key ) = = NULL ) {
2009-04-24 15:24:43 +00:00
GtkTreePath * p ;
2009-04-24 12:05:53 +00:00
gtk_list_store_append ( store , & iter ) ;
2009-04-24 15:24:43 +00:00
initPeerRow ( store , & iter , key , s ) ;
p = gtk_tree_model_get_path ( model , & iter ) ;
2009-04-24 12:05:53 +00:00
g_hash_table_insert ( hash , g_strdup ( key ) ,
2009-04-24 15:24:43 +00:00
gtk_tree_row_reference_new ( model , p ) ) ;
gtk_tree_path_free ( p ) ;
2009-04-24 01:37:04 +00:00
}
}
}
/* step 4: update the peers */
for ( i = 0 ; i < n ; + + i ) {
int j ;
const tr_torrent * tor = torrents [ i ] ;
for ( j = 0 ; j < peerCount [ i ] ; + + j ) {
const tr_peer_stat * s = & peers [ i ] [ j ] ;
char key [ 128 ] ;
GtkTreeRowReference * ref ;
2009-04-24 15:24:43 +00:00
GtkTreePath * p ;
g_snprintf ( key , sizeof ( key ) , " %d.%s " , tr_torrentId ( tor ) , s - > addr ) ;
2009-04-24 12:05:53 +00:00
ref = g_hash_table_lookup ( hash , key ) ;
2009-04-24 15:24:43 +00:00
p = gtk_tree_row_reference_get_path ( ref ) ;
gtk_tree_model_get_iter ( model , & iter , p ) ;
2009-04-24 12:05:53 +00:00
refreshPeerRow ( store , & iter , s ) ;
2009-04-24 15:24:43 +00:00
gtk_tree_path_free ( p ) ;
2009-04-24 01:37:04 +00:00
}
}
/* step 5: remove peers that have disappeared */
2009-04-24 12:05:53 +00:00
model = GTK_TREE_MODEL ( store ) ;
2009-04-24 01:37:04 +00:00
if ( gtk_tree_model_get_iter_first ( model , & iter ) ) {
gboolean more = TRUE ;
while ( more ) {
2009-04-24 12:05:53 +00:00
gboolean b ;
gtk_tree_model_get ( model , & iter , PEER_COL_WAS_UPDATED , & b , - 1 ) ;
if ( b )
2009-04-24 01:37:04 +00:00
more = gtk_tree_model_iter_next ( model , & iter ) ;
else {
char * key ;
gtk_tree_model_get ( model , & iter , PEER_COL_KEY , & key , - 1 ) ;
2009-04-24 12:05:53 +00:00
g_hash_table_remove ( hash , key ) ;
more = gtk_list_store_remove ( store , & iter ) ;
2009-04-24 01:37:04 +00:00
g_free ( key ) ;
}
}
}
/* step 6: cleanup */
for ( i = 0 ; i < n ; + + i )
tr_torrentPeersFree ( peers [ i ] , peerCount [ i ] ) ;
tr_free ( peers ) ;
tr_free ( peerCount ) ;
2007-06-06 00:30:13 +00:00
}
2009-02-13 18:23:56 +00:00
static void
2009-04-24 01:37:04 +00:00
refreshWebseedList ( struct DetailsImpl * di , tr_torrent * * torrents , int n )
2009-02-13 18:23:56 +00:00
{
2009-04-24 01:37:04 +00:00
int i ;
int total = 0 ;
GtkTreeIter iter ;
GHashTable * hash = di - > webseed_hash ;
GtkListStore * store = di - > webseed_store ;
GtkTreeModel * model = GTK_TREE_MODEL ( store ) ;
2009-08-10 20:04:08 +00:00
2009-04-24 01:37:04 +00:00
/* step 1: mark all webseeds as not-updated */
if ( gtk_tree_model_get_iter_first ( model , & iter ) ) do
gtk_list_store_set ( store , & iter , WEBSEED_COL_WAS_UPDATED , FALSE , - 1 ) ;
while ( gtk_tree_model_iter_next ( model , & iter ) ) ;
/* step 2: add any new webseeds */
for ( i = 0 ; i < n ; + + i ) {
int j ;
const tr_torrent * tor = torrents [ i ] ;
const tr_info * inf = tr_torrentInfo ( tor ) ;
total + = inf - > webseedCount ;
for ( j = 0 ; j < inf - > webseedCount ; + + j ) {
char key [ 256 ] ;
const char * url = inf - > webseeds [ j ] ;
2009-04-24 15:24:43 +00:00
g_snprintf ( key , sizeof ( key ) , " %d.%s " , tr_torrentId ( tor ) , url ) ;
2009-04-24 01:37:04 +00:00
if ( g_hash_table_lookup ( hash , key ) = = NULL ) {
2009-04-24 15:24:43 +00:00
GtkTreePath * p ;
2009-04-24 01:37:04 +00:00
gtk_list_store_append ( store , & iter ) ;
2009-05-02 16:16:23 +00:00
gtk_list_store_set ( store , & iter , WEBSEED_COL_URL , url ,
WEBSEED_COL_KEY , key ,
- 1 ) ;
2009-04-24 15:24:43 +00:00
p = gtk_tree_model_get_path ( model , & iter ) ;
2009-04-24 12:05:53 +00:00
g_hash_table_insert ( hash , g_strdup ( key ) ,
2009-04-24 15:24:43 +00:00
gtk_tree_row_reference_new ( model , p ) ) ;
gtk_tree_path_free ( p ) ;
2009-04-24 01:37:04 +00:00
}
}
}
/* step 3: update the webseeds */
for ( i = 0 ; i < n ; + + i ) {
int j ;
const tr_torrent * tor = torrents [ i ] ;
const tr_info * inf = tr_torrentInfo ( tor ) ;
float * speeds = tr_torrentWebSpeeds ( tor ) ;
for ( j = 0 ; j < inf - > webseedCount ; + + j ) {
2009-05-02 16:16:23 +00:00
char buf [ 128 ] ;
2009-04-24 01:37:04 +00:00
char key [ 256 ] ;
const char * url = inf - > webseeds [ j ] ;
2009-04-24 15:24:43 +00:00
GtkTreePath * p ;
2009-04-24 01:37:04 +00:00
GtkTreeRowReference * ref ;
2009-04-24 15:24:43 +00:00
g_snprintf ( key , sizeof ( key ) , " %d.%s " , tr_torrentId ( tor ) , url ) ;
2009-04-24 01:37:04 +00:00
ref = g_hash_table_lookup ( hash , key ) ;
2009-04-24 15:24:43 +00:00
p = gtk_tree_row_reference_get_path ( ref ) ;
gtk_tree_model_get_iter ( model , & iter , p ) ;
2009-05-02 16:16:23 +00:00
if ( speeds [ j ] > 0.01 )
tr_strlspeed ( buf , speeds [ j ] , sizeof ( buf ) ) ;
else
* buf = ' \0 ' ;
gtk_list_store_set ( store , & iter , WEBSEED_COL_DOWNLOAD_RATE_DOUBLE , ( double ) speeds [ j ] ,
WEBSEED_COL_DOWNLOAD_RATE_STRING , buf ,
WEBSEED_COL_WAS_UPDATED , TRUE ,
- 1 ) ;
2009-04-24 15:24:43 +00:00
gtk_tree_path_free ( p ) ;
2009-04-24 01:37:04 +00:00
}
tr_free ( speeds ) ;
}
2009-02-13 18:23:56 +00:00
2009-04-24 01:37:04 +00:00
/* step 4: remove webseeds that have disappeared */
if ( gtk_tree_model_get_iter_first ( model , & iter ) ) {
gboolean more = TRUE ;
while ( more ) {
2009-04-24 12:05:53 +00:00
gboolean b ;
gtk_tree_model_get ( model , & iter , WEBSEED_COL_WAS_UPDATED , & b , - 1 ) ;
if ( b )
2009-04-24 01:37:04 +00:00
more = gtk_tree_model_iter_next ( model , & iter ) ;
else {
char * key ;
2009-04-24 12:05:53 +00:00
gtk_tree_model_get ( model , & iter , WEBSEED_COL_KEY , & key , - 1 ) ;
2009-04-25 16:19:07 +00:00
if ( key ! = NULL )
g_hash_table_remove ( hash , key ) ;
2009-04-24 01:37:04 +00:00
more = gtk_list_store_remove ( store , & iter ) ;
g_free ( key ) ;
}
}
}
2009-04-24 15:24:43 +00:00
/* most of the time there are no webseeds...
if that ' s the case , don ' t waste space showing an empty list */
2009-04-24 01:37:04 +00:00
if ( total > 0 )
gtk_widget_show ( di - > webseed_view ) ;
else
gtk_widget_hide ( di - > webseed_view ) ;
2009-02-13 18:23:56 +00:00
}
2009-04-24 01:37:04 +00:00
static void
refreshPeers ( struct DetailsImpl * di , tr_torrent * * torrents , int n )
{
refreshPeerList ( di , torrents , n ) ;
refreshWebseedList ( di , torrents , n ) ;
}
2009-04-24 12:05:53 +00:00
# if GTK_CHECK_VERSION( 2,12,0 )
static gboolean
onPeerViewQueryTooltip ( GtkWidget * widget ,
gint x ,
gint y ,
gboolean keyboard_tip ,
GtkTooltip * tooltip ,
gpointer user_data UNUSED )
{
gboolean show_tip = FALSE ;
GtkTreeModel * model ;
GtkTreeIter iter ;
if ( gtk_tree_view_get_tooltip_context ( GTK_TREE_VIEW ( widget ) ,
& x , & y , keyboard_tip ,
& model , NULL , & iter ) )
{
const char * pch ;
char * str = NULL ;
GString * gstr = g_string_new ( NULL ) ;
gtk_tree_model_get ( model , & iter , PEER_COL_STATUS , & str , - 1 ) ;
for ( pch = str ; pch & & * pch ; + + pch )
{
2009-04-24 15:24:43 +00:00
const char * s = NULL ;
2009-04-24 12:05:53 +00:00
switch ( * pch )
{
2009-04-24 15:24:43 +00:00
case ' O ' : s = _ ( " Optimistic unchoke " ) ; break ;
case ' D ' : s = _ ( " Downloading from this peer " ) ; break ;
case ' d ' : s = _ ( " We would download from this peer if they would let us " ) ; break ;
2009-08-10 20:04:08 +00:00
case ' U ' : s = _ ( " Uploading to peer " ) ; break ;
2009-04-24 15:24:43 +00:00
case ' u ' : s = _ ( " We would upload to this peer if they asked " ) ; break ;
case ' K ' : s = _ ( " Peer has unchoked us, but we're not interested " ) ; break ;
case ' ? ' : s = _ ( " We unchoked this peer, but they're not interested " ) ; break ;
2009-08-10 20:04:08 +00:00
case ' E ' : s = _ ( " Encrypted connection " ) ; break ;
2009-04-24 15:24:43 +00:00
case ' X ' : s = _ ( " Peer was discovered through Peer Exchange (PEX) " ) ; break ;
2009-05-19 18:38:26 +00:00
case ' H ' : s = _ ( " Peer was discovered through DHT " ) ; break ;
2009-04-24 15:24:43 +00:00
case ' I ' : s = _ ( " Peer is an incoming connection " ) ; break ;
2009-04-24 12:05:53 +00:00
}
2009-04-24 15:24:43 +00:00
if ( s )
g_string_append_printf ( gstr , " %c: %s \n " , * pch , s ) ;
2009-04-24 12:05:53 +00:00
}
if ( gstr - > len ) /* remove the last linefeed */
g_string_set_size ( gstr , gstr - > len - 1 ) ;
gtk_tooltip_set_text ( tooltip , gstr - > str ) ;
g_string_free ( gstr , TRUE ) ;
g_free ( str ) ;
show_tip = TRUE ;
}
return show_tip ;
}
# endif
2009-04-24 01:37:04 +00:00
static GtkWidget *
peer_page_new ( struct DetailsImpl * di )
{
guint i ;
2009-04-24 12:05:53 +00:00
const char * str ;
2009-04-24 01:37:04 +00:00
GtkListStore * store ;
2009-09-26 06:20:33 +00:00
GtkWidget * v , * w , * ret , * sw , * vbox ;
2009-04-24 01:37:04 +00:00
GtkWidget * webtree = NULL ;
2009-06-16 23:58:14 +00:00
GtkTreeModel * m ;
2009-04-24 12:05:53 +00:00
GtkTreeViewColumn * c ;
GtkCellRenderer * r ;
2009-04-26 14:38:46 +00:00
int view_columns [ ] = { PEER_COL_ENCRYPTION_STOCK_ID ,
2009-04-24 01:37:04 +00:00
PEER_COL_UPLOAD_RATE_STRING ,
PEER_COL_DOWNLOAD_RATE_STRING ,
PEER_COL_PROGRESS ,
PEER_COL_STATUS ,
PEER_COL_ADDRESS ,
PEER_COL_CLIENT } ;
2009-04-24 12:05:53 +00:00
/* webseeds */
2009-04-24 01:37:04 +00:00
2009-04-24 12:05:53 +00:00
store = di - > webseed_store = webseed_model_new ( ) ;
v = gtk_tree_view_new_with_model ( GTK_TREE_MODEL ( store ) ) ;
g_signal_connect ( v , " button-release-event " , G_CALLBACK ( on_tree_view_button_released ) , NULL ) ;
gtk_tree_view_set_rules_hint ( GTK_TREE_VIEW ( v ) , TRUE ) ;
2009-04-25 15:41:10 +00:00
g_object_unref ( store ) ;
2009-04-24 01:37:04 +00:00
2009-04-24 12:05:53 +00:00
str = getWebseedColumnNames ( WEBSEED_COL_URL ) ;
r = gtk_cell_renderer_text_new ( ) ;
g_object_set ( G_OBJECT ( r ) , " ellipsize " , PANGO_ELLIPSIZE_END , NULL ) ;
c = gtk_tree_view_column_new_with_attributes ( str , r , " text " , WEBSEED_COL_URL , NULL ) ;
g_object_set ( G_OBJECT ( c ) , " expand " , TRUE , NULL ) ;
gtk_tree_view_column_set_sort_column_id ( c , WEBSEED_COL_URL ) ;
gtk_tree_view_append_column ( GTK_TREE_VIEW ( v ) , c ) ;
2009-04-24 01:37:04 +00:00
2009-05-02 16:16:23 +00:00
str = getWebseedColumnNames ( WEBSEED_COL_DOWNLOAD_RATE_STRING ) ;
2009-04-24 12:05:53 +00:00
r = gtk_cell_renderer_text_new ( ) ;
2009-05-02 16:16:23 +00:00
c = gtk_tree_view_column_new_with_attributes ( str , r , " text " , WEBSEED_COL_DOWNLOAD_RATE_STRING , NULL ) ;
gtk_tree_view_column_set_sort_column_id ( c , WEBSEED_COL_DOWNLOAD_RATE_DOUBLE ) ;
2009-04-24 12:05:53 +00:00
gtk_tree_view_append_column ( GTK_TREE_VIEW ( v ) , c ) ;
w = gtk_scrolled_window_new ( NULL , NULL ) ;
gtk_scrolled_window_set_policy ( GTK_SCROLLED_WINDOW ( w ) ,
GTK_POLICY_AUTOMATIC ,
GTK_POLICY_AUTOMATIC ) ;
gtk_scrolled_window_set_shadow_type ( GTK_SCROLLED_WINDOW ( w ) ,
GTK_SHADOW_IN ) ;
gtk_container_add ( GTK_CONTAINER ( w ) , v ) ;
webtree = w ;
di - > webseed_view = w ;
/* peers */
2009-04-24 01:37:04 +00:00
store = di - > peer_store = peer_store_new ( ) ;
2009-06-16 23:58:14 +00:00
m = gtk_tree_model_sort_new_with_model ( GTK_TREE_MODEL ( store ) ) ;
gtk_tree_sortable_set_sort_column_id ( GTK_TREE_SORTABLE ( m ) ,
PEER_COL_PROGRESS ,
GTK_SORT_DESCENDING ) ;
2009-09-11 14:34:36 +00:00
# if GTK_CHECK_VERSION( 2,12,0 )
2009-04-24 01:37:04 +00:00
v = GTK_WIDGET ( g_object_new ( GTK_TYPE_TREE_VIEW ,
2009-06-16 23:58:14 +00:00
" model " , m ,
2009-04-24 01:37:04 +00:00
" rules-hint " , TRUE ,
" has-tooltip " , TRUE ,
NULL ) ) ;
2009-09-11 14:34:36 +00:00
# else
v = GTK_WIDGET ( g_object_new ( GTK_TYPE_TREE_VIEW ,
" model " , m ,
" rules-hint " , TRUE ,
NULL ) ) ;
# endif
2009-04-24 01:37:04 +00:00
# if GTK_CHECK_VERSION( 2,12,0 )
g_signal_connect ( v , " query-tooltip " ,
G_CALLBACK ( onPeerViewQueryTooltip ) , NULL ) ;
# endif
2009-04-25 15:41:10 +00:00
g_object_unref ( store ) ;
2009-04-24 01:37:04 +00:00
g_signal_connect ( v , " button-release-event " ,
G_CALLBACK ( on_tree_view_button_released ) , NULL ) ;
2009-04-24 12:05:53 +00:00
for ( i = 0 ; i < G_N_ELEMENTS ( view_columns ) ; + + i )
2009-04-24 01:37:04 +00:00
{
2009-04-24 15:24:43 +00:00
const int col = view_columns [ i ] ;
const char * t = getPeerColumnName ( col ) ;
int sort_col = col ;
2009-04-24 01:37:04 +00:00
switch ( col )
{
case PEER_COL_ADDRESS :
r = gtk_cell_renderer_text_new ( ) ;
c = gtk_tree_view_column_new_with_attributes ( t , r , " text " , col , NULL ) ;
sort_col = PEER_COL_ADDRESS_COLLATED ;
break ;
case PEER_COL_CLIENT :
r = gtk_cell_renderer_text_new ( ) ;
c = gtk_tree_view_column_new_with_attributes ( t , r , " text " , col , NULL ) ;
break ;
case PEER_COL_PROGRESS :
r = gtk_cell_renderer_progress_new ( ) ;
c = gtk_tree_view_column_new_with_attributes ( t , r , " value " , PEER_COL_PROGRESS , NULL ) ;
break ;
2009-04-26 14:38:46 +00:00
case PEER_COL_ENCRYPTION_STOCK_ID :
2009-04-24 01:37:04 +00:00
r = gtk_cell_renderer_pixbuf_new ( ) ;
2009-04-26 14:38:46 +00:00
g_object_set ( r , " xalign " , ( gfloat ) 0.0 ,
" yalign " , ( gfloat ) 0.5 ,
NULL ) ;
c = gtk_tree_view_column_new_with_attributes ( t , r , " stock-id " , PEER_COL_ENCRYPTION_STOCK_ID , NULL ) ;
2009-04-24 01:37:04 +00:00
gtk_tree_view_column_set_sizing ( c , GTK_TREE_VIEW_COLUMN_FIXED ) ;
gtk_tree_view_column_set_fixed_width ( c , 20 ) ;
break ;
case PEER_COL_DOWNLOAD_RATE_STRING :
r = gtk_cell_renderer_text_new ( ) ;
c = gtk_tree_view_column_new_with_attributes ( t , r , " text " , col , NULL ) ;
sort_col = PEER_COL_DOWNLOAD_RATE_DOUBLE ;
break ;
2008-09-23 19:11:04 +00:00
2009-04-24 01:37:04 +00:00
case PEER_COL_UPLOAD_RATE_STRING :
r = gtk_cell_renderer_text_new ( ) ;
c = gtk_tree_view_column_new_with_attributes ( t , r , " text " , col , NULL ) ;
sort_col = PEER_COL_UPLOAD_RATE_DOUBLE ;
break ;
2007-06-06 00:30:13 +00:00
2009-04-24 01:37:04 +00:00
case PEER_COL_STATUS :
r = gtk_cell_renderer_text_new ( ) ;
c = gtk_tree_view_column_new_with_attributes ( t , r , " text " , col , NULL ) ;
break ;
2009-02-13 18:23:56 +00:00
2009-04-24 01:37:04 +00:00
default :
abort ( ) ;
}
2009-02-13 18:23:56 +00:00
2009-04-24 01:37:04 +00:00
gtk_tree_view_column_set_resizable ( c , FALSE ) ;
gtk_tree_view_column_set_sort_column_id ( c , sort_col ) ;
gtk_tree_view_append_column ( GTK_TREE_VIEW ( v ) , c ) ;
}
2009-02-13 18:23:56 +00:00
2009-04-24 01:37:04 +00:00
/* the 'expander' column has a 10-pixel margin on the left
that doesn ' t look quite correct in any of these columns . . .
so create a non - visible column and assign it as the
' expander column . */
2009-02-13 18:23:56 +00:00
{
2009-04-24 01:37:04 +00:00
GtkTreeViewColumn * c = gtk_tree_view_column_new ( ) ;
gtk_tree_view_column_set_visible ( c , FALSE ) ;
gtk_tree_view_append_column ( GTK_TREE_VIEW ( v ) , c ) ;
gtk_tree_view_set_expander_column ( GTK_TREE_VIEW ( v ) , c ) ;
2009-02-13 18:23:56 +00:00
}
2009-04-24 01:37:04 +00:00
w = sw = gtk_scrolled_window_new ( NULL , NULL ) ;
gtk_scrolled_window_set_policy ( GTK_SCROLLED_WINDOW ( w ) ,
GTK_POLICY_AUTOMATIC ,
GTK_POLICY_AUTOMATIC ) ;
gtk_scrolled_window_set_shadow_type ( GTK_SCROLLED_WINDOW ( w ) ,
GTK_SHADOW_IN ) ;
gtk_container_add ( GTK_CONTAINER ( w ) , v ) ;
2009-04-19 17:00:28 +00:00
2009-04-24 01:37:04 +00:00
vbox = gtk_vbox_new ( FALSE , GUI_PAD ) ;
gtk_container_set_border_width ( GTK_CONTAINER ( vbox ) , GUI_PAD_BIG ) ;
2009-04-19 17:00:28 +00:00
2009-04-24 15:24:43 +00:00
v = gtk_vpaned_new ( ) ;
gtk_paned_pack1 ( GTK_PANED ( v ) , webtree , FALSE , TRUE ) ;
gtk_paned_pack2 ( GTK_PANED ( v ) , sw , TRUE , TRUE ) ;
gtk_box_pack_start ( GTK_BOX ( vbox ) , v , TRUE , TRUE , 0 ) ;
2009-04-19 17:00:28 +00:00
2009-04-24 01:37:04 +00:00
/* ip-to-GtkTreeRowReference */
di - > peer_hash = g_hash_table_new_full ( g_str_hash ,
g_str_equal ,
( GDestroyNotify ) g_free ,
( GDestroyNotify ) gtk_tree_row_reference_free ) ;
/* url-to-GtkTreeRowReference */
di - > webseed_hash = g_hash_table_new_full ( g_str_hash ,
g_str_equal ,
( GDestroyNotify ) g_free ,
( GDestroyNotify ) gtk_tree_row_reference_free ) ;
ret = vbox ;
return ret ;
2009-04-19 17:00:28 +00:00
}
2009-04-24 01:37:04 +00:00
/****
* * * * * TRACKER
* * * */
2009-09-25 21:05:59 +00:00
/* if it's been longer than a minute, don't bother showing the seconds */
2009-04-24 01:37:04 +00:00
static void
2009-09-25 21:05:59 +00:00
tr_strltime_rounded ( char * buf , time_t t , size_t buflen )
2009-04-24 01:37:04 +00:00
{
2009-09-25 21:05:59 +00:00
if ( t > 60 ) t - = ( t % 60 ) ;
tr_strltime ( buf , t , buflen ) ;
}
2009-03-04 19:52:57 +00:00
2009-09-25 21:05:59 +00:00
static char *
buildTrackerSummary ( const char * key , const tr_tracker_stat * st , gboolean showScrape )
{
char * str ;
char timebuf [ 256 ] ;
const time_t now = time ( NULL ) ;
GString * gstr = g_string_new ( NULL ) ;
const char * err_markup_begin = " <span color= \" red \" > " ;
const char * err_markup_end = " </span> " ;
const char * success_markup_begin = " <span color= \" #008B00 \" > " ;
const char * success_markup_end = " </span> " ;
2009-03-04 19:52:57 +00:00
2009-09-25 21:05:59 +00:00
/* hostname */
{
const char * host = st - > host ;
const char * pch = strstr ( host , " :// " ) ;
if ( pch )
host = pch + 3 ;
g_string_append ( gstr , st - > isActive ? " <b> " : " <i> " ) ;
if ( key )
str = g_markup_printf_escaped ( " %s - %s " , host , key ) ;
2009-04-24 15:24:43 +00:00
else
2009-09-25 21:05:59 +00:00
str = g_markup_printf_escaped ( " %s " , host ) ;
g_string_append ( gstr , str ) ;
g_free ( str ) ;
g_string_append ( gstr , st - > isActive ? " </b> " : " </i> " ) ;
2009-04-24 01:37:04 +00:00
}
2007-06-06 00:30:13 +00:00
2009-09-25 21:05:59 +00:00
if ( st - > isActive & & st - > hasAnnounced ) {
g_string_append_c ( gstr , ' \n ' ) ;
tr_strltime_rounded ( timebuf , now - st - > lastAnnounceTime , sizeof ( timebuf ) ) ;
if ( st - > lastAnnounceSucceeded )
g_string_append_printf ( gstr , _ ( " Got a list of %s%'d peers%s %s ago " ) ,
success_markup_begin , st - > lastAnnouncePeerCount , success_markup_end ,
timebuf ) ;
2009-04-24 01:37:04 +00:00
else
2009-09-25 21:05:59 +00:00
g_string_append_printf ( gstr , _ ( " Got an error %s \" %s \" %s %s ago " ) ,
err_markup_begin , st - > lastAnnounceResult , err_markup_end ,
timebuf ) ;
2009-04-24 01:37:04 +00:00
}
2009-02-13 18:23:56 +00:00
2009-09-25 21:05:59 +00:00
if ( st - > isActive & & ( st - > isAnnouncing | | st - > willAnnounce ) ) {
g_string_append_c ( gstr , ' \n ' ) ;
if ( ! st - > isAnnouncing ) {
tr_strltime_rounded ( timebuf , st - > nextAnnounceTime - now , sizeof ( timebuf ) ) ;
g_string_append_printf ( gstr , _ ( " Asking for more peers in %s " ) , timebuf ) ;
} else {
tr_strltime_rounded ( timebuf , now - st - > lastAnnounceStartTime , sizeof ( timebuf ) ) ;
g_string_append_printf ( gstr , _ ( " Asking for more peers now... <small>%s</small> " ) , timebuf ) ;
}
}
2009-02-13 18:23:56 +00:00
2009-09-25 21:05:59 +00:00
if ( ! st - > hasAnnounced & & ! st - > isAnnouncing & & ! st - > willAnnounce ) {
g_string_append_c ( gstr , ' \n ' ) ;
g_string_append ( gstr , _ ( " No updates scheduled " ) ) ;
2009-04-24 01:37:04 +00:00
}
2009-02-13 18:23:56 +00:00
2009-09-25 21:05:59 +00:00
if ( st - > isActive & & showScrape )
{
if ( st - > hasScraped ) {
g_string_append_c ( gstr , ' \n ' ) ;
tr_strltime_rounded ( timebuf , now - st - > lastScrapeTime , sizeof ( timebuf ) ) ;
if ( st - > lastScrapeSucceeded )
g_string_append_printf ( gstr , _ ( " Tracker had %s%'d seeders and %'d leechers%s %s ago " ) ,
success_markup_begin , st - > seederCount , st - > leecherCount , success_markup_end ,
timebuf ) ;
else
g_string_append_printf ( gstr , _ ( " Got a scrape error \" %s%s%s \" %s ago " ) , err_markup_begin , st - > lastScrapeResult , err_markup_end , timebuf ) ;
}
2007-06-06 00:30:13 +00:00
2009-09-25 21:05:59 +00:00
if ( st - > isScraping | | st - > willScrape ) {
g_string_append_c ( gstr , ' \n ' ) ;
if ( ! st - > isScraping ) {
tr_strltime_rounded ( timebuf , st - > nextScrapeTime - now , sizeof ( timebuf ) ) ;
g_string_append_printf ( gstr , _ ( " Asking for peer counts in %s " ) , timebuf ) ;
} else {
tr_strltime_rounded ( timebuf , now - st - > lastScrapeStartTime , sizeof ( timebuf ) ) ;
g_string_append_printf ( gstr , _ ( " Asking for peer counts now... <small>%s</small> " ) , timebuf ) ;
}
}
2009-04-24 01:37:04 +00:00
}
2009-09-25 21:05:59 +00:00
return g_string_free ( gstr , FALSE ) ;
}
2007-12-22 00:06:38 +00:00
2009-09-25 21:05:59 +00:00
enum
{
TRACKER_COL_TORRENT_ID ,
TRACKER_COL_TRACKER_INDEX ,
TRACKER_COL_TEXT ,
TRACKER_COL_ACTIVE ,
TRACKER_COL_TORRENT_NAME ,
TRACKER_COL_TRACKER_NAME ,
TRACKER_N_COLS
} ;
2007-06-06 00:30:13 +00:00
2009-09-25 21:05:59 +00:00
static gboolean
trackerVisibleFunc ( GtkTreeModel * model , GtkTreeIter * iter , gpointer data )
{
gboolean active ;
struct DetailsImpl * di = data ;
2008-02-21 07:29:39 +00:00
2009-09-25 21:05:59 +00:00
/* show all */
if ( gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON ( di - > all_check ) ) )
return TRUE ;
2008-02-21 07:29:39 +00:00
2009-09-25 21:05:59 +00:00
/* only showing the active ones... */
gtk_tree_model_get ( model , iter , TRACKER_COL_ACTIVE , & active , - 1 ) ;
return active ;
}
//ccc
static void
refreshTracker ( struct DetailsImpl * di , tr_torrent * * torrents , int n )
{
int i ;
int * statCount ;
tr_tracker_stat * * stats ;
GtkTreeIter iter ;
GtkListStore * store = di - > trackers ;
GtkTreeModel * model ;
const gboolean showScrape = gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON ( di - > scrape_check ) ) ;
statCount = g_new0 ( int , n ) ;
stats = g_new0 ( tr_tracker_stat * , n ) ;
for ( i = 0 ; i < n ; + + i )
stats [ i ] = tr_torrentTrackers ( torrents [ i ] , & statCount [ i ] ) ;
/* build the store if we don't already have it */
if ( store = = NULL )
{
GtkTreeModel * filter ;
store = gtk_list_store_new ( TRACKER_N_COLS , G_TYPE_INT ,
G_TYPE_INT ,
G_TYPE_STRING ,
G_TYPE_BOOLEAN ,
G_TYPE_STRING ,
G_TYPE_STRING ) ;
filter = gtk_tree_model_filter_new ( GTK_TREE_MODEL ( store ) , NULL ) ;
gtk_tree_model_filter_set_visible_func ( GTK_TREE_MODEL_FILTER ( filter ) ,
trackerVisibleFunc , di , NULL ) ;
di - > trackers = store ;
di - > trackers_filtered = filter ;
gtk_tree_view_set_model ( GTK_TREE_VIEW ( di - > tracker_view ) , filter ) ;
2009-04-24 01:37:04 +00:00
}
2008-02-21 07:29:39 +00:00
2009-09-26 00:48:07 +00:00
if ( ( di - > tracker_buffer = = NULL ) & & ( n = = 1 ) )
{
int tier = 0 ;
GString * gstr = g_string_new ( NULL ) ;
const tr_info * inf = tr_torrentInfo ( torrents [ 0 ] ) ;
for ( i = 0 ; i < inf - > trackerCount ; + + i ) {
const tr_tracker_info * t = & inf - > trackers [ i ] ;
g_string_append_printf ( gstr , " %s \n " , t - > announce ) ;
if ( tier ! = t - > tier ) {
tier = t - > tier ;
g_string_append_c ( gstr , ' \n ' ) ;
}
}
if ( gstr - > len > 0 )
g_string_truncate ( gstr , gstr - > len - 1 ) ;
di - > tracker_buffer = gtk_text_buffer_new ( NULL ) ;
gtk_text_buffer_set_text ( di - > tracker_buffer , gstr - > str , - 1 ) ;
g_string_free ( gstr , TRUE ) ;
}
2009-09-25 21:05:59 +00:00
/* add any missing rows (FIXME: doesn't handle edited trackers) */
model = GTK_TREE_MODEL ( store ) ;
if ( n & & ! gtk_tree_model_get_iter_first ( model , & iter ) )
{
for ( i = 0 ; i < n ; + + i )
{
int j ;
const tr_torrent * tor = torrents [ i ] ;
const int torrentId = tr_torrentId ( tor ) ;
const tr_info * inf = tr_torrentInfo ( tor ) ;
for ( j = 0 ; j < statCount [ i ] ; + + j )
gtk_list_store_insert_with_values ( store , & iter , - 1 ,
TRACKER_COL_TORRENT_ID , torrentId ,
TRACKER_COL_TRACKER_INDEX , j ,
TRACKER_COL_TORRENT_NAME , inf - > name ,
TRACKER_COL_TRACKER_NAME , stats [ i ] [ j ] . host ,
- 1 ) ;
}
}
2008-06-01 01:40:32 +00:00
2009-09-25 21:05:59 +00:00
/* update the store */
if ( gtk_tree_model_get_iter_first ( model , & iter ) ) do
{
int torrentId ;
int trackerIndex ;
gtk_tree_model_get ( model , & iter , TRACKER_COL_TORRENT_ID , & torrentId ,
TRACKER_COL_TRACKER_INDEX , & trackerIndex ,
- 1 ) ;
for ( i = 0 ; i < n ; + + i )
if ( tr_torrentId ( torrents [ i ] ) = = torrentId )
2009-04-24 01:37:04 +00:00
break ;
2008-06-01 01:40:32 +00:00
2009-09-25 21:05:59 +00:00
if ( i < n & & trackerIndex < statCount [ i ] )
{
const tr_tracker_stat * st = & stats [ i ] [ trackerIndex ] ;
const char * key = n > 1 ? tr_torrentInfo ( torrents [ i ] ) - > name : NULL ;
char * text = buildTrackerSummary ( key , st , showScrape ) ;
gtk_list_store_set ( store , & iter , TRACKER_COL_TEXT , text ,
TRACKER_COL_ACTIVE , st - > isActive ,
- 1 ) ;
g_free ( text ) ;
}
}
while ( gtk_tree_model_iter_next ( model , & iter ) ) ;
2008-02-21 07:29:39 +00:00
2009-09-25 21:05:59 +00:00
/* cleanup */
for ( i = 0 ; i < n ; + + i )
tr_torrentTrackersFree ( stats [ i ] , statCount [ i ] ) ;
2009-04-24 12:05:53 +00:00
g_free ( stats ) ;
2009-09-25 21:05:59 +00:00
g_free ( statCount ) ;
2009-04-24 01:37:04 +00:00
}
2008-02-21 07:29:39 +00:00
2009-09-25 21:05:59 +00:00
static void refresh ( struct DetailsImpl * di ) ;
2008-02-21 07:29:39 +00:00
2009-09-25 21:05:59 +00:00
static void
onScrapeToggled ( GtkToggleButton * button , struct DetailsImpl * di )
{
const char * key = PREF_KEY_SHOW_MORE_TRACKER_INFO ;
const gboolean value = gtk_toggle_button_get_active ( button ) ;
tr_core_set_pref_bool ( di - > core , key , value ) ;
refresh ( di ) ;
}
2008-02-21 07:29:39 +00:00
2009-09-25 21:05:59 +00:00
static void
onBackupToggled ( GtkToggleButton * button , struct DetailsImpl * di )
{
const char * key = PREF_KEY_SHOW_BACKUP_TRACKERS ;
const gboolean value = gtk_toggle_button_get_active ( button ) ;
tr_core_set_pref_bool ( di - > core , key , value ) ;
refresh ( di ) ;
}
2008-02-21 07:29:39 +00:00
2009-09-25 21:05:59 +00:00
static void
2009-09-26 00:48:07 +00:00
onEditTrackersResponse ( GtkDialog * dialog , int response , gpointer data )
{
struct DetailsImpl * di = data ;
if ( response = = GTK_RESPONSE_ACCEPT )
{
int i , n ;
int tier ;
GtkTextIter start , end ;
char * tracker_text ;
char * * tracker_strings ;
tr_tracker_info * trackers ;
/* build the array of trackers */
gtk_text_buffer_get_bounds ( di - > tracker_buffer , & start , & end ) ;
tracker_text = gtk_text_buffer_get_text ( di - > tracker_buffer , & start , & end , FALSE ) ;
tracker_strings = g_strsplit ( tracker_text , " \n " , 0 ) ;
for ( i = 0 ; tracker_strings [ i ] ; )
+ + i ;
trackers = g_new0 ( tr_tracker_info , i ) ;
for ( i = n = tier = 0 ; tracker_strings [ i ] ; + + i ) {
const char * str = tracker_strings [ i ] ;
if ( ! * str )
+ + tier ;
else {
trackers [ n ] . tier = tier ;
trackers [ n ] . announce = tracker_strings [ i ] ;
+ + n ;
}
}
/* update the torrent */
tr_torrentSetAnnounceList ( NULL , trackers , n ) ;
di - > trackers = NULL ;
di - > tracker_buffer = NULL ;
/* cleanup */
g_free ( trackers ) ;
g_strfreev ( tracker_strings ) ;
g_free ( tracker_text ) ;
}
gtk_widget_destroy ( GTK_WIDGET ( dialog ) ) ;
}
static void
onEditTrackers ( GtkButton * button , gpointer data )
2009-09-25 21:05:59 +00:00
{
2009-09-26 00:48:07 +00:00
GtkWidget * w , * d , * sw , * fr ;
GtkWindow * win = GTK_WINDOW ( gtk_widget_get_toplevel ( GTK_WIDGET ( button ) ) ) ;
2009-09-25 21:05:59 +00:00
struct DetailsImpl * di = data ;
2009-09-26 00:48:07 +00:00
d = gtk_dialog_new_with_buttons ( _ ( " Edit Trackers " ) , win ,
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT ,
GTK_STOCK_CANCEL , GTK_RESPONSE_CANCEL ,
GTK_STOCK_SAVE , GTK_RESPONSE_ACCEPT ,
NULL ) ;
g_signal_connect ( d , " response " ,
G_CALLBACK ( onEditTrackersResponse ) , data ) ;
w = gtk_text_view_new_with_buffer ( di - > tracker_buffer ) ;
gtr_widget_set_tooltip_text ( w , _ ( " Transmission supports HTTP and HTTPS (SSL) trackers. Torrents with multiple trackers are also supported -- trackers from the same server (with similar URLs) must be grouped together and those from different servers separated by a blank line. " ) ) ;
gtk_widget_set_size_request ( w , 400 , 300 ) ;
sw = gtk_scrolled_window_new ( NULL , NULL ) ;
gtk_scrolled_window_set_policy ( GTK_SCROLLED_WINDOW ( sw ) ,
GTK_POLICY_AUTOMATIC ,
GTK_POLICY_AUTOMATIC ) ;
gtk_container_add ( GTK_CONTAINER ( sw ) , w ) ;
fr = gtk_frame_new ( NULL ) ;
gtk_frame_set_shadow_type ( GTK_FRAME ( fr ) , GTK_SHADOW_IN ) ;
gtk_container_add ( GTK_CONTAINER ( fr ) , sw ) ;
gtk_box_pack_start ( GTK_BOX ( GTK_DIALOG ( d ) - > vbox ) , fr , TRUE , TRUE , GUI_PAD_SMALL ) ;
gtk_widget_show_all ( d ) ;
2009-09-25 21:05:59 +00:00
}
2008-02-21 07:29:39 +00:00
2009-09-25 21:05:59 +00:00
static GtkWidget *
tracker_page_new ( struct DetailsImpl * di )
{
gboolean b ;
GtkWidget * vbox , * sw , * w , * v , * hbox ;
GtkCellRenderer * r ;
GtkTreeViewColumn * c ;
2008-02-21 07:29:39 +00:00
2009-09-25 21:05:59 +00:00
vbox = gtk_vbox_new ( FALSE , GUI_PAD ) ;
gtk_container_set_border_width ( GTK_CONTAINER ( vbox ) , GUI_PAD_BIG ) ;
2008-03-08 02:00:47 +00:00
2009-09-25 21:05:59 +00:00
v = di - > tracker_view = gtk_tree_view_new ( ) ;
2009-09-26 00:48:07 +00:00
g_signal_connect ( v , " button-press-event " ,
G_CALLBACK ( on_tree_view_button_pressed ) , NULL ) ;
g_signal_connect ( v , " button-release-event " ,
G_CALLBACK ( on_tree_view_button_released ) , NULL ) ;
2009-09-25 21:05:59 +00:00
gtk_tree_view_set_rules_hint ( GTK_TREE_VIEW ( v ) , TRUE ) ;
r = gtk_cell_renderer_text_new ( ) ;
g_object_set ( r , " ellipsize " , PANGO_ELLIPSIZE_END , NULL ) ;
c = gtk_tree_view_column_new_with_attributes ( _ ( " Trackers " ) , r , " markup " , TRACKER_COL_TEXT , NULL ) ;
gtk_tree_view_append_column ( GTK_TREE_VIEW ( v ) , c ) ;
g_object_set ( G_OBJECT ( r ) , " ypad " , ( GUI_PAD + GUI_PAD_BIG ) / 2 ,
" xpad " , ( GUI_PAD + GUI_PAD_BIG ) / 2 ,
NULL ) ;
sw = gtk_scrolled_window_new ( NULL , NULL ) ;
gtk_scrolled_window_set_policy ( GTK_SCROLLED_WINDOW ( sw ) ,
GTK_POLICY_AUTOMATIC ,
GTK_POLICY_AUTOMATIC ) ;
gtk_container_add ( GTK_CONTAINER ( sw ) , v ) ;
w = gtk_frame_new ( NULL ) ;
gtk_frame_set_shadow_type ( GTK_FRAME ( w ) , GTK_SHADOW_IN ) ;
gtk_container_add ( GTK_CONTAINER ( w ) , sw ) ;
gtk_box_pack_start ( GTK_BOX ( vbox ) , w , TRUE , TRUE , 0 ) ;
2008-02-21 07:29:39 +00:00
2009-09-25 21:05:59 +00:00
hbox = gtk_hbox_new ( FALSE , 0 ) ;
2008-02-21 07:29:39 +00:00
2009-09-25 21:05:59 +00:00
w = gtk_check_button_new_with_mnemonic ( _ ( " Show _more details " ) ) ;
di - > scrape_check = w ;
b = pref_flag_get ( PREF_KEY_SHOW_MORE_TRACKER_INFO ) ;
gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON ( w ) , b ) ;
g_signal_connect ( w , " toggled " , G_CALLBACK ( onScrapeToggled ) , di ) ;
gtk_box_pack_start ( GTK_BOX ( hbox ) , w , FALSE , FALSE , 0 ) ;
2008-02-21 07:29:39 +00:00
2009-09-25 21:05:59 +00:00
w = gtk_button_new_from_stock ( GTK_STOCK_EDIT ) ;
g_signal_connect ( w , " clicked " , G_CALLBACK ( onEditTrackers ) , di ) ;
gtk_box_pack_end ( GTK_BOX ( hbox ) , w , FALSE , FALSE , 0 ) ;
2008-02-21 07:29:39 +00:00
2009-09-25 21:05:59 +00:00
gtk_box_pack_start ( GTK_BOX ( vbox ) , hbox , FALSE , FALSE , 0 ) ;
2008-02-21 07:29:39 +00:00
2009-09-25 21:05:59 +00:00
w = gtk_check_button_new_with_mnemonic ( _ ( " Show _backup trackers " ) ) ;
di - > all_check = w ;
b = pref_flag_get ( PREF_KEY_SHOW_BACKUP_TRACKERS ) ;
gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON ( w ) , b ) ;
g_signal_connect ( w , " toggled " , G_CALLBACK ( onBackupToggled ) , di ) ;
gtk_box_pack_start ( GTK_BOX ( vbox ) , w , FALSE , FALSE , 0 ) ;
return vbox ;
2008-02-21 07:29:39 +00:00
}
2007-06-06 00:30:13 +00:00
/****
* * * * * DIALOG
* * * */
static void
2009-04-24 01:37:04 +00:00
refresh ( struct DetailsImpl * di )
2007-06-06 00:30:13 +00:00
{
2009-04-24 01:37:04 +00:00
int n ;
tr_torrent * * torrents = getTorrents ( di , & n ) ;
refreshInfo ( di , torrents , n ) ;
refreshPeers ( di , torrents , n ) ;
refreshTracker ( di , torrents , n ) ;
refreshOptions ( di , torrents , n ) ;
g_free ( torrents ) ;
2007-06-06 00:30:13 +00:00
}
2009-04-24 01:37:04 +00:00
static gboolean
periodic_refresh ( gpointer data )
2007-06-06 00:30:13 +00:00
{
2009-04-24 01:37:04 +00:00
refresh ( data ) ;
return TRUE ;
2007-06-06 00:30:13 +00:00
}
static void
2009-04-24 12:05:53 +00:00
details_free ( gpointer gdata )
2007-06-06 00:30:13 +00:00
{
2009-04-24 01:37:04 +00:00
struct DetailsImpl * data = gdata ;
g_source_remove ( data - > periodic_refresh_tag ) ;
2009-06-15 21:01:20 +00:00
g_hash_table_destroy ( data - > webseed_hash ) ;
2009-09-26 23:46:30 +00:00
g_hash_table_destroy ( data - > peer_hash ) ;
2009-04-24 01:37:04 +00:00
g_slist_free ( data - > ids ) ;
g_free ( data ) ;
2007-06-06 00:30:13 +00:00
}
2009-04-24 01:37:04 +00:00
static void
response_cb ( GtkDialog * dialog , int a UNUSED , gpointer b UNUSED )
2007-06-06 00:30:13 +00:00
{
2009-04-24 01:37:04 +00:00
GtkWidget * w = GTK_WIDGET ( dialog ) ;
torrent_inspector_set_torrents ( w , NULL ) ;
2009-06-10 17:01:33 +00:00
gtk_widget_destroy ( w ) ;
2007-06-06 00:30:13 +00:00
}
GtkWidget *
2009-04-24 01:37:04 +00:00
torrent_inspector_new ( GtkWindow * parent , TrCore * core )
2007-06-06 00:30:13 +00:00
{
2009-04-24 01:37:04 +00:00
GtkWidget * d , * n , * w , * l ;
2009-04-24 15:24:43 +00:00
struct DetailsImpl * di = g_new0 ( struct DetailsImpl , 1 ) ;
2008-09-23 19:11:04 +00:00
/* create the dialog */
2009-04-24 15:24:43 +00:00
di - > core = core ;
2009-04-24 12:05:53 +00:00
d = gtk_dialog_new_with_buttons ( NULL , parent , 0 ,
2009-03-05 17:18:36 +00:00
GTK_STOCK_CLOSE , GTK_RESPONSE_CLOSE ,
NULL ) ;
gtk_window_set_role ( GTK_WINDOW ( d ) , " tr-info " ) ;
2009-04-24 01:37:04 +00:00
g_signal_connect ( d , " response " , G_CALLBACK ( response_cb ) , NULL ) ;
2008-09-23 19:11:04 +00:00
gtk_dialog_set_has_separator ( GTK_DIALOG ( d ) , FALSE ) ;
gtk_container_set_border_width ( GTK_CONTAINER ( d ) , GUI_PAD ) ;
2009-04-24 15:24:43 +00:00
g_object_set_data_full ( G_OBJECT ( d ) , DETAILS_KEY , di , details_free ) ;
2008-09-23 19:11:04 +00:00
2009-03-05 17:18:36 +00:00
n = gtk_notebook_new ( ) ;
gtk_container_set_border_width ( GTK_CONTAINER ( n ) , GUI_PAD ) ;
2008-09-23 19:11:04 +00:00
2009-06-23 00:24:37 +00:00
w = info_page_new ( di ) ;
l = gtk_label_new ( _ ( " Information " ) ) ;
2009-04-24 01:37:04 +00:00
gtk_notebook_append_page ( GTK_NOTEBOOK ( n ) , w , l ) ;
2008-09-23 19:11:04 +00:00
2009-04-24 15:24:43 +00:00
w = peer_page_new ( di ) ;
2009-04-24 01:37:04 +00:00
l = gtk_label_new ( _ ( " Peers " ) ) ;
gtk_notebook_append_page ( GTK_NOTEBOOK ( n ) , w , l ) ;
2008-09-23 19:11:04 +00:00
2009-04-24 15:24:43 +00:00
w = tracker_page_new ( di ) ;
2009-04-24 01:37:04 +00:00
l = gtk_label_new ( _ ( " Tracker " ) ) ;
gtk_notebook_append_page ( GTK_NOTEBOOK ( n ) , w , l ) ;
2008-09-23 19:11:04 +00:00
2009-04-24 15:24:43 +00:00
w = file_list_new ( core , 0 ) ;
2008-09-23 19:11:04 +00:00
gtk_container_set_border_width ( GTK_CONTAINER ( w ) , GUI_PAD_BIG ) ;
2009-04-24 01:37:04 +00:00
l = gtk_label_new ( _ ( " Files " ) ) ;
gtk_notebook_append_page ( GTK_NOTEBOOK ( n ) , w , l ) ;
2009-04-24 15:24:43 +00:00
di - > file_list = w ;
2008-09-23 19:11:04 +00:00
2009-04-24 15:24:43 +00:00
w = options_page_new ( di ) ;
2009-04-24 01:37:04 +00:00
l = gtk_label_new ( _ ( " Options " ) ) ;
gtk_notebook_append_page ( GTK_NOTEBOOK ( n ) , w , l ) ;
2008-09-23 19:11:04 +00:00
2008-10-31 18:25:21 +00:00
gtk_box_pack_start ( GTK_BOX ( GTK_DIALOG ( d ) - > vbox ) , n , TRUE , TRUE , 0 ) ;
2008-09-23 19:11:04 +00:00
2009-04-24 15:24:43 +00:00
di - > periodic_refresh_tag = gtr_timeout_add_seconds ( UPDATE_INTERVAL_SECONDS ,
periodic_refresh , di ) ;
periodic_refresh ( di ) ;
2009-03-05 17:18:36 +00:00
gtk_widget_show_all ( GTK_DIALOG ( d ) - > vbox ) ;
2008-09-23 19:11:04 +00:00
return d ;
2007-06-06 00:30:13 +00:00
}
2008-09-23 19:11:04 +00:00
2009-04-24 01:37:04 +00:00
void
torrent_inspector_set_torrents ( GtkWidget * w , GSList * ids )
{
2009-04-24 15:24:43 +00:00
struct DetailsImpl * di = g_object_get_data ( G_OBJECT ( w ) , DETAILS_KEY ) ;
2009-04-24 12:05:53 +00:00
const int len = g_slist_length ( ids ) ;
char title [ 256 ] ;
2009-04-24 01:37:04 +00:00
2009-04-24 15:24:43 +00:00
g_slist_free ( di - > ids ) ;
di - > ids = g_slist_copy ( ids ) ;
2009-04-24 01:37:04 +00:00
2009-04-24 12:05:53 +00:00
if ( len = = 1 )
{
2009-04-24 01:37:04 +00:00
const int id = GPOINTER_TO_INT ( ids - > data ) ;
2009-04-24 15:24:43 +00:00
tr_session * session = tr_core_session ( di - > core ) ;
2009-04-24 12:05:53 +00:00
tr_torrent * tor = tr_torrentFindFromId ( session , id ) ;
const tr_info * inf = tr_torrentInfo ( tor ) ;
g_snprintf ( title , sizeof ( title ) , _ ( " %s Properties " ) , inf - > name ) ;
2009-04-24 15:24:43 +00:00
file_list_set_torrent ( di - > file_list , id ) ;
2009-09-25 21:05:59 +00:00
//tracker_list_set_torrent( di->tracker_list, id );
2009-04-24 12:05:53 +00:00
}
else
{
2009-04-24 15:24:43 +00:00
file_list_clear ( di - > file_list ) ;
2009-09-25 21:05:59 +00:00
//tracker_list_clear( di->tracker_list );
2009-04-24 12:05:53 +00:00
g_snprintf ( title , sizeof ( title ) , _ ( " %'d Torrent Properties " ) , len ) ;
2009-04-24 01:37:04 +00:00
}
2009-04-24 12:05:53 +00:00
gtk_window_set_title ( GTK_WINDOW ( w ) , title ) ;
2009-04-24 15:24:43 +00:00
refresh ( di ) ;
2009-04-24 01:37:04 +00:00
}