source: trunk/gtk/tr-prefs.c @ 5217

Last change on this file since 5217 was 5217, checked in by charles, 14 years ago

remove a couple of preferences:
(1) "delete original file" ... this can be turned on in the "add" dialog, but who would want this to always be unconditionally true?
(2) "show in systray" ... since not many people will toggle this, move it from the prefs dialog to the .ini file

  • Property svn:keywords set to Date Rev Author Id
File size: 11.9 KB
Line 
1/*
2 * This file Copyright (C) 2007-2008 Charles Kerr <charles@rebelbase.com>
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: tr-prefs.c 5217 2008-03-07 18:57:32Z charles $
11 */
12
13#include <glib/gi18n.h>
14#include <gtk/gtk.h>
15#include <third-party/miniupnp/miniwget.h>
16#include <libtransmission/transmission.h>
17#include "conf.h"
18#include "hig.h"
19#include "tr-core.h"
20#include "tr-prefs.h"
21#include "util.h"
22
23/**
24 * This is where we initialize the preferences file with the default values.
25 * If you add a new preferences key, you /must/ add a default value here.
26 */
27void
28tr_prefs_init_global( void )
29{
30    const char * str;
31
32    cf_check_older_configs( );
33
34    pref_int_set_default    ( PREF_KEY_MAX_PEERS_GLOBAL, 200 );
35    pref_int_set_default    ( PREF_KEY_MAX_PEERS_PER_TORRENT, 50 );
36
37    pref_flag_set_default   ( PREF_KEY_TOOLBAR, TRUE );
38    pref_flag_set_default   ( PREF_KEY_FILTER_BAR, TRUE );
39    pref_flag_set_default   ( PREF_KEY_STATUS_BAR, TRUE );
40    pref_string_set_default ( PREF_KEY_STATUS_BAR_STATS, "total-ratio" );
41
42    pref_flag_set_default   ( PREF_KEY_DL_LIMIT_ENABLED, FALSE );
43    pref_int_set_default    ( PREF_KEY_DL_LIMIT, 100 );
44    pref_flag_set_default   ( PREF_KEY_UL_LIMIT_ENABLED, FALSE );
45    pref_int_set_default    ( PREF_KEY_UL_LIMIT, 50 );
46    pref_flag_set_default   ( PREF_KEY_OPTIONS_PROMPT, TRUE );
47
48    str = NULL;
49#if GLIB_CHECK_VERSION(2,14,0)
50    if( !str )
51        str = g_get_user_special_dir( G_USER_DIRECTORY_DOWNLOAD );
52#endif
53    if( !str )
54        str = g_get_home_dir( );
55    pref_string_set_default ( PREF_KEY_DIR_DEFAULT, str );
56
57    pref_int_set_default    ( PREF_KEY_PORT, TR_DEFAULT_PORT );
58
59    pref_flag_set_default   ( PREF_KEY_NOTIFY, TRUE );
60
61    pref_flag_set_default   ( PREF_KEY_NAT, TRUE );
62    pref_flag_set_default   ( PREF_KEY_PEX, TRUE );
63    pref_flag_set_default   ( PREF_KEY_SYSTRAY, TRUE );
64    pref_flag_set_default   ( PREF_KEY_ASKQUIT, TRUE );
65    pref_flag_set_default   ( PREF_KEY_ENCRYPTED_ONLY, FALSE );
66
67    pref_int_set_default    ( PREF_KEY_MSGLEVEL, TR_MSG_INF );
68
69    pref_string_set_default ( PREF_KEY_SORT_MODE, "sort-by-name" );
70    pref_flag_set_default   ( PREF_KEY_SORT_REVERSED, FALSE );
71    pref_flag_set_default   ( PREF_KEY_MINIMAL_VIEW, FALSE );
72
73    pref_flag_set_default   ( PREF_KEY_START, TRUE );
74
75    pref_save( NULL );
76}
77
78/**
79***
80**/
81
82#define PREF_KEY "pref-key"
83
84static void
85response_cb( GtkDialog * dialog, int response UNUSED, gpointer unused UNUSED )
86{
87    gtk_widget_destroy( GTK_WIDGET(dialog) );
88}
89
90static void
91toggled_cb( GtkToggleButton * w, gpointer core )
92{
93    const char * key = g_object_get_data( G_OBJECT(w), PREF_KEY );
94    const gboolean flag = gtk_toggle_button_get_active( w );
95    tr_core_set_pref_bool( TR_CORE(core), key, flag );
96}
97
98static GtkWidget*
99new_check_button( const char * mnemonic, const char * key, gpointer core )
100{
101    GtkWidget * w = gtk_check_button_new_with_mnemonic( mnemonic );
102    g_object_set_data_full( G_OBJECT(w), PREF_KEY, g_strdup(key), g_free );
103    gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(w), pref_flag_get(key) );
104    g_signal_connect( w, "toggled", G_CALLBACK(toggled_cb), core );
105    return w;
106}
107
108static void
109spun_cb( GtkSpinButton * w, gpointer core )
110{
111    const char * key = g_object_get_data( G_OBJECT(w), PREF_KEY );
112    const int value = gtk_spin_button_get_value_as_int( w );
113    tr_core_set_pref_int( TR_CORE(core), key, value );
114}
115
116static GtkWidget*
117new_spin_button( const char * key, gpointer core, int low, int high, int step )
118{
119    GtkWidget * w = gtk_spin_button_new_with_range( low, high, step );
120    g_object_set_data_full( G_OBJECT(w), PREF_KEY, g_strdup(key), g_free );
121    gtk_spin_button_set_digits( GTK_SPIN_BUTTON(w), 0 );
122    gtk_spin_button_set_value( GTK_SPIN_BUTTON(w), pref_int_get(key) );
123    g_signal_connect( w, "value-changed", G_CALLBACK(spun_cb), core );
124    return w;
125}
126
127static void
128chosen_cb( GtkFileChooser * w, gpointer core )
129{
130    const char * key = g_object_get_data( G_OBJECT(w), PREF_KEY );
131    char * value = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(w) );
132    tr_core_set_pref( TR_CORE(core), key, value );
133    g_free( value );
134}
135
136static GtkWidget*
137new_path_chooser_button( const char * key, gpointer core )
138{
139    GtkWidget * w = gtk_file_chooser_button_new( NULL,
140                                    GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER );
141    char * path = pref_string_get( key );
142    g_object_set_data_full( G_OBJECT(w), PREF_KEY, g_strdup(key), g_free );
143    g_signal_connect( w, "selection-changed", G_CALLBACK(chosen_cb), core );
144    gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(w), path );
145    return w;
146}
147
148static void
149target_cb( GtkWidget * tb, gpointer target )
150{
151    const gboolean b = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( tb ) );
152    gtk_widget_set_sensitive( GTK_WIDGET(target), b );
153}
154
155struct test_port_data
156{
157    GtkWidget * label;
158    gboolean * alive;
159};
160
161static gpointer
162test_port( gpointer data_gpointer )
163{
164    struct test_port_data * data = data_gpointer;
165
166    if( *data->alive )
167    {
168        GObject * o = G_OBJECT( data->label );
169        GtkSpinButton * spin = g_object_get_data( o, "tr-port-spin" );
170        const int port = gtk_spin_button_get_value_as_int( spin );
171        int isOpen;
172        int size;
173        char * text;
174        char url[256];
175
176        g_usleep( G_USEC_PER_SEC * 3 ); /* give portmapping time to kick in */
177        snprintf( url, sizeof(url), "http://portcheck.transmissionbt.com/%d", port );
178        text = miniwget( url, &size );
179        /*g_message(" got len %d, [%*.*s]", size, size, size, text );*/
180        isOpen = text && *text=='1';
181
182        if( *data->alive )
183            gtk_label_set_markup( GTK_LABEL(data->label), isOpen
184                ? _("Port is <b>open</b>")
185                : _("Port is <b>closed</b>") );
186    }
187
188    g_free( data );
189    return NULL;
190}
191
192static void
193testing_port_cb( GtkWidget * unused UNUSED, gpointer l )
194{
195    struct test_port_data * data = g_new0( struct test_port_data, 1 );
196    data->alive = g_object_get_data( G_OBJECT( l ), "alive" );
197    data->label = l;
198    gtk_label_set_markup( GTK_LABEL(l), _( "<i>Testing port...</i>" ) );
199    g_thread_create( test_port, data, FALSE, NULL );
200}
201
202static void
203dialogDestroyed( gpointer alive, GObject * dialog UNUSED )
204{
205    *(gboolean*)alive = FALSE;
206}
207
208static GtkWidget*
209torrentPage( GObject * core )
210{
211    int row = 0;
212    const char * s;
213    GtkWidget * t;
214    GtkWidget * w;
215
216    t = hig_workarea_create( );
217    hig_workarea_add_section_title( t, &row, _( "Adding" ) );
218
219        w = new_path_chooser_button( PREF_KEY_DIR_DEFAULT, core );
220        hig_workarea_add_row( t, &row, _( "Default download _location:" ), w, NULL );
221
222        s = _( "Show _options dialog" );
223        w = new_check_button( s, PREF_KEY_OPTIONS_PROMPT, core );
224        hig_workarea_add_wide_control( t, &row, w );
225
226        s = _( "_Start when added" );
227        w = new_check_button( s, PREF_KEY_START, core );
228        hig_workarea_add_wide_control( t, &row, w );
229
230#ifdef HAVE_LIBNOTIFY
231    hig_workarea_add_section_divider( t, &row );
232    hig_workarea_add_section_title( t, &row, _( "Notification" ) );
233
234        s = _( "_Popup message when a torrent finishes" );
235        w = new_check_button( s, PREF_KEY_NOTIFY, core );
236        hig_workarea_add_wide_control( t, &row, w );
237#endif
238
239    hig_workarea_finish( t, &row );
240    return t;
241}
242
243static GtkWidget*
244peerPage( GObject * core )
245{
246    int row = 0;
247    const char * s;
248    GtkWidget * t;
249    GtkWidget * w;
250
251    t = hig_workarea_create( );
252    hig_workarea_add_section_title (t, &row, _("Options"));
253       
254        s = _("Use peer _exchange if possible");
255        w = new_check_button( s, PREF_KEY_PEX, core );
256        hig_workarea_add_wide_control( t, &row, w );
257       
258        s = _("_Ignore unencrypted peers");
259        w = new_check_button( s, PREF_KEY_ENCRYPTED_ONLY, core );
260        hig_workarea_add_wide_control( t, &row, w );
261
262    hig_workarea_add_section_divider( t, &row );
263    hig_workarea_add_section_title( t, &row, _( "Limits" ) );
264 
265        w = new_spin_button( PREF_KEY_MAX_PEERS_GLOBAL, core, 1, 3000, 5 );
266        hig_workarea_add_row( t, &row, _( "Maximum peers _overall:" ), w, NULL );
267        w = new_spin_button( PREF_KEY_MAX_PEERS_PER_TORRENT, core, 1, 300, 5 );
268        hig_workarea_add_row( t, &row, _( "Maximum peers per _torrent:" ), w, NULL );
269
270    hig_workarea_finish( t, &row );
271    return t;
272}
273
274static GtkWidget*
275networkPage( GObject * core, gpointer alive )
276{
277    int row = 0;
278    const char * s;
279    GtkWidget * t;
280    GtkWidget * w, * w2;
281    GtkWidget * l;
282    GtkWidget * h;
283
284    t = hig_workarea_create( );
285
286    hig_workarea_add_section_title (t, &row, _("Bandwidth"));
287
288        s = _("Limit _upload speed (KiB/s):");
289        w = new_check_button( s, PREF_KEY_UL_LIMIT_ENABLED, core );
290        w2 = new_spin_button( PREF_KEY_UL_LIMIT, core, 0, INT_MAX, 5 );
291        gtk_widget_set_sensitive( GTK_WIDGET(w2), pref_flag_get( PREF_KEY_UL_LIMIT_ENABLED ) );
292        g_signal_connect( w, "toggled", G_CALLBACK(target_cb), w2 );
293        hig_workarea_add_row_w( t, &row, w, w2, NULL );
294
295        s = _("Limit _download speed (KiB/s):");
296        w = new_check_button( s, PREF_KEY_DL_LIMIT_ENABLED, core );
297        w2 = new_spin_button( PREF_KEY_DL_LIMIT, core, 0, INT_MAX, 5 );
298        gtk_widget_set_sensitive( GTK_WIDGET(w2), pref_flag_get( PREF_KEY_DL_LIMIT_ENABLED ) );
299        g_signal_connect( w, "toggled", G_CALLBACK(target_cb), w2 );
300        hig_workarea_add_row_w( t, &row, w, w2, NULL );
301
302    hig_workarea_add_section_title (t, &row, _("Ports"));
303       
304        s = _("_Map port with UPnP or NAT-PMP" );
305        w = new_check_button( s, PREF_KEY_NAT, core );
306        hig_workarea_add_wide_control( t, &row, w );
307
308        h = gtk_hbox_new( FALSE, GUI_PAD );
309        w2 = new_spin_button( PREF_KEY_PORT, core, 1, INT_MAX, 1 );
310        gtk_box_pack_start( GTK_BOX(h), w2, FALSE, FALSE, 0 );
311        l = gtk_label_new( NULL );
312        gtk_misc_set_alignment( GTK_MISC(l), 0.0f, 0.5f );
313        gtk_box_pack_start( GTK_BOX(h), l, FALSE, FALSE, 0 );
314        hig_workarea_add_row( t, &row, _("Incoming TCP _port"), h, w );
315
316        g_object_set_data( G_OBJECT(l), "tr-port-spin", w2 );
317        g_object_set_data( G_OBJECT(l), "alive", alive );
318        testing_port_cb( NULL, l );
319
320        g_signal_connect( w, "toggled", G_CALLBACK(testing_port_cb), l );
321        g_signal_connect( w2, "value-changed", G_CALLBACK(testing_port_cb), l );
322
323    hig_workarea_finish( t, &row );
324    return t;
325}
326
327GtkWidget *
328tr_prefs_dialog_new( GObject * core, GtkWindow * parent )
329{
330    GtkWidget * d;
331    GtkWidget * n;
332    gboolean * alive;
333
334    alive = g_new( gboolean, 1 );
335    *alive = TRUE;
336
337    d = gtk_dialog_new_with_buttons( _("Preferences"), parent,
338                                     GTK_DIALOG_DESTROY_WITH_PARENT,
339                                     GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
340                                     NULL );
341    gtk_window_set_role( GTK_WINDOW(d), "transmission-preferences-dialog" );
342    gtk_dialog_set_has_separator( GTK_DIALOG( d ), FALSE );
343    gtk_container_set_border_width( GTK_CONTAINER( d ), GUI_PAD );
344    g_object_weak_ref( G_OBJECT( d ), dialogDestroyed, alive );
345
346    n = gtk_notebook_new( );
347
348    gtk_notebook_append_page( GTK_NOTEBOOK( n ),
349                              torrentPage( core ),
350                              gtk_label_new (_("Torrents")) );
351    gtk_notebook_append_page( GTK_NOTEBOOK( n ),
352                              peerPage( core ),
353                              gtk_label_new (_("Peers")) );
354    gtk_notebook_append_page( GTK_NOTEBOOK( n ),
355                              networkPage( core, alive ),
356                              gtk_label_new (_("Network")) );
357
358    g_signal_connect( d, "response", G_CALLBACK(response_cb), core );
359    gtk_box_pack_start_defaults( GTK_BOX(GTK_DIALOG(d)->vbox), n );
360    gtk_widget_show_all( GTK_DIALOG(d)->vbox );
361    return d;
362}
Note: See TracBrowser for help on using the repository browser.