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 14132 2013-07-20 16:19:15Z jordan $
13 #include <glib/gi18n.h>
18 #include <libtransmission/transmission.h>
19 #include <libtransmission/utils.h> /* tr_is_same_file () */
22 #include "file-list.h"
24 #include "open-dialog.h"
26 #include "util.h" /* gtr_priority_combo_get_value () */
35 get_recent_destinations (void)
40 for (i
=0; i
<N_RECENT
; ++i
)
44 g_snprintf (key
, sizeof (key
), "recent-download-dir-%d", i
+1);
45 if ((val
= gtr_pref_string_get (tr_quark_new(key
,-1))))
46 list
= g_slist_append (list
, (void*)val
);
53 save_recent_destination (TrCore
* core
, const char * dir
)
57 GSList
* list
= get_recent_destinations ();
62 /* if it was already in the list, remove it */
63 if ((l
= g_slist_find_custom (list
, dir
, (GCompareFunc
)g_strcmp0
)))
64 list
= g_slist_delete_link (list
, l
);
66 /* add it to the front of the list */
67 list
= g_slist_prepend (list
, (void*)dir
);
69 /* make local copies of the strings that aren't
70 * invalidated by gtr_pref_string_set () */
71 for (l
=list
; l
; l
=l
->next
)
72 l
->data
= g_strdup (l
->data
);
74 /* save the first N_RECENT directories */
75 for (l
=list
, i
=0; l
&& (i
<N_RECENT
); ++i
, l
=l
->next
)
78 g_snprintf (key
, sizeof (key
), "recent-download-dir-%d", i
+ 1);
79 gtr_pref_string_set (tr_quark_new(key
,-1), l
->data
);
81 gtr_pref_save (gtr_core_session (core
));
84 g_slist_foreach (list
, (GFunc
)g_free
, NULL
);
95 GtkWidget
* file_list
;
96 GtkWidget
* run_check
;
97 GtkWidget
* trash_check
;
98 GtkWidget
* priority_combo
;
99 GtkWidget
* freespace_label
;
107 removeOldTorrent (struct OpenData
* o
)
111 gtr_file_list_clear (o
->file_list
);
112 tr_torrentRemove (o
->tor
, FALSE
, NULL
);
118 addResponseCB (GtkDialog
* dialog
,
122 struct OpenData
* o
= gdata
;
126 if (response
!= GTK_RESPONSE_ACCEPT
)
128 removeOldTorrent (o
);
132 tr_torrentSetPriority (o
->tor
, gtr_priority_combo_get_value (GTK_COMBO_BOX (o
->priority_combo
)));
134 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (o
->run_check
)))
135 tr_torrentStart (o
->tor
);
137 gtr_core_add_torrent (o
->core
, o
->tor
, FALSE
);
139 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (o
->trash_check
)))
140 gtr_file_trash_or_remove (o
->filename
);
142 save_recent_destination (o
->core
, o
->downloadDir
);
146 tr_ctorFree (o
->ctor
);
147 g_free (o
->filename
);
148 g_free (o
->downloadDir
);
150 gtk_widget_destroy (GTK_WIDGET (dialog
));
154 updateTorrent (struct OpenData
* o
)
156 const gboolean isLocalFile
= tr_ctorGetSourceFile (o
->ctor
) != NULL
;
157 gtk_widget_set_sensitive (o
->trash_check
, isLocalFile
);
161 gtr_file_list_clear (o
->file_list
);
162 gtk_widget_set_sensitive (o
->file_list
, FALSE
);
166 tr_torrentSetDownloadDir (o
->tor
, o
->downloadDir
);
167 gtk_widget_set_sensitive (o
->file_list
, tr_torrentHasMetadata (o
->tor
));
168 gtr_file_list_set_torrent (o
->file_list
, tr_torrentId (o
->tor
));
169 tr_torrentVerify (o
->tor
, NULL
, NULL
);
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.
181 sourceChanged (GtkFileChooserButton
* b
, gpointer gdata
)
183 struct OpenData
* o
= gdata
;
184 char * filename
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (b
));
186 /* maybe instantiate a torrent */
187 if (filename
|| !o
->tor
)
191 int duplicate_id
= 0;
192 tr_torrent
* torrent
;
194 if (filename
&& (!o
->filename
|| !tr_is_same_file (filename
, o
->filename
)))
196 g_free (o
->filename
);
197 o
->filename
= g_strdup (filename
);
198 tr_ctorSetMetainfoFromFile (o
->ctor
, o
->filename
);
202 tr_ctorSetDownloadDir (o
->ctor
, TR_FORCE
, o
->downloadDir
);
203 tr_ctorSetPaused (o
->ctor
, TR_FORCE
, TRUE
);
204 tr_ctorSetDeleteSource (o
->ctor
, FALSE
);
206 if ((torrent
= tr_torrentNew (o
->ctor
, &err
, &duplicate_id
)))
208 removeOldTorrent (o
);
216 tor
= gtr_core_find_torrent (o
->core
, duplicate_id
);
220 gtr_add_torrent_error_dialog (GTK_WIDGET (b
), err
, tor
, o
->filename
);
230 downloadDirChanged (GtkFileChooserButton
* b
, gpointer gdata
)
232 struct OpenData
* data
= gdata
;
233 char * fname
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (b
));
235 if (fname
&& (!data
->downloadDir
|| !tr_is_same_file (fname
, data
->downloadDir
)))
237 g_free (data
->downloadDir
);
238 data
->downloadDir
= g_strdup (fname
);
239 updateTorrent (data
);
241 gtr_freespace_label_set_dir (data
->freespace_label
, data
->downloadDir
);
248 addTorrentFilters (GtkFileChooser
* chooser
)
250 GtkFileFilter
* filter
;
252 filter
= gtk_file_filter_new ();
253 gtk_file_filter_set_name (filter
, _("Torrent files"));
254 gtk_file_filter_add_pattern (filter
, "*.torrent");
255 gtk_file_chooser_add_filter (chooser
, filter
);
257 filter
= gtk_file_filter_new ();
258 gtk_file_filter_set_name (filter
, _("All files"));
259 gtk_file_filter_add_pattern (filter
, "*");
260 gtk_file_chooser_add_filter (chooser
, filter
);
268 gtr_torrent_options_dialog_new (GtkWindow
* parent
, TrCore
* core
, tr_ctor
* ctor
)
276 GtkWidget
* source_chooser
;
277 struct OpenData
* data
;
282 /* make the dialog */
283 d
= gtk_dialog_new_with_buttons (_("Torrent Options"), parent
,
284 GTK_DIALOG_DESTROY_WITH_PARENT
,
285 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
286 GTK_STOCK_OPEN
, GTK_RESPONSE_ACCEPT
,
288 gtk_dialog_set_default_response (GTK_DIALOG (d
),
289 GTK_RESPONSE_ACCEPT
);
290 gtk_dialog_set_alternative_button_order (GTK_DIALOG (d
),
295 if (tr_ctorGetDownloadDir (ctor
, TR_FORCE
, &str
))
296 g_assert_not_reached ();
299 data
= g_new0 (struct OpenData
, 1);
302 data
->filename
= g_strdup (tr_ctorGetSourceFile (ctor
));
303 data
->downloadDir
= g_strdup (str
);
304 data
->file_list
= gtr_file_list_new (core
, 0);
305 str
= _("Mo_ve .torrent file to the trash");
306 data
->trash_check
= gtk_check_button_new_with_mnemonic (str
);
307 str
= _("_Start when added");
308 data
->run_check
= gtk_check_button_new_with_mnemonic (str
);
310 w
= data
->priority_combo
= gtr_priority_combo_new ();
311 gtr_priority_combo_set_value (GTK_COMBO_BOX (w
), TR_PRI_NORMAL
);
313 g_signal_connect (G_OBJECT (d
), "response",
314 G_CALLBACK (addResponseCB
), data
);
317 grid
= GTK_GRID (gtk_grid_new ());
318 gtk_container_set_border_width (GTK_CONTAINER (grid
), GUI_PAD_BIG
);
319 gtk_grid_set_row_spacing (grid
, GUI_PAD
);
320 gtk_grid_set_column_spacing (grid
, GUI_PAD_BIG
);
322 /* "torrent file" row */
323 l
= gtk_label_new_with_mnemonic (_("_Torrent file:"));
324 gtk_misc_set_alignment (GTK_MISC (l
), 0.0f
, 0.5f
);
325 gtk_grid_attach (grid
, l
, 0, row
, 1, 1);
326 w
= gtk_file_chooser_button_new (_("Select Source File"),
327 GTK_FILE_CHOOSER_ACTION_OPEN
);
329 gtk_widget_set_hexpand (w
, TRUE
);
330 gtk_grid_attach_next_to (grid
, w
, l
, GTK_POS_RIGHT
, 1, 1);
331 gtk_label_set_mnemonic_widget (GTK_LABEL (l
), w
);
332 addTorrentFilters (GTK_FILE_CHOOSER (w
));
333 g_signal_connect (w
, "selection-changed",
334 G_CALLBACK (sourceChanged
), data
);
336 /* "destination folder" row */
338 l
= gtk_label_new_with_mnemonic (_("_Destination folder:"));
339 gtk_misc_set_alignment (GTK_MISC (l
), 0.0f
, 0.5f
);
340 gtk_grid_attach (grid
, l
, 0, row
, 1, 1);
341 w
= gtk_file_chooser_button_new (_("Select Destination Folder"),
342 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
);
343 if (!gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (w
),
345 g_warning ("couldn't select '%s'", data
->downloadDir
);
346 list
= get_recent_destinations ();
347 for (walk
= list
; walk
; walk
= walk
->next
)
348 gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (w
), walk
->data
, NULL
);
350 gtk_grid_attach_next_to (grid
, w
, l
, GTK_POS_RIGHT
, 1, 1);
351 gtk_label_set_mnemonic_widget (GTK_LABEL (l
), w
);
352 g_signal_connect (w
, "selection-changed",
353 G_CALLBACK (downloadDirChanged
), data
);
356 l
= data
->freespace_label
= gtr_freespace_label_new (core
, data
->downloadDir
);
357 gtk_widget_set_margin_bottom (l
, GUI_PAD_BIG
);
358 gtk_misc_set_alignment (GTK_MISC (l
), 1.0f
, 0.5f
);
359 gtk_grid_attach (grid
, l
, 0, row
, 2, 1);
365 gtk_widget_set_vexpand (w
, TRUE
);
366 gtk_widget_set_size_request (w
, 466u, 300u);
367 gtk_grid_attach (grid
, w
, 0, row
, 2, 1);
369 /* torrent priority row */
371 l
= gtk_label_new_with_mnemonic (_("Torrent _priority:"));
372 gtk_misc_set_alignment (GTK_MISC (l
), 0.0f
, 0.5f
);
373 gtk_grid_attach (grid
, l
, 0, row
, 1, 1);
374 w
= data
->priority_combo
;
375 gtk_label_set_mnemonic_widget (GTK_LABEL (l
), w
);
376 gtk_grid_attach_next_to (grid
, w
, l
, GTK_POS_RIGHT
, 1, 1);
378 /* torrent priority row */
381 if (tr_ctorGetPaused (ctor
, TR_FORCE
, &flag
))
382 g_assert_not_reached ();
383 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w
), !flag
);
384 gtk_grid_attach (grid
, w
, 0, row
, 2, 1);
386 /* "trash .torrent file" row */
388 w
= data
->trash_check
;
389 if (tr_ctorGetDeleteSource (ctor
, &flag
))
390 g_assert_not_reached ();
391 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w
), flag
);
392 gtk_grid_attach (grid
, w
, 0, row
, 2, 1);
394 /* trigger sourceChanged, either directly or indirectly,
395 * so that it creates the tor/gtor objects */
398 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (w
), data
->filename
);
400 sourceChanged (GTK_FILE_CHOOSER_BUTTON (w
), data
);
402 gtr_dialog_set_content (GTK_DIALOG (d
), GTK_WIDGET (grid
));
403 w
= gtk_dialog_get_widget_for_response (GTK_DIALOG (d
), GTK_RESPONSE_ACCEPT
);
404 gtk_widget_grab_focus (w
);
413 onOpenDialogResponse (GtkDialog
* dialog
, int response
, gpointer core
)
417 /* remember this folder the next time we use this dialog */
418 folder
= gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog
));
419 gtr_pref_string_set (TR_KEY_open_dialog_dir
, folder
);
422 if (response
== GTK_RESPONSE_ACCEPT
)
424 GtkFileChooser
* chooser
= GTK_FILE_CHOOSER (dialog
);
425 GtkWidget
* w
= gtk_file_chooser_get_extra_widget (chooser
);
426 GtkToggleButton
* tb
= GTK_TOGGLE_BUTTON (w
);
427 const gboolean do_start
= gtr_pref_flag_get (TR_KEY_start_added_torrents
);
428 const gboolean do_prompt
= gtk_toggle_button_get_active (tb
);
429 const gboolean do_notify
= FALSE
;
430 GSList
* files
= gtk_file_chooser_get_files (chooser
);
432 gtr_core_add_files (core
, files
, do_start
, do_prompt
, do_notify
);
433 g_slist_foreach (files
, (GFunc
)g_object_unref
, NULL
);
434 g_slist_free (files
);
437 gtk_widget_destroy (GTK_WIDGET (dialog
));
441 gtr_torrent_open_from_file_dialog_new (GtkWindow
* parent
, TrCore
* core
)
447 w
= gtk_file_chooser_dialog_new (_("Open a Torrent"), parent
,
448 GTK_FILE_CHOOSER_ACTION_OPEN
,
449 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
450 GTK_STOCK_OPEN
, GTK_RESPONSE_ACCEPT
,
452 gtk_dialog_set_alternative_button_order (GTK_DIALOG (w
),
456 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (w
), TRUE
);
457 addTorrentFilters (GTK_FILE_CHOOSER (w
));
458 g_signal_connect (w
, "response", G_CALLBACK (onOpenDialogResponse
), core
);
460 if ((folder
= gtr_pref_string_get (TR_KEY_open_dialog_dir
)))
461 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (w
), folder
);
463 c
= gtk_check_button_new_with_mnemonic (_("Show _options dialog"));
464 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (c
),
465 gtr_pref_flag_get (TR_KEY_show_options_window
));
466 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (w
), c
);
477 onOpenURLResponse (GtkDialog
* dialog
, int response
, gpointer user_data
)
479 bool handled
= false;
481 if (response
== GTK_RESPONSE_ACCEPT
)
483 GtkWidget
* e
= GTK_WIDGET (g_object_get_data (G_OBJECT (dialog
), "url-entry"));
484 char * url
= g_strdup (gtk_entry_get_text (GTK_ENTRY (e
)));
489 handled
= gtr_core_add_from_url (user_data
, url
);
491 gtr_unrecognized_url_dialog (GTK_WIDGET (dialog
), url
);
495 else if (response
== GTK_RESPONSE_CANCEL
)
501 gtk_widget_destroy (GTK_WIDGET (dialog
));
505 gtr_torrent_open_from_url_dialog_new (GtkWindow
* parent
, TrCore
* core
)
512 w
= gtk_dialog_new_with_buttons (_("Open URL"), parent
,
513 GTK_DIALOG_DESTROY_WITH_PARENT
,
514 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
515 GTK_STOCK_OPEN
, GTK_RESPONSE_ACCEPT
,
517 gtk_dialog_set_alternative_button_order (GTK_DIALOG (w
),
521 g_signal_connect (w
, "response", G_CALLBACK (onOpenURLResponse
), core
);
524 t
= hig_workarea_create ();
525 hig_workarea_add_section_title (t
, &row
, _("Open torrent from URL"));
526 e
= gtk_entry_new ();
527 gtk_widget_set_size_request (e
, 400, -1);
528 gtr_paste_clipboard_url_into_entry (e
);
529 g_object_set_data (G_OBJECT (w
), "url-entry", e
);
530 hig_workarea_add_row (t
, &row
, _("_URL"), e
, NULL
);
532 gtr_dialog_set_content (GTK_DIALOG (w
), t
);
534 if (gtk_entry_get_text_length (GTK_ENTRY (e
)) == 0)
535 gtk_widget_grab_focus (e
);
537 gtk_widget_grab_focus (gtk_dialog_get_widget_for_response (GTK_DIALOG (w
), GTK_RESPONSE_ACCEPT
));