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

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

(gtk) #867: add missing accelerators; remove accelerator collisions where possible

  • Property svn:keywords set to Date Rev Author Id
File size: 12.2 KB
Line 
1/*
2 * This file Copyright (C) 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: add-dialog.c 6370 2008-07-19 19:55:08Z 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    for( i=0; i<N_RECENT; ++i )
33    {
34        char key[64];
35        const char * val;
36        g_snprintf( key, sizeof(key), "recent-download-dir-%d", i+1 );
37        if(( val = pref_string_get( key )))
38            list = g_slist_append( list, (void*)val );
39    }
40    return list;
41}
42
43static void
44save_recent_destination( const char * dir  )
45{
46    int i;
47    GSList * list = get_recent_destinations( );
48    GSList * l;
49
50    if( !dir )
51        return;
52
53    /* if it was already in the list, remove it */
54    if(( l = g_slist_find_custom( list, dir, (GCompareFunc)strcmp )))
55        list = g_slist_delete_link( list, l );
56
57    /* add it to the front of the list */
58    list = g_slist_prepend( list, (void*)dir );
59
60    /* make local copies of the strings that aren't
61     * invalidated by pref_string_set() */
62    for( l=list; l; l=l->next )
63         l->data = g_strdup( l->data );
64
65    /* save the first N_RECENT directories */
66    for( l=list, i=0; l && (i<N_RECENT); ++i, l=l->next ) {
67        char key[64];
68        g_snprintf( key, sizeof(key), "recent-download-dir-%d", i+1 );
69        pref_string_set( key, l->data );
70    }
71    pref_save( );
72
73    /* cleanup */
74    g_slist_foreach( list, (GFunc)g_free, NULL );
75    g_slist_free( list );
76}
77
78/****
79*****
80****/
81
82struct AddData
83{
84    TrCore * core;
85    GtkWidget * list;
86    GtkWidget * run_check;
87    GtkWidget * trash_check;
88    char * filename;
89    char * downloadDir;
90    TrTorrent * gtor;
91    tr_ctor * ctor;
92};
93
94static void
95removeOldTorrent( struct AddData * data )
96{
97    if( data->gtor )
98    {
99        file_list_set_torrent( data->list, NULL );
100
101        tr_torrent_set_remove_flag( data->gtor, TRUE );
102        g_object_unref( G_OBJECT( data->gtor ) );
103        data->gtor = NULL;
104    }
105}
106
107static void
108addResponseCB( GtkDialog * dialog, gint response, gpointer gdata )
109{
110    struct AddData * data = gdata;
111
112    if( data->gtor )
113    {
114        if( response != GTK_RESPONSE_ACCEPT )
115            removeOldTorrent( data );
116        else {
117            if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( data->run_check ) ) )
118                tr_torrentStart( tr_torrent_handle( data->gtor ) );
119            tr_core_add_torrent( data->core, data->gtor );
120            if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( data->trash_check ) ) )
121                tr_file_trash_or_unlink( data->filename );
122            save_recent_destination( data->downloadDir );
123        }
124    }
125
126    tr_ctorFree( data->ctor );
127    g_free( data->filename );
128    g_free( data->downloadDir );
129    g_free( data );
130    gtk_widget_destroy( GTK_WIDGET( dialog ) );
131}
132
133static void
134updateTorrent( struct AddData * o )
135{
136    if( o->gtor )
137        tr_torrentSetDownloadDir( tr_torrent_handle( o->gtor ), o->downloadDir );
138
139    file_list_set_torrent( o->list, o->gtor );
140}
141
142static void
143sourceChanged( GtkFileChooserButton * b, gpointer gdata )
144{
145    struct AddData * data = gdata;
146
147    removeOldTorrent( data );
148
149    g_free( data->filename );
150    data->filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( b ) );
151
152    /* maybe instantiate a torrent */
153    if( data->filename ) {
154        int err = 0;
155        tr_torrent * torrent;
156        tr_handle * handle = tr_core_handle( data->core );
157        tr_ctorSetMetainfoFromFile( data->ctor, data->filename );
158        tr_ctorSetDownloadDir( data->ctor, TR_FORCE, data->downloadDir );
159        tr_ctorSetPaused( data->ctor, TR_FORCE, TRUE );
160        tr_ctorSetDeleteSource( data->ctor, FALSE );
161        if(( torrent = tr_torrentNew( handle, data->ctor, &err )))
162            data->gtor = tr_torrent_new_preexisting( torrent );
163        else
164            addTorrentErrorDialog( GTK_WIDGET(b), err, data->filename );
165    }
166
167    updateTorrent( data );
168}
169
170static void
171verifyRequested( GtkButton * button UNUSED, gpointer gdata )
172{
173    struct AddData * data = gdata;
174    if( data->gtor )
175        tr_torrentVerify( tr_torrent_handle( data->gtor ) );
176}
177
178static void
179downloadDirChanged( GtkFileChooserButton * b, gpointer gdata )
180{
181    char * fname = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( b ) );
182    if( fname )
183    {
184        struct AddData * data = gdata;
185        g_free( data->downloadDir );
186        data->downloadDir = fname;
187
188        updateTorrent( data );
189        verifyRequested( NULL, data );
190    }
191}
192
193static void
194addTorrentFilters( GtkFileChooser * chooser )
195{
196    GtkFileFilter * filter;
197
198    filter = gtk_file_filter_new( );
199    gtk_file_filter_set_name( filter, _( "Torrent files" ) );
200    gtk_file_filter_add_pattern( filter, "*.torrent" );
201    gtk_file_chooser_add_filter( chooser, filter );
202
203    filter = gtk_file_filter_new( );
204    gtk_file_filter_set_name( filter, _( "All files" ) );
205    gtk_file_filter_add_pattern( filter, "*" );
206    gtk_file_chooser_add_filter( chooser, filter );
207}
208
209/****
210*****
211****/
212
213GtkWidget*
214addSingleTorrentDialog( GtkWindow  * parent,
215                        TrCore     * core,
216                        tr_ctor    * ctor )
217{
218    int row;
219    int col;
220    const char * str;
221    GtkWidget * w;
222    GtkWidget * d;
223    GtkWidget * t;
224    GtkWidget * l;
225    struct AddData * data;
226    uint8_t flag;
227    GSList * list;
228    GSList * walk;
229
230    /* make the dialog */
231    d = gtk_dialog_new_with_buttons( _( "Torrent Options" ), parent,
232            GTK_DIALOG_DESTROY_WITH_PARENT|GTK_DIALOG_NO_SEPARATOR,
233            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
234            GTK_STOCK_ADD, GTK_RESPONSE_ACCEPT,
235            NULL );
236    gtk_dialog_set_default_response( GTK_DIALOG( d ),
237                                     GTK_RESPONSE_ACCEPT );
238    gtk_dialog_set_alternative_button_order( GTK_DIALOG( d ),
239                                             GTK_RESPONSE_ACCEPT,
240                                             GTK_RESPONSE_CANCEL,
241                                             -1 );
242
243    if( tr_ctorGetDownloadDir( ctor, TR_FORCE, &str ) )
244        g_assert_not_reached( );
245    g_assert( str );
246
247    data = g_new0( struct AddData, 1 );
248    data->core = core;
249    data->ctor = ctor;
250    data->filename = g_strdup( tr_ctorGetSourceFile( ctor ) );
251    data->downloadDir = g_strdup( str );
252    data->list = file_list_new( NULL );
253    data->trash_check = gtk_check_button_new_with_mnemonic( _( "_Move source file to Trash" ) );
254    data->run_check = gtk_check_button_new_with_mnemonic( _( "_Start when added" ) );
255
256    g_signal_connect( G_OBJECT( d ), "response",
257                      G_CALLBACK( addResponseCB ), data );
258
259    t = gtk_table_new( 6, 2, FALSE );
260    gtk_container_set_border_width( GTK_CONTAINER( t ), GUI_PAD_BIG );
261    gtk_table_set_row_spacings( GTK_TABLE( t ), GUI_PAD );
262    gtk_table_set_col_spacings( GTK_TABLE( t ), GUI_PAD_BIG );
263
264    row = col = 0;
265    l = gtk_label_new_with_mnemonic( _( "_Torrent file:" ) );
266    gtk_misc_set_alignment( GTK_MISC( l ), 0.0f, 0.5f );
267    gtk_table_attach( GTK_TABLE( t ), l, col, col+1, row, row+1, GTK_FILL, 0, 0, 0 );
268    ++col;
269    w = gtk_file_chooser_button_new( _( "Select Source File" ),
270                                     GTK_FILE_CHOOSER_ACTION_OPEN );
271    gtk_table_attach( GTK_TABLE( t ), w, col, col+1, row, row+1, ~0, 0, 0, 0 );
272    gtk_label_set_mnemonic_widget( GTK_LABEL( l ), w );
273    addTorrentFilters( GTK_FILE_CHOOSER( w ) );
274    if( data->filename )
275        if( !gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( w ), data->filename ) )
276            g_warning( "couldn't select '%s'", data->filename );
277    g_signal_connect( w, "selection-changed",
278                      G_CALLBACK( sourceChanged ), data );
279
280    ++row;
281    col = 0;
282    l = gtk_label_new_with_mnemonic( _( "_Destination folder:" ) );
283    gtk_misc_set_alignment( GTK_MISC( l ), 0.0f, 0.5f );
284    gtk_table_attach( GTK_TABLE( t ), l, col, col+1, row, row+1, GTK_FILL, 0, 0, 0 );
285    ++col;
286    w = gtk_file_chooser_button_new( _( "Select Destination Folder" ), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER );
287    if( !gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( w ), data->downloadDir ) )
288        g_warning( "couldn't select '%s'", data->downloadDir );
289    list = get_recent_destinations( );
290    for( walk=list; walk; walk=walk->next )
291        gtk_file_chooser_add_shortcut_folder( GTK_FILE_CHOOSER( w ), walk->data, NULL );
292    g_slist_free( list );
293    gtk_table_attach( GTK_TABLE( t ), w, col, col+1, row, row+1, ~0, 0, 0, 0 );
294    gtk_label_set_mnemonic_widget( GTK_LABEL( l ), w );
295    g_signal_connect( w, "selection-changed", G_CALLBACK( downloadDirChanged ), data );
296
297    ++row;
298    col = 0;
299    w = data->list;
300    gtk_widget_set_size_request ( w, 466u, 300u );
301    gtk_table_attach_defaults( GTK_TABLE( t ), w, col, col+2, row, row+1 );
302
303    ++row;
304    col = 0;
305    w = gtk_button_new_with_mnemonic( _( "_Verify Local Data" ) );
306    gtk_table_attach( GTK_TABLE( t ), w, col, col+1, row, row+1, GTK_FILL, 0, 0, 0 );
307    g_signal_connect( w, "clicked", G_CALLBACK( verifyRequested ), data );
308
309    ++row;
310    col = 0;
311    w = data->run_check;
312    if( tr_ctorGetPaused( ctor, TR_FORCE, &flag ) )
313        g_assert_not_reached( );
314    gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( w ), !flag );
315    gtk_table_attach( GTK_TABLE( t ), w, col, col+2, row, row+1, GTK_FILL, 0, 0, 0 );
316
317    ++row;
318    col = 0;
319    w = data->trash_check;
320    if( tr_ctorGetDeleteSource( ctor, &flag ) )
321        g_assert_not_reached( );
322    gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( w ), flag );
323    gtk_table_attach( GTK_TABLE( t ), w, col, col+2, row, row+1, GTK_FILL, 0, 0, 0 );
324
325    gtk_box_pack_start_defaults( GTK_BOX( GTK_DIALOG( d )->vbox ), t );
326    gtk_widget_show_all( d );
327    return d;
328}
329
330/****
331*****
332****/
333
334static void
335onAddDialogResponse( GtkDialog * dialog, int response, gpointer core )
336{
337    char * folder;
338
339    /* remember this folder the next time we use this dialog */
340    folder = gtk_file_chooser_get_current_folder( GTK_FILE_CHOOSER( dialog ) );
341    pref_string_set( PREF_KEY_OPEN_DIALOG_FOLDER, folder );
342    g_free( folder );
343
344    if( response == GTK_RESPONSE_ACCEPT )
345    {
346        GtkWidget * w = gtk_file_chooser_get_extra_widget( GTK_FILE_CHOOSER( dialog ) );
347        const gboolean showOptions = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON ( w ) );
348        const pref_flag_t start = PREF_FLAG_DEFAULT;
349        const pref_flag_t prompt = showOptions ? PREF_FLAG_TRUE : PREF_FLAG_FALSE;
350        GSList * l = gtk_file_chooser_get_filenames( GTK_FILE_CHOOSER( dialog ) );
351        tr_core_add_list( core, l, start, prompt );
352    }
353
354    gtk_widget_destroy( GTK_WIDGET( dialog ) );
355}
356
357GtkWidget*
358addDialog( GtkWindow * parent,
359           TrCore    * core )
360{
361    GtkWidget * w;
362    GtkWidget * c;
363    const char * folder;
364
365    w = gtk_file_chooser_dialog_new( _( "Add a Torrent" ), parent,
366                                     GTK_FILE_CHOOSER_ACTION_OPEN,
367                                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
368                                     GTK_STOCK_ADD, GTK_RESPONSE_ACCEPT,
369                                     NULL );
370    gtk_dialog_set_alternative_button_order( GTK_DIALOG( w ),
371                                             GTK_RESPONSE_ACCEPT,
372                                             GTK_RESPONSE_CANCEL,
373                                             -1 );
374    gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER( w ), TRUE );
375    addTorrentFilters( GTK_FILE_CHOOSER( w ) );
376    g_signal_connect( w, "response", G_CALLBACK(onAddDialogResponse), core );
377
378    if(( folder = pref_string_get( PREF_KEY_OPEN_DIALOG_FOLDER )))
379        gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( w ), folder );
380
381    c = gtk_check_button_new_with_mnemonic( _( "Display _options dialog" ) );
382    gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( c ), pref_flag_get( PREF_KEY_OPTIONS_PROMPT ) );
383    gtk_file_chooser_set_extra_widget( GTK_FILE_CHOOSER( w ), c );
384    gtk_widget_show( c );
385
386    gtk_widget_show( w );
387    return w;
388}
Note: See TracBrowser for help on using the repository browser.