source: trunk/gtk/add-dialog.c @ 9338

Last change on this file since 9338 was 9338, checked in by charles, 13 years ago

(trunk gtk,qt) synchronize the gtk, qt preferences dialogs a bit

  • Property svn:keywords set to Date Rev Author Id
File size: 14.5 KB
Line 
1/*
2 * This file Copyright (C) 2008-2009 Charles Kerr <charles@transmissionbt.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: add-dialog.c 9338 2009-10-20 14:01:15Z charles $
11 */
12
13#include <glib/gi18n.h>
14#include <gtk/gtk.h>
15#include "add-dialog.h"
16#include "conf.h"
17#include "file-list.h"
18#include "hig.h"
19#include "tr-prefs.h"
20
21/****
22*****
23****/
24
25#define N_RECENT 4
26
27static GSList*
28get_recent_destinations( void )
29{
30    int      i;
31    GSList * list = NULL;
32
33    for( i = 0; i < N_RECENT; ++i )
34    {
35        char         key[64];
36        const char * val;
37        g_snprintf( key, sizeof( key ), "recent-download-dir-%d", i + 1 );
38        if( ( val = pref_string_get( key ) ) )
39            list = g_slist_append( list, (void*)val );
40    }
41    return list;
42}
43
44static void
45save_recent_destination( TrCore * core, const char * dir  )
46{
47    int      i;
48    GSList * list = get_recent_destinations( );
49    GSList * l;
50
51    if( !dir )
52        return;
53
54    /* if it was already in the list, remove it */
55    if( ( l = g_slist_find_custom( list, dir, (GCompareFunc)strcmp ) ) )
56        list = g_slist_delete_link( list, l );
57
58    /* add it to the front of the list */
59    list = g_slist_prepend( list, (void*)dir );
60
61    /* make local copies of the strings that aren't
62     * invalidated by pref_string_set() */
63    for( l = list; l; l = l->next )
64        l->data = g_strdup( l->data );
65
66    /* save the first N_RECENT directories */
67    for( l = list, i = 0; l && ( i < N_RECENT ); ++i, l = l->next )
68    {
69        char key[64];
70        g_snprintf( key, sizeof( key ), "recent-download-dir-%d", i + 1 );
71        pref_string_set( key, l->data );
72    }
73    pref_save( tr_core_session( core ) );
74
75    /* cleanup */
76    g_slist_foreach( list, (GFunc)g_free, NULL );
77    g_slist_free( list );
78}
79
80/****
81*****
82****/
83
84struct AddData
85{
86    TrCore *     core;
87    GtkWidget *  list;
88    GtkWidget *  run_check;
89    GtkWidget *  trash_check;
90    char *       filename;
91    char *       downloadDir;
92    TrTorrent *  gtor;
93    tr_ctor *    ctor;
94};
95
96static void
97removeOldTorrent( struct AddData * data )
98{
99    if( data->gtor )
100    {
101        file_list_clear( data->list );
102        tr_torrent_set_remove_flag( data->gtor, TRUE );
103        g_object_unref( G_OBJECT( data->gtor ) );
104        data->gtor = NULL;
105    }
106}
107
108static void
109addResponseCB( GtkDialog * dialog,
110               gint        response,
111               gpointer    gdata )
112{
113    struct AddData * data = gdata;
114
115    if( data->gtor )
116    {
117        if( response != GTK_RESPONSE_ACCEPT )
118        {
119            removeOldTorrent( data );
120        }
121        else
122        {
123            if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( data->run_check ) ) )
124                tr_torrentStart( tr_torrent_handle( data->gtor ) );
125
126            tr_core_add_torrent( data->core, data->gtor, FALSE );
127
128            if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( data->trash_check ) ) )
129
130                tr_file_trash_or_remove( data->filename );
131            save_recent_destination( data->core, data->downloadDir );
132        }
133    }
134
135    tr_ctorFree( data->ctor );
136    g_free( data->filename );
137    g_free( data->downloadDir );
138    g_free( data );
139    gtk_widget_destroy( GTK_WIDGET( dialog ) );
140}
141
142static void
143updateTorrent( struct AddData * o )
144{
145    if( !o->gtor )
146        file_list_clear( o->list );
147    else {
148        tr_torrent * tor = tr_torrent_handle( o->gtor );
149        tr_torrentSetDownloadDir( tor, o->downloadDir );
150        file_list_set_torrent( o->list, tr_torrentId( tor ) );
151    }
152}
153
154/**
155 * When the source .torrent file is deleted
156 * (such as, if it was a temp file that a web browser passed to us),
157 * gtk invokes this callback and `filename' will be NULL.
158 * The `filename' tests here are to prevent us from losing the current
159 * metadata when that happens.
160 */
161static void
162sourceChanged( GtkFileChooserButton * b,
163               gpointer               gdata )
164{
165    struct AddData * data = gdata;
166    char *           filename = gtk_file_chooser_get_filename(
167         GTK_FILE_CHOOSER( b ) );
168
169    /* maybe instantiate a torrent */
170    if( data->filename || !data->gtor )
171    {
172        int          err = 0;
173        int          new_file = 0;
174        tr_torrent * torrent;
175
176        if( filename
177          && ( !data->filename || strcmp( filename, data->filename ) ) )
178        {
179            g_free( data->filename );
180            data->filename = g_strdup( filename );
181            tr_ctorSetMetainfoFromFile( data->ctor, data->filename );
182            new_file = 1;
183        }
184
185        tr_ctorSetDownloadDir( data->ctor, TR_FORCE, data->downloadDir );
186        tr_ctorSetPaused( data->ctor, TR_FORCE, TRUE );
187        tr_ctorSetDeleteSource( data->ctor, FALSE );
188
189        if( ( torrent = tr_torrentNew( data->ctor, &err ) ) )
190        {
191            removeOldTorrent( data );
192            data->gtor = tr_torrent_new_preexisting( torrent );
193        }
194        else if( new_file )
195        {
196            addTorrentErrorDialog( GTK_WIDGET( b ), err, data->filename );
197        }
198
199        updateTorrent( data );
200    }
201
202    g_free( filename );
203}
204
205static void
206verifyRequested( GtkButton * button UNUSED,
207                 gpointer           gdata )
208{
209    struct AddData * data = gdata;
210
211    if( data->gtor )
212        tr_torrentVerify( tr_torrent_handle( data->gtor ) );
213}
214
215static void
216downloadDirChanged( GtkFileChooserButton * b,
217                    gpointer               gdata )
218{
219    char *           fname = gtk_file_chooser_get_filename(
220         GTK_FILE_CHOOSER( b ) );
221    struct AddData * data = gdata;
222
223    if( fname && ( !data->downloadDir || strcmp( fname, data->downloadDir ) ) )
224    {
225        g_free( data->downloadDir );
226        data->downloadDir = g_strdup( fname );
227
228        updateTorrent( data );
229        verifyRequested( NULL, data );
230    }
231
232    g_free( fname );
233}
234
235static void
236addTorrentFilters( GtkFileChooser * chooser )
237{
238    GtkFileFilter * filter;
239
240    filter = gtk_file_filter_new( );
241    gtk_file_filter_set_name( filter, _( "Torrent files" ) );
242    gtk_file_filter_add_pattern( filter, "*.torrent" );
243    gtk_file_chooser_add_filter( chooser, filter );
244
245    filter = gtk_file_filter_new( );
246    gtk_file_filter_set_name( filter, _( "All files" ) );
247    gtk_file_filter_add_pattern( filter, "*" );
248    gtk_file_chooser_add_filter( chooser, filter );
249}
250
251/****
252*****
253****/
254
255GtkWidget*
256addSingleTorrentDialog( GtkWindow * parent,
257                        TrCore *    core,
258                        tr_ctor *   ctor )
259{
260    int              row;
261    int              col;
262    const char *     str;
263    GtkWidget *      w;
264    GtkWidget *      d;
265    GtkWidget *      t;
266    GtkWidget *      l;
267    GtkWidget *      source_chooser;
268    struct AddData * data;
269    uint8_t          flag;
270    GSList *         list;
271    GSList *         walk;
272
273    /* make the dialog */
274    d = gtk_dialog_new_with_buttons( _(
275                                         "Torrent Options" ), parent,
276                                     GTK_DIALOG_DESTROY_WITH_PARENT |
277                                     GTK_DIALOG_NO_SEPARATOR,
278                                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
279                                     GTK_STOCK_ADD, GTK_RESPONSE_ACCEPT,
280                                     NULL );
281    gtk_dialog_set_default_response( GTK_DIALOG( d ),
282                                     GTK_RESPONSE_ACCEPT );
283    gtk_dialog_set_alternative_button_order( GTK_DIALOG( d ),
284                                             GTK_RESPONSE_ACCEPT,
285                                             GTK_RESPONSE_CANCEL,
286                                             -1 );
287
288    if( tr_ctorGetDownloadDir( ctor, TR_FORCE, &str ) )
289        g_assert_not_reached( );
290    g_assert( str );
291
292    data = g_new0( struct AddData, 1 );
293    data->core = core;
294    data->ctor = ctor;
295    data->filename = g_strdup( tr_ctorGetSourceFile( ctor ) );
296    data->downloadDir = g_strdup( str );
297    data->list = file_list_new( core, 0 );
298    str = _( "Mo_ve .torrent file to the trash" );
299    data->trash_check = gtk_check_button_new_with_mnemonic( str );
300    str = _( "_Start when added" );
301    data->run_check = gtk_check_button_new_with_mnemonic( str );
302
303    g_signal_connect( G_OBJECT( d ), "response",
304                      G_CALLBACK( addResponseCB ), data );
305
306    t = gtk_table_new( 6, 2, FALSE );
307    gtk_container_set_border_width( GTK_CONTAINER( t ), GUI_PAD_BIG );
308    gtk_table_set_row_spacings( GTK_TABLE( t ), GUI_PAD );
309    gtk_table_set_col_spacings( GTK_TABLE( t ), GUI_PAD_BIG );
310
311    row = col = 0;
312    l = gtk_label_new_with_mnemonic( _( "_Torrent file:" ) );
313    gtk_misc_set_alignment( GTK_MISC( l ), 0.0f, 0.5f );
314    gtk_table_attach( GTK_TABLE(
315                          t ), l, col, col + 1, row, row + 1, GTK_FILL, 0,
316                      0, 0 );
317    ++col;
318    w = gtk_file_chooser_button_new( _( "Select Source File" ),
319                                     GTK_FILE_CHOOSER_ACTION_OPEN );
320    source_chooser = w;
321    gtk_table_attach( GTK_TABLE(
322                          t ), w, col, col + 1, row, row + 1, ~0, 0, 0, 0 );
323    gtk_label_set_mnemonic_widget( GTK_LABEL( l ), w );
324    addTorrentFilters( GTK_FILE_CHOOSER( w ) );
325    g_signal_connect( w, "selection-changed",
326                      G_CALLBACK( sourceChanged ), data );
327
328    ++row;
329    col = 0;
330    l = gtk_label_new_with_mnemonic( _( "_Destination folder:" ) );
331    gtk_misc_set_alignment( GTK_MISC( l ), 0.0f, 0.5f );
332    gtk_table_attach( GTK_TABLE(
333                          t ), l, col, col + 1, row, row + 1, GTK_FILL, 0,
334                      0, 0 );
335    ++col;
336    w = gtk_file_chooser_button_new( _(
337                                         "Select Destination Folder" ),
338                                     GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER );
339    if( !gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( w ),
340                                        data->downloadDir ) )
341        g_warning( "couldn't select '%s'", data->downloadDir );
342    list = get_recent_destinations( );
343    for( walk = list; walk; walk = walk->next )
344        gtk_file_chooser_add_shortcut_folder( GTK_FILE_CHOOSER(
345                                                  w ), walk->data, NULL );
346    g_slist_free( list );
347    gtk_table_attach( GTK_TABLE(
348                          t ), w, col, col + 1, row, row + 1, ~0, 0, 0, 0 );
349    gtk_label_set_mnemonic_widget( GTK_LABEL( l ), w );
350    g_signal_connect( w, "selection-changed",
351                      G_CALLBACK( downloadDirChanged ), data );
352
353    ++row;
354    col = 0;
355    w = data->list;
356    gtk_widget_set_size_request ( w, 466u, 300u );
357    gtk_table_attach_defaults( GTK_TABLE(
358                                   t ), w, col, col + 2, row, row + 1 );
359
360    ++row;
361    col = 0;
362    w = gtk_button_new_with_mnemonic( _( "_Verify Local Data" ) );
363    gtk_table_attach( GTK_TABLE(
364                          t ), w, col, col + 1, row, row + 1, GTK_FILL, 0,
365                      0, 0 );
366    g_signal_connect( w, "clicked", G_CALLBACK( verifyRequested ), data );
367
368    ++row;
369    col = 0;
370    w = data->run_check;
371    if( tr_ctorGetPaused( ctor, TR_FORCE, &flag ) )
372        g_assert_not_reached( );
373    gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( w ), !flag );
374    gtk_table_attach( GTK_TABLE(
375                          t ), w, col, col + 2, row, row + 1, GTK_FILL, 0,
376                      0, 0 );
377
378    ++row;
379    col = 0;
380    w = data->trash_check;
381    if( tr_ctorGetDeleteSource( ctor, &flag ) )
382        g_assert_not_reached( );
383    gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( w ), flag );
384    gtk_table_attach( GTK_TABLE(
385                          t ), w, col, col + 2, row, row + 1, GTK_FILL, 0,
386                      0, 0 );
387
388    /* trigger sourceChanged, either directly or indirectly,
389     * so that it creates the tor/gtor objects */
390    w = source_chooser;
391    if( data->filename )
392        gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( w ), data->filename );
393    else
394        sourceChanged( GTK_FILE_CHOOSER_BUTTON( w ), data );
395
396    gtk_box_pack_start( GTK_BOX( GTK_DIALOG( d )->vbox ), t, TRUE, TRUE, 0 );
397    gtk_widget_show_all( d );
398    return d;
399}
400
401/****
402*****
403****/
404
405static void
406onAddDialogResponse( GtkDialog * dialog,
407                     int         response,
408                     gpointer    core )
409{
410    char * folder;
411
412    /* remember this folder the next time we use this dialog */
413    folder = gtk_file_chooser_get_current_folder( GTK_FILE_CHOOSER( dialog ) );
414    pref_string_set( PREF_KEY_OPEN_DIALOG_FOLDER, folder );
415    g_free( folder );
416
417    if( response == GTK_RESPONSE_ACCEPT )
418    {
419        GtkFileChooser  * chooser = GTK_FILE_CHOOSER( dialog );
420        GtkWidget       * w = gtk_file_chooser_get_extra_widget( chooser );
421        GtkToggleButton * tb = GTK_TOGGLE_BUTTON( w );
422        const gboolean    showOptions = gtk_toggle_button_get_active( tb );
423        const pref_flag_t start = PREF_FLAG_DEFAULT;
424        const pref_flag_t prompt = showOptions
425                                 ? PREF_FLAG_TRUE
426                                 : PREF_FLAG_FALSE;
427        GSList * l = gtk_file_chooser_get_filenames( chooser );
428
429        tr_core_add_list( core, l, start, prompt, FALSE );
430    }
431
432    gtk_widget_destroy( GTK_WIDGET( dialog ) );
433}
434
435GtkWidget*
436addDialog( GtkWindow * parent,
437           TrCore *    core )
438{
439    GtkWidget *  w;
440    GtkWidget *  c;
441    const char * folder;
442
443    w = gtk_file_chooser_dialog_new( _( "Add a Torrent" ), parent,
444                                     GTK_FILE_CHOOSER_ACTION_OPEN,
445                                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
446                                     GTK_STOCK_ADD, GTK_RESPONSE_ACCEPT,
447                                     NULL );
448    gtk_dialog_set_alternative_button_order( GTK_DIALOG( w ),
449                                             GTK_RESPONSE_ACCEPT,
450                                             GTK_RESPONSE_CANCEL,
451                                             -1 );
452    gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER( w ), TRUE );
453    addTorrentFilters( GTK_FILE_CHOOSER( w ) );
454    g_signal_connect( w, "response", G_CALLBACK(
455                          onAddDialogResponse ), core );
456
457    if( ( folder = pref_string_get( PREF_KEY_OPEN_DIALOG_FOLDER ) ) )
458        gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( w ), folder );
459
460    c = gtk_check_button_new_with_mnemonic( _( "Show _options dialog" ) );
461    gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( c ),
462                                 pref_flag_get( PREF_KEY_OPTIONS_PROMPT ) );
463    gtk_file_chooser_set_extra_widget( GTK_FILE_CHOOSER( w ), c );
464    gtk_widget_show( c );
465
466    gtk_widget_show( w );
467    return w;
468}
469
Note: See TracBrowser for help on using the repository browser.