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

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

(gtk) don't use code marked as deprecated in gtk 2.14

  • Property svn:keywords set to Date Rev Author Id
File size: 14.4 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 6998 2008-10-31 18:25:21Z 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( 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( );
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_set_torrent( data->list, NULL );
102
103        tr_torrent_set_remove_flag( data->gtor, TRUE );
104        g_object_unref( G_OBJECT( data->gtor ) );
105        data->gtor = NULL;
106    }
107}
108
109static void
110addResponseCB( GtkDialog * dialog,
111               gint        response,
112               gpointer    gdata )
113{
114    struct AddData * data = gdata;
115
116    if( data->gtor )
117    {
118        if( response != GTK_RESPONSE_ACCEPT )
119            removeOldTorrent( data );
120        else
121        {
122            if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( data->
123                                                                 run_check ) ) )
124                tr_torrentStart( tr_torrent_handle( data->gtor ) );
125            tr_core_add_torrent( data->core, data->gtor );
126            if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( data->
127                                                                 trash_check ) ) )
128                tr_file_trash_or_unlink( data->filename );
129            save_recent_destination( data->downloadDir );
130        }
131    }
132
133    tr_ctorFree( data->ctor );
134    g_free( data->filename );
135    g_free( data->downloadDir );
136    g_free( data );
137    gtk_widget_destroy( GTK_WIDGET( dialog ) );
138}
139
140static void
141updateTorrent( struct AddData * o )
142{
143    if( o->gtor )
144        tr_torrentSetDownloadDir( tr_torrent_handle(
145                                      o->gtor ), o->downloadDir );
146
147    file_list_set_torrent( o->list, o->gtor );
148}
149
150/**
151 * When the source .torrent file is deleted
152 * (such as, if it was a temp file that a web browser passed to us),
153 * gtk invokes this callback and `filename' will be NULL.
154 * The `filename' tests here are to prevent us from losing the current
155 * metadata when that happens.
156 */
157static void
158sourceChanged( GtkFileChooserButton * b,
159               gpointer               gdata )
160{
161    struct AddData * data = gdata;
162    char *           filename = gtk_file_chooser_get_filename(
163         GTK_FILE_CHOOSER( b ) );
164
165    /* maybe instantiate a torrent */
166    if( data->filename || !data->gtor )
167    {
168        int          err = 0;
169        int          new_file = 0;
170        tr_torrent * torrent;
171        tr_session * session = tr_core_session( data->core );
172
173        if( filename
174          && ( !data->filename || strcmp( filename, data->filename ) ) )
175        {
176            g_free( data->filename );
177            data->filename = g_strdup( filename );
178            tr_ctorSetMetainfoFromFile( data->ctor, data->filename );
179            new_file = 1;
180        }
181
182        tr_ctorSetDownloadDir( data->ctor, TR_FORCE, data->downloadDir );
183        tr_ctorSetPaused( data->ctor, TR_FORCE, TRUE );
184        tr_ctorSetDeleteSource( data->ctor, FALSE );
185
186        if( ( torrent = tr_torrentNew( session, data->ctor, &err ) ) )
187        {
188            removeOldTorrent( data );
189            data->gtor = tr_torrent_new_preexisting( torrent );
190        }
191        else if( new_file )
192        {
193            addTorrentErrorDialog( GTK_WIDGET( b ), err, data->filename );
194        }
195
196        updateTorrent( data );
197    }
198
199    g_free( filename );
200}
201
202static void
203verifyRequested( GtkButton * button UNUSED,
204                 gpointer           gdata )
205{
206    struct AddData * data = gdata;
207
208    if( data->gtor )
209        tr_torrentVerify( tr_torrent_handle( data->gtor ) );
210}
211
212static void
213downloadDirChanged( GtkFileChooserButton * b,
214                    gpointer               gdata )
215{
216    char *           fname = gtk_file_chooser_get_filename(
217         GTK_FILE_CHOOSER( b ) );
218    struct AddData * data = gdata;
219
220    if( fname && ( !data->downloadDir || strcmp( fname, data->downloadDir ) ) )
221    {
222        g_free( data->downloadDir );
223        data->downloadDir = g_strdup( fname );
224
225        updateTorrent( data );
226        verifyRequested( NULL, data );
227    }
228
229    g_free( fname );
230}
231
232static void
233addTorrentFilters( GtkFileChooser * chooser )
234{
235    GtkFileFilter * filter;
236
237    filter = gtk_file_filter_new( );
238    gtk_file_filter_set_name( filter, _( "Torrent files" ) );
239    gtk_file_filter_add_pattern( filter, "*.torrent" );
240    gtk_file_chooser_add_filter( chooser, filter );
241
242    filter = gtk_file_filter_new( );
243    gtk_file_filter_set_name( filter, _( "All files" ) );
244    gtk_file_filter_add_pattern( filter, "*" );
245    gtk_file_chooser_add_filter( chooser, filter );
246}
247
248/****
249*****
250****/
251
252GtkWidget*
253addSingleTorrentDialog( GtkWindow * parent,
254                        TrCore *    core,
255                        tr_ctor *   ctor )
256{
257    int              row;
258    int              col;
259    const char *     str;
260    GtkWidget *      w;
261    GtkWidget *      d;
262    GtkWidget *      t;
263    GtkWidget *      l;
264    struct AddData * data;
265    uint8_t          flag;
266    GSList *         list;
267    GSList *         walk;
268
269    /* make the dialog */
270    d = gtk_dialog_new_with_buttons( _(
271                                         "Torrent Options" ), parent,
272                                     GTK_DIALOG_DESTROY_WITH_PARENT |
273                                     GTK_DIALOG_NO_SEPARATOR,
274                                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
275                                     GTK_STOCK_ADD, GTK_RESPONSE_ACCEPT,
276                                     NULL );
277    gtk_dialog_set_default_response( GTK_DIALOG( d ),
278                                     GTK_RESPONSE_ACCEPT );
279    gtk_dialog_set_alternative_button_order( GTK_DIALOG( d ),
280                                             GTK_RESPONSE_ACCEPT,
281                                             GTK_RESPONSE_CANCEL,
282                                             -1 );
283
284    if( tr_ctorGetDownloadDir( ctor, TR_FORCE, &str ) )
285        g_assert_not_reached( );
286    g_assert( str );
287
288    data = g_new0( struct AddData, 1 );
289    data->core = core;
290    data->ctor = ctor;
291    data->filename = g_strdup( tr_ctorGetSourceFile( ctor ) );
292    data->downloadDir = g_strdup( str );
293    data->list = file_list_new( NULL );
294    data->trash_check =
295        gtk_check_button_new_with_mnemonic( _( "_Move source file to Trash" ) );
296    data->run_check =
297        gtk_check_button_new_with_mnemonic( _( "_Start when added" ) );
298
299    g_signal_connect( G_OBJECT( d ), "response",
300                      G_CALLBACK( addResponseCB ), data );
301
302    t = gtk_table_new( 6, 2, FALSE );
303    gtk_container_set_border_width( GTK_CONTAINER( t ), GUI_PAD_BIG );
304    gtk_table_set_row_spacings( GTK_TABLE( t ), GUI_PAD );
305    gtk_table_set_col_spacings( GTK_TABLE( t ), GUI_PAD_BIG );
306
307    row = col = 0;
308    l = gtk_label_new_with_mnemonic( _( "_Torrent file:" ) );
309    gtk_misc_set_alignment( GTK_MISC( l ), 0.0f, 0.5f );
310    gtk_table_attach( GTK_TABLE(
311                          t ), l, col, col + 1, row, row + 1, GTK_FILL, 0,
312                      0, 0 );
313    ++col;
314    w = gtk_file_chooser_button_new( _( "Select Source File" ),
315                                     GTK_FILE_CHOOSER_ACTION_OPEN );
316    gtk_table_attach( GTK_TABLE(
317                          t ), w, col, col + 1, row, row + 1, ~0, 0, 0, 0 );
318    gtk_label_set_mnemonic_widget( GTK_LABEL( l ), w );
319    addTorrentFilters( GTK_FILE_CHOOSER( w ) );
320    if( data->filename )
321        if( !gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( w ),
322                                            data->filename ) )
323            g_warning( "couldn't select '%s'", data->filename );
324    g_signal_connect( w, "selection-changed",
325                      G_CALLBACK( sourceChanged ), data );
326
327    ++row;
328    col = 0;
329    l = gtk_label_new_with_mnemonic( _( "_Destination folder:" ) );
330    gtk_misc_set_alignment( GTK_MISC( l ), 0.0f, 0.5f );
331    gtk_table_attach( GTK_TABLE(
332                          t ), l, col, col + 1, row, row + 1, GTK_FILL, 0,
333                      0, 0 );
334    ++col;
335    w = gtk_file_chooser_button_new( _(
336                                         "Select Destination Folder" ),
337                                     GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER );
338    if( !gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( w ),
339                                        data->downloadDir ) )
340        g_warning( "couldn't select '%s'", data->downloadDir );
341    list = get_recent_destinations( );
342    for( walk = list; walk; walk = walk->next )
343        gtk_file_chooser_add_shortcut_folder( GTK_FILE_CHOOSER(
344                                                  w ), walk->data, NULL );
345    g_slist_free( list );
346    gtk_table_attach( GTK_TABLE(
347                          t ), w, col, col + 1, row, row + 1, ~0, 0, 0, 0 );
348    gtk_label_set_mnemonic_widget( GTK_LABEL( l ), w );
349    g_signal_connect( w, "selection-changed",
350                      G_CALLBACK( downloadDirChanged ), data );
351
352    ++row;
353    col = 0;
354    w = data->list;
355    gtk_widget_set_size_request ( w, 466u, 300u );
356    gtk_table_attach_defaults( GTK_TABLE(
357                                   t ), w, col, col + 2, row, row + 1 );
358
359    ++row;
360    col = 0;
361    w = gtk_button_new_with_mnemonic( _( "_Verify Local Data" ) );
362    gtk_table_attach( GTK_TABLE(
363                          t ), w, col, col + 1, row, row + 1, GTK_FILL, 0,
364                      0, 0 );
365    g_signal_connect( w, "clicked", G_CALLBACK( verifyRequested ), data );
366
367    ++row;
368    col = 0;
369    w = data->run_check;
370    if( tr_ctorGetPaused( ctor, TR_FORCE, &flag ) )
371        g_assert_not_reached( );
372    gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( w ), !flag );
373    gtk_table_attach( GTK_TABLE(
374                          t ), w, col, col + 2, row, row + 1, GTK_FILL, 0,
375                      0, 0 );
376
377    ++row;
378    col = 0;
379    w = data->trash_check;
380    if( tr_ctorGetDeleteSource( ctor, &flag ) )
381        g_assert_not_reached( );
382    gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( w ), flag );
383    gtk_table_attach( GTK_TABLE(
384                          t ), w, col, col + 2, row, row + 1, GTK_FILL, 0,
385                      0, 0 );
386
387    gtk_box_pack_start( GTK_BOX( GTK_DIALOG( d )->vbox ), t, TRUE, TRUE, 0 );
388    gtk_widget_show_all( d );
389    return d;
390}
391
392/****
393*****
394****/
395
396static void
397onAddDialogResponse( GtkDialog * dialog,
398                     int         response,
399                     gpointer    core )
400{
401    char * folder;
402
403    /* remember this folder the next time we use this dialog */
404    folder = gtk_file_chooser_get_current_folder( GTK_FILE_CHOOSER( dialog ) );
405    pref_string_set( PREF_KEY_OPEN_DIALOG_FOLDER, folder );
406    g_free( folder );
407
408    if( response == GTK_RESPONSE_ACCEPT )
409    {
410        GtkFileChooser  * chooser = GTK_FILE_CHOOSER( dialog );
411        GtkWidget       * w = gtk_file_chooser_get_extra_widget( chooser );
412        GtkToggleButton * tb = GTK_TOGGLE_BUTTON( w );
413        const gboolean    showOptions = gtk_toggle_button_get_active( tb );
414        const pref_flag_t start = PREF_FLAG_DEFAULT;
415        const pref_flag_t prompt = showOptions
416                                 ? PREF_FLAG_TRUE
417                                 : PREF_FLAG_FALSE;
418        GSList * l = gtk_file_chooser_get_filenames( chooser );
419
420        tr_core_add_list( core, l, start, prompt );
421    }
422
423    gtk_widget_destroy( GTK_WIDGET( dialog ) );
424}
425
426GtkWidget*
427addDialog( GtkWindow * parent,
428           TrCore *    core )
429{
430    GtkWidget *  w;
431    GtkWidget *  c;
432    const char * folder;
433
434    w = gtk_file_chooser_dialog_new( _( "Add a Torrent" ), parent,
435                                     GTK_FILE_CHOOSER_ACTION_OPEN,
436                                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
437                                     GTK_STOCK_ADD, GTK_RESPONSE_ACCEPT,
438                                     NULL );
439    gtk_dialog_set_alternative_button_order( GTK_DIALOG( w ),
440                                             GTK_RESPONSE_ACCEPT,
441                                             GTK_RESPONSE_CANCEL,
442                                             -1 );
443    gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER( w ), TRUE );
444    addTorrentFilters( GTK_FILE_CHOOSER( w ) );
445    g_signal_connect( w, "response", G_CALLBACK(
446                          onAddDialogResponse ), core );
447
448    if( ( folder = pref_string_get( PREF_KEY_OPEN_DIALOG_FOLDER ) ) )
449        gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( w ), folder );
450
451    c = gtk_check_button_new_with_mnemonic( _( "Display _options dialog" ) );
452    gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( c ),
453                                 pref_flag_get( PREF_KEY_OPTIONS_PROMPT ) );
454    gtk_file_chooser_set_extra_widget( GTK_FILE_CHOOSER( w ), c );
455    gtk_widget_show( c );
456
457    gtk_widget_show( w );
458    return w;
459}
460
Note: See TracBrowser for help on using the repository browser.