Transmission: update to 2.82
[tomato.git] / release / src / router / transmission / gtk / open-dialog.c
blob5f5104adbfef7c04e038a1927c9db2dbf942f625
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 14132 2013-07-20 16:19:15Z 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"
26 #include "util.h" /* gtr_priority_combo_get_value () */
28 /****
29 *****
30 ****/
32 #define N_RECENT 4
34 static GSList*
35 get_recent_destinations (void)
37 int i;
38 GSList * list = NULL;
40 for (i=0; i<N_RECENT; ++i)
42 char key[64];
43 const char * val;
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);
49 return list;
52 static void
53 save_recent_destination (TrCore * core, const char * dir)
55 int i;
56 GSList * l;
57 GSList * list = get_recent_destinations ();
59 if (dir == NULL)
60 return;
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)
77 char key[64];
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));
83 /* cleanup */
84 g_slist_foreach (list, (GFunc)g_free, NULL);
85 g_slist_free (list);
88 /****
89 *****
90 ****/
92 struct OpenData
94 TrCore * core;
95 GtkWidget * file_list;
96 GtkWidget * run_check;
97 GtkWidget * trash_check;
98 GtkWidget * priority_combo;
99 GtkWidget * freespace_label;
100 char * filename;
101 char * downloadDir;
102 tr_torrent * tor;
103 tr_ctor * ctor;
106 static void
107 removeOldTorrent (struct OpenData * o)
109 if (o->tor)
111 gtr_file_list_clear (o->file_list);
112 tr_torrentRemove (o->tor, FALSE, NULL);
113 o->tor = NULL;
117 static void
118 addResponseCB (GtkDialog * dialog,
119 gint response,
120 gpointer gdata)
122 struct OpenData * o = gdata;
124 if (o->tor)
126 if (response != GTK_RESPONSE_ACCEPT)
128 removeOldTorrent (o);
130 else
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);
149 g_free (o);
150 gtk_widget_destroy (GTK_WIDGET (dialog));
153 static void
154 updateTorrent (struct OpenData * o)
156 const gboolean isLocalFile = tr_ctorGetSourceFile (o->ctor) != NULL;
157 gtk_widget_set_sensitive (o->trash_check, isLocalFile);
159 if (!o->tor)
161 gtr_file_list_clear (o->file_list);
162 gtk_widget_set_sensitive (o->file_list, FALSE);
164 else
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.
180 static void
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)
189 int err = 0;
190 int new_file = 0;
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);
199 new_file = 1;
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);
209 o->tor = torrent;
211 else if (new_file)
213 tr_torrent * tor;
215 if (duplicate_id)
216 tor = gtr_core_find_torrent (o->core, duplicate_id);
217 else
218 tor = NULL;
220 gtr_add_torrent_error_dialog (GTK_WIDGET (b), err, tor, o->filename);
223 updateTorrent (o);
226 g_free (filename);
229 static void
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);
244 g_free (fname);
247 static void
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);
263 /****
264 *****
265 ****/
267 GtkWidget*
268 gtr_torrent_options_dialog_new (GtkWindow * parent, TrCore * core, tr_ctor * ctor)
270 const char * str;
271 GtkWidget * w;
272 GtkWidget * d;
273 GtkGrid * grid;
274 int row;
275 GtkWidget * l;
276 GtkWidget * source_chooser;
277 struct OpenData * data;
278 bool flag;
279 GSList * list;
280 GSList * walk;
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,
287 NULL);
288 gtk_dialog_set_default_response (GTK_DIALOG (d),
289 GTK_RESPONSE_ACCEPT);
290 gtk_dialog_set_alternative_button_order (GTK_DIALOG (d),
291 GTK_RESPONSE_ACCEPT,
292 GTK_RESPONSE_CANCEL,
293 -1);
295 if (tr_ctorGetDownloadDir (ctor, TR_FORCE, &str))
296 g_assert_not_reached ();
297 g_assert (str);
299 data = g_new0 (struct OpenData, 1);
300 data->core = core;
301 data->ctor = ctor;
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);
316 row = 0;
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);
328 source_chooser = w;
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 */
337 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),
344 data->downloadDir))
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);
349 g_slist_free (list);
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);
355 row++;
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);
362 /* file list row */
363 row++;
364 w = data->file_list;
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 */
370 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 */
379 row++;
380 w = data->run_check;
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 */
387 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 */
396 w = source_chooser;
397 if (data->filename)
398 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (w), data->filename);
399 else
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);
405 return d;
408 /****
409 *****
410 ****/
412 static void
413 onOpenDialogResponse (GtkDialog * dialog, int response, gpointer core)
415 char * folder;
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);
420 g_free (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));
440 GtkWidget*
441 gtr_torrent_open_from_file_dialog_new (GtkWindow * parent, TrCore * core)
443 GtkWidget * w;
444 GtkWidget * c;
445 const char * folder;
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,
451 NULL);
452 gtk_dialog_set_alternative_button_order (GTK_DIALOG (w),
453 GTK_RESPONSE_ACCEPT,
454 GTK_RESPONSE_CANCEL,
455 -1);
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);
467 gtk_widget_show (c);
469 return w;
472 /***
473 ****
474 ***/
476 static void
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)));
485 g_strstrip (url);
487 if (url)
489 handled = gtr_core_add_from_url (user_data, url);
490 if (!handled)
491 gtr_unrecognized_url_dialog (GTK_WIDGET (dialog), url);
492 g_free (url);
495 else if (response == GTK_RESPONSE_CANCEL)
497 handled = TRUE;
500 if (handled)
501 gtk_widget_destroy (GTK_WIDGET (dialog));
504 GtkWidget*
505 gtr_torrent_open_from_url_dialog_new (GtkWindow * parent, TrCore * core)
507 guint row;
508 GtkWidget * e;
509 GtkWidget * t;
510 GtkWidget * w;
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,
516 NULL);
517 gtk_dialog_set_alternative_button_order (GTK_DIALOG (w),
518 GTK_RESPONSE_ACCEPT,
519 GTK_RESPONSE_CANCEL,
520 -1);
521 g_signal_connect (w, "response", G_CALLBACK (onOpenURLResponse), core);
523 row = 0;
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);
536 else
537 gtk_widget_grab_focus (gtk_dialog_get_widget_for_response (GTK_DIALOG (w), GTK_RESPONSE_ACCEPT));
539 return w;