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

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

(gtk) #826: Transmission doesn't open torrents via web browser

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