transmission: update from 2.13 to 2.22
[tomato.git] / release / src / router / transmission / gtk / open-dialog.c
bloba1411e624a929a62fe2453f0d392a5c557e433b3
1 /*
2 * This file Copyright (C) Mnemosyne LLC
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.
10 * $Id: open-dialog.c 11721 2011-01-20 19:57:42Z jordan $
13 #include <glib/gi18n.h>
14 #include <gtk/gtk.h>
16 #include <string.h>
18 #include <libtransmission/transmission.h>
19 #include <libtransmission/utils.h> /* tr_is_same_file() */
21 #include "conf.h"
22 #include "file-list.h"
23 #include "hig.h"
24 #include "open-dialog.h"
25 #include "tr-prefs.h"
27 /****
28 *****
29 ****/
31 #define N_RECENT 4
33 static GSList*
34 get_recent_destinations( void )
36 int i;
37 GSList * list = NULL;
39 for( i=0; i<N_RECENT; ++i )
41 char key[64];
42 const char * val;
43 g_snprintf( key, sizeof( key ), "recent-download-dir-%d", i+1 );
44 if(( val = gtr_pref_string_get( key )))
45 list = g_slist_append( list, (void*)val );
47 return list;
50 static void
51 save_recent_destination( TrCore * core, const char * dir )
53 int i;
54 GSList * l;
55 GSList * list = get_recent_destinations( );
57 if( dir == NULL )
58 return;
60 /* if it was already in the list, remove it */
61 if(( l = g_slist_find_custom( list, dir, (GCompareFunc)strcmp )))
62 list = g_slist_delete_link( list, l );
64 /* add it to the front of the list */
65 list = g_slist_prepend( list, (void*)dir );
67 /* make local copies of the strings that aren't
68 * invalidated by gtr_pref_string_set() */
69 for( l=list; l; l=l->next )
70 l->data = g_strdup( l->data );
72 /* save the first N_RECENT directories */
73 for( l=list, i=0; l && ( i<N_RECENT ); ++i, l=l->next ) {
74 char key[64];
75 g_snprintf( key, sizeof( key ), "recent-download-dir-%d", i + 1 );
76 gtr_pref_string_set( key, l->data );
78 gtr_pref_save( tr_core_session( core ) );
80 /* cleanup */
81 g_slist_foreach( list, (GFunc)g_free, NULL );
82 g_slist_free( list );
85 /****
86 *****
87 ****/
89 struct OpenData
91 TrCore * core;
92 GtkWidget * file_list;
93 GtkWidget * run_check;
94 GtkWidget * trash_check;
95 GtkWidget * priority_combo;
96 char * filename;
97 char * downloadDir;
98 TrTorrent * gtor;
99 tr_ctor * ctor;
102 static void
103 removeOldTorrent( struct OpenData * data )
105 if( data->gtor )
107 gtr_file_list_clear( data->file_list );
108 tr_torrent_set_remove_flag( data->gtor, TRUE );
109 g_object_unref( G_OBJECT( data->gtor ) );
110 data->gtor = NULL;
114 static void
115 addResponseCB( GtkDialog * dialog,
116 gint response,
117 gpointer gdata )
119 struct OpenData * data = gdata;
121 if( data->gtor )
123 if( response != GTK_RESPONSE_ACCEPT )
125 removeOldTorrent( data );
127 else
129 tr_torrent * tor = tr_torrent_handle( data->gtor );
131 tr_torrentSetPriority( tor, gtr_priority_combo_get_value( GTK_COMBO_BOX( data->priority_combo ) ) );
133 if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( data->run_check ) ) )
134 tr_torrentStart( tor );
136 tr_core_add_torrent( data->core, data->gtor, FALSE );
138 if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( data->trash_check ) ) )
139 gtr_file_trash_or_remove( data->filename );
141 save_recent_destination( data->core, data->downloadDir );
145 tr_ctorFree( data->ctor );
146 g_free( data->filename );
147 g_free( data->downloadDir );
148 g_free( data );
149 gtk_widget_destroy( GTK_WIDGET( dialog ) );
152 static void
153 updateTorrent( struct OpenData * o )
155 const gboolean isLocalFile = tr_ctorGetSourceFile( o->ctor ) != NULL;
156 gtk_widget_set_sensitive( o->trash_check, isLocalFile );
158 if( !o->gtor )
160 gtr_file_list_clear( o->file_list );
161 gtk_widget_set_sensitive( o->file_list, FALSE );
163 else
165 tr_torrent * tor = tr_torrent_handle( o->gtor );
166 tr_torrentSetDownloadDir( tor, o->downloadDir );
167 gtk_widget_set_sensitive( o->file_list, tr_torrentHasMetadata( tor ) );
168 gtr_file_list_set_torrent( o->file_list, tr_torrentId( tor ) );
169 tr_torrentVerify( tor );
174 * When the source .torrent file is deleted
175 * (such as, if it was a temp file that a web browser passed to us),
176 * gtk invokes this callback and `filename' will be NULL.
177 * The `filename' tests here are to prevent us from losing the current
178 * metadata when that happens.
180 static void
181 sourceChanged( GtkFileChooserButton * b, gpointer gdata )
183 struct OpenData * data = gdata;
184 char * filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( b ) );
186 /* maybe instantiate a torrent */
187 if( filename || !data->gtor )
189 int err = 0;
190 int new_file = 0;
191 tr_torrent * torrent;
193 if( filename && ( !data->filename || !tr_is_same_file( filename, data->filename ) ) )
195 g_free( data->filename );
196 data->filename = g_strdup( filename );
197 tr_ctorSetMetainfoFromFile( data->ctor, data->filename );
198 new_file = 1;
201 tr_ctorSetDownloadDir( data->ctor, TR_FORCE, data->downloadDir );
202 tr_ctorSetPaused( data->ctor, TR_FORCE, TRUE );
203 tr_ctorSetDeleteSource( data->ctor, FALSE );
205 if( ( torrent = tr_torrentNew( data->ctor, &err ) ) )
207 removeOldTorrent( data );
208 data->gtor = tr_torrent_new_preexisting( torrent );
210 else if( new_file )
212 gtr_add_torrent_error_dialog( GTK_WIDGET( b ), err, data->filename );
215 updateTorrent( data );
218 g_free( filename );
221 static void
222 downloadDirChanged( GtkFileChooserButton * b, gpointer gdata )
224 struct OpenData * data = gdata;
225 char * fname = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( b ) );
227 if( fname && ( !data->downloadDir || !tr_is_same_file( fname, data->downloadDir ) ) )
229 g_free( data->downloadDir );
230 data->downloadDir = g_strdup( fname );
231 updateTorrent( data );
234 g_free( fname );
237 static void
238 addTorrentFilters( GtkFileChooser * chooser )
240 GtkFileFilter * filter;
242 filter = gtk_file_filter_new( );
243 gtk_file_filter_set_name( filter, _( "Torrent files" ) );
244 gtk_file_filter_add_pattern( filter, "*.torrent" );
245 gtk_file_chooser_add_filter( chooser, filter );
247 filter = gtk_file_filter_new( );
248 gtk_file_filter_set_name( filter, _( "All files" ) );
249 gtk_file_filter_add_pattern( filter, "*" );
250 gtk_file_chooser_add_filter( chooser, filter );
253 /****
254 *****
255 ****/
257 GtkWidget*
258 gtr_torrent_options_dialog_new( GtkWindow * parent, TrCore * core, tr_ctor * ctor )
260 int row;
261 int col;
262 const char * str;
263 GtkWidget * w;
264 GtkWidget * d;
265 GtkWidget * t;
266 GtkWidget * l;
267 GtkWidget * grab;
268 GtkWidget * source_chooser;
269 struct OpenData * data;
270 uint8_t flag;
271 GSList * list;
272 GSList * walk;
274 /* make the dialog */
275 d = gtk_dialog_new_with_buttons( _( "Torrent Options" ), parent,
276 GTK_DIALOG_DESTROY_WITH_PARENT,
277 NULL );
278 gtk_dialog_add_button( GTK_DIALOG( d ), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL );
279 grab = gtk_dialog_add_button( GTK_DIALOG( d ), GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT );
280 gtk_dialog_set_default_response( GTK_DIALOG( d ),
281 GTK_RESPONSE_ACCEPT );
282 gtk_dialog_set_alternative_button_order( GTK_DIALOG( d ),
283 GTK_RESPONSE_ACCEPT,
284 GTK_RESPONSE_CANCEL,
285 -1 );
287 if( tr_ctorGetDownloadDir( ctor, TR_FORCE, &str ) )
288 g_assert_not_reached( );
289 g_assert( str );
291 data = g_new0( struct OpenData, 1 );
292 data->core = core;
293 data->ctor = ctor;
294 data->filename = g_strdup( tr_ctorGetSourceFile( ctor ) );
295 data->downloadDir = g_strdup( str );
296 data->file_list = gtr_file_list_new( core, 0 );
297 str = _( "Mo_ve .torrent file to the trash" );
298 data->trash_check = gtk_check_button_new_with_mnemonic( str );
299 str = _( "_Start when added" );
300 data->run_check = gtk_check_button_new_with_mnemonic( str );
302 w = data->priority_combo = gtr_priority_combo_new( );
303 gtr_priority_combo_set_value( GTK_COMBO_BOX( w ), TR_PRI_NORMAL );
305 g_signal_connect( G_OBJECT( d ), "response",
306 G_CALLBACK( addResponseCB ), data );
308 t = gtk_table_new( 6, 2, FALSE );
309 gtk_container_set_border_width( GTK_CONTAINER( t ), GUI_PAD_BIG );
310 gtk_table_set_row_spacings( GTK_TABLE( t ), GUI_PAD );
311 gtk_table_set_col_spacings( GTK_TABLE( t ), GUI_PAD_BIG );
313 row = col = 0;
314 l = gtk_label_new_with_mnemonic( _( "_Torrent file:" ) );
315 gtk_misc_set_alignment( GTK_MISC( l ), 0.0f, 0.5f );
316 gtk_table_attach( GTK_TABLE( t ), l, col, col + 1, row, row + 1, GTK_FILL, 0, 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( t ), w, col, col + 1, row, row + 1, ~0, 0, 0, 0 );
322 gtk_label_set_mnemonic_widget( GTK_LABEL( l ), w );
323 addTorrentFilters( GTK_FILE_CHOOSER( w ) );
324 g_signal_connect( w, "selection-changed",
325 G_CALLBACK( sourceChanged ), data );
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( t ), l, col, col + 1, row, row + 1, GTK_FILL, 0, 0, 0 );
332 ++col;
333 w = gtk_file_chooser_button_new( _( "Select Destination Folder" ),
334 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER );
335 if( !gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( w ),
336 data->downloadDir ) )
337 g_warning( "couldn't select '%s'", data->downloadDir );
338 list = get_recent_destinations( );
339 for( walk = list; walk; walk = walk->next )
340 gtk_file_chooser_add_shortcut_folder( GTK_FILE_CHOOSER( w ), walk->data, NULL );
341 g_slist_free( list );
342 gtk_table_attach( GTK_TABLE( t ), w, col, col + 1, row, row + 1, ~0, 0, 0, 0 );
343 gtk_label_set_mnemonic_widget( GTK_LABEL( l ), w );
344 g_signal_connect( w, "selection-changed",
345 G_CALLBACK( downloadDirChanged ), data );
347 ++row;
348 col = 0;
349 w = data->file_list;
350 gtk_widget_set_size_request ( w, 466u, 300u );
351 gtk_table_attach_defaults( GTK_TABLE( t ), w, col, col + 2, row, row + 1 );
353 ++row;
354 col = 0;
355 w = gtk_label_new_with_mnemonic( _( "Torrent _priority:" ) );
356 gtk_misc_set_alignment( GTK_MISC( w ), 0.0f, 0.5f );
357 gtk_table_attach( GTK_TABLE( t ), w, col, col + 1, row, row + 1, ~0, 0, 0, 0 );
358 ++col;
359 gtk_table_attach( GTK_TABLE( t ), data->priority_combo, col, col + 1, row, row + 1, ~0, 0, 0, 0 );
360 gtk_label_set_mnemonic_widget( GTK_LABEL( w ), data->priority_combo );
362 ++row;
363 col = 0;
364 w = data->run_check;
365 if( tr_ctorGetPaused( ctor, TR_FORCE, &flag ) )
366 g_assert_not_reached( );
367 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( w ), !flag );
368 gtk_table_attach( GTK_TABLE( t ), w, col, col + 2, row, row + 1, GTK_FILL, 0, 0, 0 );
370 ++row;
371 col = 0;
372 w = data->trash_check;
373 if( tr_ctorGetDeleteSource( ctor, &flag ) )
374 g_assert_not_reached( );
375 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( w ), flag );
376 gtk_table_attach( GTK_TABLE( t ), w, col, col + 2, row, row + 1, GTK_FILL, 0, 0, 0 );
378 /* trigger sourceChanged, either directly or indirectly,
379 * so that it creates the tor/gtor objects */
380 w = source_chooser;
381 if( data->filename )
382 gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( w ), data->filename );
383 else
384 sourceChanged( GTK_FILE_CHOOSER_BUTTON( w ), data );
386 gtr_dialog_set_content( GTK_DIALOG( d ), t );
387 gtk_widget_grab_focus( grab );
388 return d;
391 /****
392 *****
393 ****/
395 static void
396 onOpenDialogResponse( GtkDialog * dialog, int response, gpointer core )
398 char * folder;
400 /* remember this folder the next time we use this dialog */
401 folder = gtk_file_chooser_get_current_folder( GTK_FILE_CHOOSER( dialog ) );
402 gtr_pref_string_set( PREF_KEY_OPEN_DIALOG_FOLDER, folder );
403 g_free( folder );
405 if( response == GTK_RESPONSE_ACCEPT )
407 GtkFileChooser * chooser = GTK_FILE_CHOOSER( dialog );
408 GtkWidget * w = gtk_file_chooser_get_extra_widget( chooser );
409 GtkToggleButton * tb = GTK_TOGGLE_BUTTON( w );
410 const gboolean doStart = gtr_pref_flag_get( TR_PREFS_KEY_START );
411 const gboolean doPrompt = gtk_toggle_button_get_active( tb );
412 const gboolean doNotify = FALSE;
413 GSList * l = gtk_file_chooser_get_filenames( chooser );
415 tr_core_add_list( core, l, doStart, doPrompt, doNotify );
418 gtk_widget_destroy( GTK_WIDGET( dialog ) );
421 GtkWidget*
422 gtr_torrent_open_from_file_dialog_new( GtkWindow * parent, TrCore * core )
424 GtkWidget * w;
425 GtkWidget * c;
426 const char * folder;
428 w = gtk_file_chooser_dialog_new( _( "Open a Torrent" ), parent,
429 GTK_FILE_CHOOSER_ACTION_OPEN,
430 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
431 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
432 NULL );
433 gtk_dialog_set_alternative_button_order( GTK_DIALOG( w ),
434 GTK_RESPONSE_ACCEPT,
435 GTK_RESPONSE_CANCEL,
436 -1 );
437 gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER( w ), TRUE );
438 addTorrentFilters( GTK_FILE_CHOOSER( w ) );
439 g_signal_connect( w, "response", G_CALLBACK( onOpenDialogResponse ), core );
441 if( ( folder = gtr_pref_string_get( PREF_KEY_OPEN_DIALOG_FOLDER ) ) )
442 gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( w ), folder );
444 c = gtk_check_button_new_with_mnemonic( _( "Show _options dialog" ) );
445 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( c ),
446 gtr_pref_flag_get( PREF_KEY_OPTIONS_PROMPT ) );
447 gtk_file_chooser_set_extra_widget( GTK_FILE_CHOOSER( w ), c );
448 gtk_widget_show( c );
450 return w;
453 /***
454 ****
455 ***/
457 static void
458 onOpenURLResponse( GtkDialog * dialog, int response, gpointer user_data )
460 gboolean destroy = TRUE;
462 if( response == GTK_RESPONSE_ACCEPT )
464 GtkWidget * e = GTK_WIDGET( g_object_get_data( G_OBJECT( dialog ), "url-entry" ) );
465 char * url = g_strdup( gtk_entry_get_text( GTK_ENTRY( e ) ) );
466 g_strstrip( url );
468 if( url && *url )
470 TrCore * core = user_data;
472 if( gtr_is_supported_url( url ) || gtr_is_magnet_link( url )
473 || gtr_is_hex_hashcode( url ) )
475 tr_core_add_from_url( core, url );
477 else
479 gtr_unrecognized_url_dialog( GTK_WIDGET( dialog ), url );
480 destroy = FALSE;
484 g_free( url );
487 if( destroy )
488 gtk_widget_destroy( GTK_WIDGET( dialog ) );
491 GtkWidget*
492 gtr_torrent_open_from_url_dialog_new( GtkWindow * parent, TrCore * core )
494 int row;
495 GtkWidget * e;
496 GtkWidget * t;
497 GtkWidget * w;
499 w = gtk_dialog_new_with_buttons( _( "Open URL" ), parent,
500 GTK_DIALOG_DESTROY_WITH_PARENT,
501 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
502 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
503 NULL );
504 gtk_dialog_set_alternative_button_order( GTK_DIALOG( w ),
505 GTK_RESPONSE_ACCEPT,
506 GTK_RESPONSE_CANCEL,
507 -1 );
508 g_signal_connect( w, "response", G_CALLBACK( onOpenURLResponse ), core );
510 row = 0;
511 t = hig_workarea_create( );
512 hig_workarea_add_section_title( t, &row, _( "Open torrent from URL" ) );
513 e = gtk_entry_new( );
514 gtk_widget_set_size_request( e, 400, -1 );
515 gtr_paste_clipboard_url_into_entry( e );
516 g_object_set_data( G_OBJECT( w ), "url-entry", e );
517 hig_workarea_add_row( t, &row, _( "_URL" ), e, NULL );
519 gtr_dialog_set_content( GTK_DIALOG( w ), t );
520 return w;