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>
18 #include "add-dialog.h"
20 #include "file-list.h"
31 get_recent_destinations( void )
36 for( i
=0; i
<N_RECENT
; ++i
)
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
);
48 save_recent_destination( TrCore
* core
, const char * dir
)
52 GSList
* list
= get_recent_destinations( );
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
) {
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
) );
78 g_slist_foreach( list
, (GFunc
)g_free
, NULL
);
89 GtkWidget
* file_list
;
90 GtkWidget
* run_check
;
91 GtkWidget
* trash_check
;
92 GtkWidget
* priority_combo
;
100 removeOldTorrent( struct AddData
* data
)
104 file_list_clear( data
->file_list
);
105 tr_torrent_set_remove_flag( data
->gtor
, TRUE
);
106 g_object_unref( G_OBJECT( data
->gtor
) );
112 addResponseCB( GtkDialog
* dialog
,
116 struct AddData
* data
= gdata
;
120 if( response
!= GTK_RESPONSE_ACCEPT
)
122 removeOldTorrent( data
);
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
);
146 gtk_widget_destroy( GTK_WIDGET( dialog
) );
150 updateTorrent( struct AddData
* o
)
152 const gboolean isLocalFile
= tr_ctorGetSourceFile( o
->ctor
) != NULL
;
153 gtk_widget_set_sensitive( o
->trash_check
, isLocalFile
);
157 file_list_clear( o
->file_list
);
158 gtk_widget_set_sensitive( o
->file_list
, FALSE
);
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.
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
)
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
);
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
);
209 addTorrentErrorDialog( GTK_WIDGET( b
), err
, data
->filename
);
212 updateTorrent( data
);
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
);
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
);
255 addSingleTorrentDialog( GtkWindow
* parent
, TrCore
* core
, tr_ctor
* ctor
)
265 GtkWidget
* source_chooser
;
266 struct AddData
* data
;
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
,
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
),
285 if( tr_ctorGetDownloadDir( ctor
, TR_FORCE
, &str
) )
286 g_assert_not_reached( );
289 data
= g_new0( struct AddData
, 1 );
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
);
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 );
316 w
= gtk_file_chooser_button_new( _( "Select Source File" ),
317 GTK_FILE_CHOOSER_ACTION_OPEN
);
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
);
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 );
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
);
348 gtk_widget_set_size_request ( w
, 466u, 300u );
349 gtk_table_attach_defaults( GTK_TABLE( t
), w
, col
, col
+ 2, row
, row
+ 1 );
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 );
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
);
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 );
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 */
380 gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( w
), data
->filename
);
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
);
396 onAddDialogResponse( GtkDialog
* dialog
,
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
);
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
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
) );
426 addDialog( GtkWindow
* parent
,
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
,
438 gtk_dialog_set_alternative_button_order( GTK_DIALOG( w
),
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
);
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
) ) );
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
);
486 gtr_unrecognized_url_dialog( GTK_WIDGET( dialog
), url
);
495 gtk_widget_destroy( GTK_WIDGET( dialog
) );
499 paste_clipboard_url_into_entry( GtkWidget
* e
)
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
) {
510 if( s
&& ( gtr_is_supported_url( s
) || gtr_is_magnet_link( s
) ) ) {
511 gtk_entry_set_text( GTK_ENTRY( e
), s
);
516 for( i
=0; i
<G_N_ELEMENTS(text
); ++i
)
521 addURLDialog( GtkWindow
* parent
, TrCore
* core
)
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
,
533 gtk_dialog_set_alternative_button_order( GTK_DIALOG( w
),
537 g_signal_connect( w
, "response", G_CALLBACK( onAddURLResponse
), core
);
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
);