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

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

(gtk) #1043: Include recent folders in the destination folder chooser

  • Property svn:keywords set to Date Rev Author Id
File size: 12.1 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 6278 2008-07-02 00:17:27Z 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    }
164
165    updateTorrent( data );
166}
167
168static void
169verifyRequested( GtkButton * button UNUSED, gpointer gdata )
170{
171    struct AddData * data = gdata;
172    if( data->gtor )
173        tr_torrentVerify( tr_torrent_handle( data->gtor ) );
174}
175
176static void
177downloadDirChanged( GtkFileChooserButton * b, gpointer gdata )
178{
179    char * fname = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( b ) );
180    if( fname )
181    {
182        struct AddData * data = gdata;
183        g_free( data->downloadDir );
184        data->downloadDir = fname;
185
186        updateTorrent( data );
187        verifyRequested( NULL, data );
188    }
189}
190
191static void
192addTorrentFilters( GtkFileChooser * chooser )
193{
194    GtkFileFilter * filter;
195
196    filter = gtk_file_filter_new( );
197    gtk_file_filter_set_name( filter, _( "Torrent files" ) );
198    gtk_file_filter_add_pattern( filter, "*.torrent" );
199    gtk_file_chooser_add_filter( chooser, filter );
200
201    filter = gtk_file_filter_new( );
202    gtk_file_filter_set_name( filter, _( "All files" ) );
203    gtk_file_filter_add_pattern( filter, "*" );
204    gtk_file_chooser_add_filter( chooser, filter );
205}
206
207/****
208*****
209****/
210
211GtkWidget*
212addSingleTorrentDialog( GtkWindow  * parent,
213                        TrCore     * core,
214                        tr_ctor    * ctor )
215{
216    int row;
217    int col;
218    const char * str;
219    GtkWidget * w;
220    GtkWidget * d;
221    GtkWidget * t;
222    GtkWidget * l;
223    struct AddData * data;
224    uint8_t flag;
225    GSList * list;
226    GSList * walk;
227
228    /* make the dialog */
229    d = gtk_dialog_new_with_buttons( _( "Torrent Options" ), parent,
230            GTK_DIALOG_DESTROY_WITH_PARENT|GTK_DIALOG_NO_SEPARATOR,
231            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
232            GTK_STOCK_ADD, GTK_RESPONSE_ACCEPT,
233            NULL );
234    gtk_dialog_set_default_response( GTK_DIALOG( d ),
235                                     GTK_RESPONSE_ACCEPT );
236    gtk_dialog_set_alternative_button_order( GTK_DIALOG( d ),
237                                             GTK_RESPONSE_ACCEPT,
238                                             GTK_RESPONSE_CANCEL,
239                                             -1 );
240
241    if( tr_ctorGetDownloadDir( ctor, TR_FORCE, &str ) )
242        g_assert_not_reached( );
243    g_assert( str );
244
245    data = g_new0( struct AddData, 1 );
246    data->core = core;
247    data->ctor = ctor;
248    data->filename = g_strdup( tr_ctorGetSourceFile( ctor ) );
249    data->downloadDir = g_strdup( str );
250    data->list = file_list_new( NULL );
251    data->trash_check = gtk_check_button_new_with_mnemonic( _( "Mo_ve source file to Trash" ) );
252    data->run_check = gtk_check_button_new_with_mnemonic( _( "_Start when added" ) );
253
254    g_signal_connect( G_OBJECT( d ), "response",
255                      G_CALLBACK( addResponseCB ), data );
256
257    t = gtk_table_new( 6, 2, FALSE );
258    gtk_container_set_border_width( GTK_CONTAINER( t ), GUI_PAD_BIG );
259    gtk_table_set_row_spacings( GTK_TABLE( t ), GUI_PAD );
260    gtk_table_set_col_spacings( GTK_TABLE( t ), GUI_PAD_BIG );
261
262    row = col = 0;
263    l = gtk_label_new_with_mnemonic( _( "_Source file:" ) );
264    gtk_misc_set_alignment( GTK_MISC( l ), 0.0f, 0.5f );
265    gtk_table_attach( GTK_TABLE( t ), l, col, col+1, row, row+1, GTK_FILL, 0, 0, 0 );
266    ++col;
267    w = gtk_file_chooser_button_new( _( "Select Source File" ),
268                                     GTK_FILE_CHOOSER_ACTION_OPEN );
269    gtk_table_attach( GTK_TABLE( t ), w, col, col+1, row, row+1, ~0, 0, 0, 0 );
270    gtk_label_set_mnemonic_widget( GTK_LABEL( l ), w );
271    addTorrentFilters( GTK_FILE_CHOOSER( w ) );
272    if( data->filename )
273        if( !gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( w ), data->filename ) )
274            g_warning( "couldn't select '%s'", data->filename );
275    g_signal_connect( w, "selection-changed",
276                      G_CALLBACK( sourceChanged ), data );
277
278    ++row;
279    col = 0;
280    l = gtk_label_new_with_mnemonic( _( "_Destination folder:" ) );
281    gtk_misc_set_alignment( GTK_MISC( l ), 0.0f, 0.5f );
282    gtk_table_attach( GTK_TABLE( t ), l, col, col+1, row, row+1, GTK_FILL, 0, 0, 0 );
283    ++col;
284    w = gtk_file_chooser_button_new( _( "Select Destination Folder" ), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER );
285    if( !gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( w ), data->downloadDir ) )
286        g_warning( "couldn't select '%s'", data->downloadDir );
287    list = get_recent_destinations( );
288    for( walk=list; walk; walk=walk->next )
289        gtk_file_chooser_add_shortcut_folder( GTK_FILE_CHOOSER( w ), walk->data, NULL );
290    g_slist_free( list );
291    gtk_table_attach( GTK_TABLE( t ), w, col, col+1, row, row+1, ~0, 0, 0, 0 );
292    gtk_label_set_mnemonic_widget( GTK_LABEL( l ), w );
293    g_signal_connect( w, "selection-changed", G_CALLBACK( downloadDirChanged ), data );
294
295    ++row;
296    col = 0;
297    w = data->list;
298    gtk_widget_set_size_request ( w, 466u, 300u );
299    gtk_table_attach_defaults( GTK_TABLE( t ), w, col, col+2, row, row+1 );
300
301    ++row;
302    col = 0;
303    w = gtk_button_new_with_mnemonic( _( "Verify Local Data" ) );
304    gtk_table_attach( GTK_TABLE( t ), w, col, col+1, row, row+1, GTK_FILL, 0, 0, 0 );
305    g_signal_connect( w, "clicked", G_CALLBACK( verifyRequested ), data );
306
307    ++row;
308    col = 0;
309    w = data->run_check;
310    if( tr_ctorGetPaused( ctor, TR_FORCE, &flag ) )
311        g_assert_not_reached( );
312    gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( w ), !flag );
313    gtk_table_attach( GTK_TABLE( t ), w, col, col+2, row, row+1, GTK_FILL, 0, 0, 0 );
314
315    ++row;
316    col = 0;
317    w = data->trash_check;
318    if( tr_ctorGetDeleteSource( ctor, &flag ) )
319        g_assert_not_reached( );
320    gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( w ), flag );
321    gtk_table_attach( GTK_TABLE( t ), w, col, col+2, row, row+1, GTK_FILL, 0, 0, 0 );
322
323    gtk_box_pack_start_defaults( GTK_BOX( GTK_DIALOG( d )->vbox ), t );
324    gtk_widget_show_all( d );
325    return d;
326}
327
328/****
329*****
330****/
331
332static void
333onAddDialogResponse( GtkDialog * dialog, int response, gpointer core )
334{
335    char * folder;
336
337    /* remember this folder the next time we use this dialog */
338    folder = gtk_file_chooser_get_current_folder( GTK_FILE_CHOOSER( dialog ) );
339    pref_string_set( PREF_KEY_OPEN_DIALOG_FOLDER, folder );
340    g_free( folder );
341
342    if( response == GTK_RESPONSE_ACCEPT )
343    {
344        GtkWidget * w = gtk_file_chooser_get_extra_widget( GTK_FILE_CHOOSER( dialog ) );
345        const gboolean showOptions = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON ( w ) );
346        const pref_flag_t start = PREF_FLAG_DEFAULT;
347        const pref_flag_t prompt = showOptions ? PREF_FLAG_TRUE : PREF_FLAG_FALSE;
348        GSList * l = gtk_file_chooser_get_filenames( GTK_FILE_CHOOSER( dialog ) );
349        tr_core_add_list( core, l, start, prompt );
350    }
351
352    gtk_widget_destroy( GTK_WIDGET( dialog ) );
353}
354
355GtkWidget*
356addDialog( GtkWindow * parent,
357           TrCore    * core )
358{
359    GtkWidget * w;
360    GtkWidget * c;
361    const char * folder;
362
363    w = gtk_file_chooser_dialog_new( _( "Add a Torrent" ), parent,
364                                     GTK_FILE_CHOOSER_ACTION_OPEN,
365                                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
366                                     GTK_STOCK_ADD, GTK_RESPONSE_ACCEPT,
367                                     NULL );
368    gtk_dialog_set_alternative_button_order( GTK_DIALOG( w ),
369                                             GTK_RESPONSE_ACCEPT,
370                                             GTK_RESPONSE_CANCEL,
371                                             -1 );
372    gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER( w ), TRUE );
373    addTorrentFilters( GTK_FILE_CHOOSER( w ) );
374    g_signal_connect( w, "response", G_CALLBACK(onAddDialogResponse), core );
375
376    if(( folder = pref_string_get( PREF_KEY_OPEN_DIALOG_FOLDER )))
377        gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( w ), folder );
378
379    c = gtk_check_button_new_with_mnemonic( _( "Display _options dialog" ) );
380    gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( c ), pref_flag_get( PREF_KEY_OPTIONS_PROMPT ) );
381    gtk_file_chooser_set_extra_widget( GTK_FILE_CHOOSER( w ), c );
382    gtk_widget_show( c );
383
384    gtk_widget_show( w );
385    return w;
386}
Note: See TracBrowser for help on using the repository browser.