Revert "transmission: update from 2.13 to 2.22"
[tomato.git] / release / src / router / transmission / gtk / add-dialog.c
blobee9abf76413d8c5fd11e2fa16b4031ea81ef8710
1 /*
2 * This file Copyright (C) 2008-2010 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: add-dialog.c 11350 2010-10-24 05:52:38Z charles $
13 #include <glib/gi18n.h>
14 #include <gtk/gtk.h>
16 #include <string.h>
18 #include "add-dialog.h"
19 #include "conf.h"
20 #include "file-list.h"
21 #include "hig.h"
22 #include "tr-prefs.h"
24 /****
25 *****
26 ****/
28 #define N_RECENT 4
30 static GSList*
31 get_recent_destinations( void )
33 int i;
34 GSList * list = NULL;
36 for( i=0; i<N_RECENT; ++i )
38 char key[64];
39 const char * val;
40 g_snprintf( key, sizeof( key ), "recent-download-dir-%d", i+1 );
41 if(( val = pref_string_get( key )))
42 list = g_slist_append( list, (void*)val );
44 return list;
47 static void
48 save_recent_destination( TrCore * core, const char * dir )
50 int i;
51 GSList * l;
52 GSList * list = get_recent_destinations( );
54 if( dir == NULL )
55 return;
57 /* if it was already in the list, remove it */
58 if(( l = g_slist_find_custom( list, dir, (GCompareFunc)strcmp )))
59 list = g_slist_delete_link( list, l );
61 /* add it to the front of the list */
62 list = g_slist_prepend( list, (void*)dir );
64 /* make local copies of the strings that aren't
65 * invalidated by pref_string_set() */
66 for( l=list; l; l=l->next )
67 l->data = g_strdup( l->data );
69 /* save the first N_RECENT directories */
70 for( l=list, i=0; l && ( i<N_RECENT ); ++i, l=l->next ) {
71 char key[64];
72 g_snprintf( key, sizeof( key ), "recent-download-dir-%d", i + 1 );
73 pref_string_set( key, l->data );
75 pref_save( tr_core_session( core ) );
77 /* cleanup */
78 g_slist_foreach( list, (GFunc)g_free, NULL );
79 g_slist_free( list );
82 /****
83 *****
84 ****/
86 struct AddData
88 TrCore * core;
89 GtkWidget * file_list;
90 GtkWidget * run_check;
91 GtkWidget * trash_check;
92 GtkWidget * priority_combo;
93 char * filename;
94 char * downloadDir;
95 TrTorrent * gtor;
96 tr_ctor * ctor;
99 static void
100 removeOldTorrent( struct AddData * data )
102 if( data->gtor )
104 file_list_clear( data->file_list );
105 tr_torrent_set_remove_flag( data->gtor, TRUE );
106 g_object_unref( G_OBJECT( data->gtor ) );
107 data->gtor = NULL;
111 static void
112 addResponseCB( GtkDialog * dialog,
113 gint response,
114 gpointer gdata )
116 struct AddData * data = gdata;
118 if( data->gtor )
120 if( response != GTK_RESPONSE_ACCEPT )
122 removeOldTorrent( data );
124 else
126 tr_torrent * tor = tr_torrent_handle( data->gtor );
128 tr_torrentSetPriority( tor, gtr_priority_combo_get_value( GTK_COMBO_BOX( data->priority_combo ) ) );
130 if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( data->run_check ) ) )
131 tr_torrentStart( tor );
133 tr_core_add_torrent( data->core, data->gtor, FALSE );
135 if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( data->trash_check ) ) )
136 gtr_file_trash_or_remove( data->filename );
138 save_recent_destination( data->core, data->downloadDir );
142 tr_ctorFree( data->ctor );
143 g_free( data->filename );
144 g_free( data->downloadDir );
145 g_free( data );
146 gtk_widget_destroy( GTK_WIDGET( dialog ) );
149 static void
150 updateTorrent( struct AddData * o )
152 const gboolean isLocalFile = tr_ctorGetSourceFile( o->ctor ) != NULL;
153 gtk_widget_set_sensitive( o->trash_check, isLocalFile );
155 if( !o->gtor )
157 file_list_clear( o->file_list );
158 gtk_widget_set_sensitive( o->file_list, FALSE );
160 else
162 tr_torrent * tor = tr_torrent_handle( o->gtor );
163 tr_torrentSetDownloadDir( tor, o->downloadDir );
164 gtk_widget_set_sensitive( o->file_list, tr_torrentHasMetadata( tor ) );
165 file_list_set_torrent( o->file_list, tr_torrentId( tor ) );
166 tr_torrentVerify( tor );
171 * When the source .torrent file is deleted
172 * (such as, if it was a temp file that a web browser passed to us),
173 * gtk invokes this callback and `filename' will be NULL.
174 * The `filename' tests here are to prevent us from losing the current
175 * metadata when that happens.
177 static void
178 sourceChanged( GtkFileChooserButton * b, gpointer gdata )
180 struct AddData * data = gdata;
181 char * filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( b ) );
183 /* maybe instantiate a torrent */
184 if( filename || !data->gtor )
186 int err = 0;
187 int new_file = 0;
188 tr_torrent * torrent;
190 if( filename && ( !data->filename || strcmp( filename, data->filename ) ) )
192 g_free( data->filename );
193 data->filename = g_strdup( filename );
194 tr_ctorSetMetainfoFromFile( data->ctor, data->filename );
195 new_file = 1;
198 tr_ctorSetDownloadDir( data->ctor, TR_FORCE, data->downloadDir );
199 tr_ctorSetPaused( data->ctor, TR_FORCE, TRUE );
200 tr_ctorSetDeleteSource( data->ctor, FALSE );
202 if( ( torrent = tr_torrentNew( data->ctor, &err ) ) )
204 removeOldTorrent( data );
205 data->gtor = tr_torrent_new_preexisting( torrent );
207 else if( new_file )
209 addTorrentErrorDialog( GTK_WIDGET( b ), err, data->filename );
212 updateTorrent( data );
215 g_free( filename );
218 static void
219 downloadDirChanged( GtkFileChooserButton * b, gpointer gdata )
221 struct AddData * data = gdata;
222 char * fname = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( b ) );
224 if( fname && ( !data->downloadDir || strcmp( fname, data->downloadDir ) ) )
226 g_free( data->downloadDir );
227 data->downloadDir = g_strdup( fname );
228 updateTorrent( data );
231 g_free( fname );
234 static void
235 addTorrentFilters( GtkFileChooser * chooser )
237 GtkFileFilter * filter;
239 filter = gtk_file_filter_new( );
240 gtk_file_filter_set_name( filter, _( "Torrent files" ) );
241 gtk_file_filter_add_pattern( filter, "*.torrent" );
242 gtk_file_chooser_add_filter( chooser, filter );
244 filter = gtk_file_filter_new( );
245 gtk_file_filter_set_name( filter, _( "All files" ) );
246 gtk_file_filter_add_pattern( filter, "*" );
247 gtk_file_chooser_add_filter( chooser, filter );
250 /****
251 *****
252 ****/
254 GtkWidget*
255 addSingleTorrentDialog( GtkWindow * parent, TrCore * core, tr_ctor * ctor )
257 int row;
258 int col;
259 const char * str;
260 GtkWidget * w;
261 GtkWidget * d;
262 GtkWidget * t;
263 GtkWidget * l;
264 GtkWidget * grab;
265 GtkWidget * source_chooser;
266 struct AddData * data;
267 uint8_t flag;
268 GSList * list;
269 GSList * walk;
271 /* make the dialog */
272 d = gtk_dialog_new_with_buttons( _( "Torrent Options" ), parent,
273 GTK_DIALOG_DESTROY_WITH_PARENT |
274 GTK_DIALOG_NO_SEPARATOR,
275 NULL );
276 gtk_dialog_add_button( GTK_DIALOG( d ), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL );
277 grab = gtk_dialog_add_button( GTK_DIALOG( d ), GTK_STOCK_ADD, GTK_RESPONSE_ACCEPT );
278 gtk_dialog_set_default_response( GTK_DIALOG( d ),
279 GTK_RESPONSE_ACCEPT );
280 gtk_dialog_set_alternative_button_order( GTK_DIALOG( d ),
281 GTK_RESPONSE_ACCEPT,
282 GTK_RESPONSE_CANCEL,
283 -1 );
285 if( tr_ctorGetDownloadDir( ctor, TR_FORCE, &str ) )
286 g_assert_not_reached( );
287 g_assert( str );
289 data = g_new0( struct AddData, 1 );
290 data->core = core;
291 data->ctor = ctor;
292 data->filename = g_strdup( tr_ctorGetSourceFile( ctor ) );
293 data->downloadDir = g_strdup( str );
294 data->file_list = file_list_new( core, 0 );
295 str = _( "Mo_ve .torrent file to the trash" );
296 data->trash_check = gtk_check_button_new_with_mnemonic( str );
297 str = _( "_Start when added" );
298 data->run_check = gtk_check_button_new_with_mnemonic( str );
300 w = data->priority_combo = gtr_priority_combo_new( );
301 gtr_priority_combo_set_value( GTK_COMBO_BOX( w ), TR_PRI_NORMAL );
303 g_signal_connect( G_OBJECT( d ), "response",
304 G_CALLBACK( addResponseCB ), data );
306 t = gtk_table_new( 6, 2, FALSE );
307 gtk_container_set_border_width( GTK_CONTAINER( t ), GUI_PAD_BIG );
308 gtk_table_set_row_spacings( GTK_TABLE( t ), GUI_PAD );
309 gtk_table_set_col_spacings( GTK_TABLE( t ), GUI_PAD_BIG );
311 row = col = 0;
312 l = gtk_label_new_with_mnemonic( _( "_Torrent file:" ) );
313 gtk_misc_set_alignment( GTK_MISC( l ), 0.0f, 0.5f );
314 gtk_table_attach( GTK_TABLE( t ), l, col, col + 1, row, row + 1, GTK_FILL, 0, 0, 0 );
315 ++col;
316 w = gtk_file_chooser_button_new( _( "Select Source File" ),
317 GTK_FILE_CHOOSER_ACTION_OPEN );
318 source_chooser = w;
319 gtk_table_attach( GTK_TABLE( t ), w, col, col + 1, row, row + 1, ~0, 0, 0, 0 );
320 gtk_label_set_mnemonic_widget( GTK_LABEL( l ), w );
321 addTorrentFilters( GTK_FILE_CHOOSER( w ) );
322 g_signal_connect( w, "selection-changed",
323 G_CALLBACK( sourceChanged ), data );
325 ++row;
326 col = 0;
327 l = gtk_label_new_with_mnemonic( _( "_Destination folder:" ) );
328 gtk_misc_set_alignment( GTK_MISC( l ), 0.0f, 0.5f );
329 gtk_table_attach( GTK_TABLE( t ), l, col, col + 1, row, row + 1, GTK_FILL, 0, 0, 0 );
330 ++col;
331 w = gtk_file_chooser_button_new( _( "Select Destination Folder" ),
332 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER );
333 if( !gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( w ),
334 data->downloadDir ) )
335 g_warning( "couldn't select '%s'", data->downloadDir );
336 list = get_recent_destinations( );
337 for( walk = list; walk; walk = walk->next )
338 gtk_file_chooser_add_shortcut_folder( GTK_FILE_CHOOSER( w ), walk->data, NULL );
339 g_slist_free( list );
340 gtk_table_attach( GTK_TABLE( t ), w, col, col + 1, row, row + 1, ~0, 0, 0, 0 );
341 gtk_label_set_mnemonic_widget( GTK_LABEL( l ), w );
342 g_signal_connect( w, "selection-changed",
343 G_CALLBACK( downloadDirChanged ), data );
345 ++row;
346 col = 0;
347 w = data->file_list;
348 gtk_widget_set_size_request ( w, 466u, 300u );
349 gtk_table_attach_defaults( GTK_TABLE( t ), w, col, col + 2, row, row + 1 );
351 ++row;
352 col = 0;
353 w = gtk_label_new_with_mnemonic( _( "Torrent _priority:" ) );
354 gtk_misc_set_alignment( GTK_MISC( w ), 0.0f, 0.5f );
355 gtk_table_attach( GTK_TABLE( t ), w, col, col + 1, row, row + 1, ~0, 0, 0, 0 );
356 ++col;
357 gtk_table_attach( GTK_TABLE( t ), data->priority_combo, col, col + 1, row, row + 1, ~0, 0, 0, 0 );
358 gtk_label_set_mnemonic_widget( GTK_LABEL( w ), data->priority_combo );
360 ++row;
361 col = 0;
362 w = data->run_check;
363 if( tr_ctorGetPaused( ctor, TR_FORCE, &flag ) )
364 g_assert_not_reached( );
365 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( w ), !flag );
366 gtk_table_attach( GTK_TABLE( t ), w, col, col + 2, row, row + 1, GTK_FILL, 0, 0, 0 );
368 ++row;
369 col = 0;
370 w = data->trash_check;
371 if( tr_ctorGetDeleteSource( ctor, &flag ) )
372 g_assert_not_reached( );
373 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( w ), flag );
374 gtk_table_attach( GTK_TABLE( t ), w, col, col + 2, row, row + 1, GTK_FILL, 0, 0, 0 );
376 /* trigger sourceChanged, either directly or indirectly,
377 * so that it creates the tor/gtor objects */
378 w = source_chooser;
379 if( data->filename )
380 gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( w ), data->filename );
381 else
382 sourceChanged( GTK_FILE_CHOOSER_BUTTON( w ), data );
384 gtk_box_pack_start( GTK_BOX( GTK_DIALOG( d )->vbox ), t, TRUE, TRUE, 0 );
386 gtk_widget_grab_focus( grab );
387 gtk_widget_show_all( d );
388 return d;
391 /****
392 *****
393 ****/
395 static void
396 onAddDialogResponse( GtkDialog * dialog,
397 int response,
398 gpointer core )
400 char * folder;
402 /* remember this folder the next time we use this dialog */
403 folder = gtk_file_chooser_get_current_folder( GTK_FILE_CHOOSER( dialog ) );
404 pref_string_set( PREF_KEY_OPEN_DIALOG_FOLDER, folder );
405 g_free( folder );
407 if( response == GTK_RESPONSE_ACCEPT )
409 GtkFileChooser * chooser = GTK_FILE_CHOOSER( dialog );
410 GtkWidget * w = gtk_file_chooser_get_extra_widget( chooser );
411 GtkToggleButton * tb = GTK_TOGGLE_BUTTON( w );
412 const gboolean showOptions = gtk_toggle_button_get_active( tb );
413 const pref_flag_t start = PREF_FLAG_DEFAULT;
414 const pref_flag_t prompt = showOptions
415 ? PREF_FLAG_TRUE
416 : PREF_FLAG_FALSE;
417 GSList * l = gtk_file_chooser_get_filenames( chooser );
419 tr_core_add_list( core, l, start, prompt, FALSE );
422 gtk_widget_destroy( GTK_WIDGET( dialog ) );
425 GtkWidget*
426 addDialog( GtkWindow * parent,
427 TrCore * core )
429 GtkWidget * w;
430 GtkWidget * c;
431 const char * folder;
433 w = gtk_file_chooser_dialog_new( _( "Add a Torrent" ), parent,
434 GTK_FILE_CHOOSER_ACTION_OPEN,
435 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
436 GTK_STOCK_ADD, GTK_RESPONSE_ACCEPT,
437 NULL );
438 gtk_dialog_set_alternative_button_order( GTK_DIALOG( w ),
439 GTK_RESPONSE_ACCEPT,
440 GTK_RESPONSE_CANCEL,
441 -1 );
442 gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER( w ), TRUE );
443 addTorrentFilters( GTK_FILE_CHOOSER( w ) );
444 g_signal_connect( w, "response", G_CALLBACK(
445 onAddDialogResponse ), core );
447 if( ( folder = pref_string_get( PREF_KEY_OPEN_DIALOG_FOLDER ) ) )
448 gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( w ), folder );
450 c = gtk_check_button_new_with_mnemonic( _( "Show _options dialog" ) );
451 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( c ),
452 pref_flag_get( PREF_KEY_OPTIONS_PROMPT ) );
453 gtk_file_chooser_set_extra_widget( GTK_FILE_CHOOSER( w ), c );
454 gtk_widget_show( c );
456 gtk_widget_show( w );
457 return w;
460 /***
461 ****
462 ***/
464 static void
465 onAddURLResponse( GtkDialog * dialog, int response, gpointer user_data )
467 gboolean destroy = TRUE;
469 if( response == GTK_RESPONSE_ACCEPT )
471 GtkWidget * e = GTK_WIDGET( g_object_get_data( G_OBJECT( dialog ), "url-entry" ) );
472 char * url = g_strdup( gtk_entry_get_text( GTK_ENTRY( e ) ) );
473 g_strstrip( url );
475 if( url && *url )
477 TrCore * core = user_data;
479 if( gtr_is_supported_url( url ) || gtr_is_magnet_link( url )
480 || gtr_is_hex_hashcode( url ) )
482 tr_core_add_from_url( core, url );
484 else
486 gtr_unrecognized_url_dialog( GTK_WIDGET( dialog ), url );
487 destroy = FALSE;
491 g_free( url );
494 if( destroy )
495 gtk_widget_destroy( GTK_WIDGET( dialog ) );
498 static void
499 paste_clipboard_url_into_entry( GtkWidget * e )
501 size_t i;
503 char * text[] = {
504 gtk_clipboard_wait_for_text( gtk_clipboard_get( GDK_SELECTION_PRIMARY ) ),
505 gtk_clipboard_wait_for_text( gtk_clipboard_get( GDK_SELECTION_CLIPBOARD ) )
508 for( i=0; i<G_N_ELEMENTS(text); ++i ) {
509 char * s = text[i];
510 if( s && ( gtr_is_supported_url( s ) || gtr_is_magnet_link( s ) ) ) {
511 gtk_entry_set_text( GTK_ENTRY( e ), s );
512 break;
516 for( i=0; i<G_N_ELEMENTS(text); ++i )
517 g_free( text[i] );
520 GtkWidget*
521 addURLDialog( GtkWindow * parent, TrCore * core )
523 int row;
524 GtkWidget * e;
525 GtkWidget * t;
526 GtkWidget * w;
528 w = gtk_dialog_new_with_buttons( _( "Add URL" ), parent,
529 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
530 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
531 GTK_STOCK_ADD, GTK_RESPONSE_ACCEPT,
532 NULL );
533 gtk_dialog_set_alternative_button_order( GTK_DIALOG( w ),
534 GTK_RESPONSE_ACCEPT,
535 GTK_RESPONSE_CANCEL,
536 -1 );
537 g_signal_connect( w, "response", G_CALLBACK( onAddURLResponse ), core );
539 row = 0;
540 t = hig_workarea_create( );
541 hig_workarea_add_section_title( t, &row, _( "Add torrent from URL" ) );
542 e = gtk_entry_new( );
543 gtk_widget_set_size_request( e, 400, -1 );
544 paste_clipboard_url_into_entry( e );
545 g_object_set_data( G_OBJECT( w ), "url-entry", e );
546 hig_workarea_add_row( t, &row, _( "_URL" ), e, NULL );
548 gtk_box_pack_start( GTK_BOX( GTK_DIALOG( w )->vbox ), t, TRUE, TRUE, 0 );
549 gtk_widget_show_all( t );
550 gtk_widget_show( w );
551 return w;