/* * This file Copyright (C) Mnemosyne LLC * * This file is licensed by the GPL version 2. Works owned by the * Transmission project are granted a special exemption to clause 2 (b) * so that the bulk of its code can remain under the MIT license. * This exemption does not extend to derived works not owned by * the Transmission project. * * $Id$ */ #include #include #include #include #include /* tr_is_same_file () */ #include "conf.h" #include "file-list.h" #include "hig.h" #include "open-dialog.h" #include "tr-prefs.h" #include "util.h" /* gtr_priority_combo_get_value () */ /**** ***** ****/ #define N_RECENT 4 static GSList* get_recent_destinations (void) { int i; GSList * list = NULL; for (i=0; inext) l->data = g_strdup (l->data); /* save the first N_RECENT directories */ for (l=list, i=0; l && (inext) { char key[64]; g_snprintf (key, sizeof (key), "recent-download-dir-%d", i + 1); gtr_pref_string_set (tr_quark_new(key,-1), l->data); } gtr_pref_save (gtr_core_session (core)); /* cleanup */ g_slist_foreach (list, (GFunc)g_free, NULL); g_slist_free (list); } /**** ***** ****/ struct OpenData { TrCore * core; GtkWidget * file_list; GtkWidget * run_check; GtkWidget * trash_check; GtkWidget * priority_combo; GtkWidget * freespace_label; char * filename; char * downloadDir; tr_torrent * tor; tr_ctor * ctor; }; static void removeOldTorrent (struct OpenData * o) { if (o->tor) { gtr_file_list_clear (o->file_list); tr_torrentRemove (o->tor, FALSE, NULL); o->tor = NULL; } } static void addResponseCB (GtkDialog * dialog, gint response, gpointer gdata) { struct OpenData * o = gdata; if (o->tor) { if (response != GTK_RESPONSE_ACCEPT) { removeOldTorrent (o); } else { tr_torrentSetPriority (o->tor, gtr_priority_combo_get_value (GTK_COMBO_BOX (o->priority_combo))); if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (o->run_check))) tr_torrentStart (o->tor); gtr_core_add_torrent (o->core, o->tor, FALSE); if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (o->trash_check))) gtr_file_trash_or_remove (o->filename); save_recent_destination (o->core, o->downloadDir); } } tr_ctorFree (o->ctor); g_free (o->filename); g_free (o->downloadDir); g_free (o); gtk_widget_destroy (GTK_WIDGET (dialog)); } static void updateTorrent (struct OpenData * o) { const gboolean isLocalFile = tr_ctorGetSourceFile (o->ctor) != NULL; gtk_widget_set_sensitive (o->trash_check, isLocalFile); if (!o->tor) { gtr_file_list_clear (o->file_list); gtk_widget_set_sensitive (o->file_list, FALSE); } else { tr_torrentSetDownloadDir (o->tor, o->downloadDir); gtk_widget_set_sensitive (o->file_list, tr_torrentHasMetadata (o->tor)); gtr_file_list_set_torrent (o->file_list, tr_torrentId (o->tor)); tr_torrentVerify (o->tor, NULL, NULL); } } /** * When the source .torrent file is deleted * (such as, if it was a temp file that a web browser passed to us), * gtk invokes this callback and `filename' will be NULL. * The `filename' tests here are to prevent us from losing the current * metadata when that happens. */ static void sourceChanged (GtkFileChooserButton * b, gpointer gdata) { struct OpenData * o = gdata; char * filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (b)); /* maybe instantiate a torrent */ if (filename || !o->tor) { int err = 0; int new_file = 0; int duplicate_id = 0; tr_torrent * torrent; if (filename && (!o->filename || !tr_is_same_file (filename, o->filename))) { g_free (o->filename); o->filename = g_strdup (filename); tr_ctorSetMetainfoFromFile (o->ctor, o->filename); new_file = 1; } tr_ctorSetDownloadDir (o->ctor, TR_FORCE, o->downloadDir); tr_ctorSetPaused (o->ctor, TR_FORCE, TRUE); tr_ctorSetDeleteSource (o->ctor, FALSE); if ((torrent = tr_torrentNew (o->ctor, &err, &duplicate_id))) { removeOldTorrent (o); o->tor = torrent; } else if (new_file) { tr_torrent * tor; if (duplicate_id) tor = gtr_core_find_torrent (o->core, duplicate_id); else tor = NULL; gtr_add_torrent_error_dialog (GTK_WIDGET (b), err, tor, o->filename); } updateTorrent (o); } g_free (filename); } static void downloadDirChanged (GtkFileChooserButton * b, gpointer gdata) { struct OpenData * data = gdata; char * fname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (b)); if (fname && (!data->downloadDir || !tr_is_same_file (fname, data->downloadDir))) { g_free (data->downloadDir); data->downloadDir = g_strdup (fname); updateTorrent (data); gtr_freespace_label_set_dir (data->freespace_label, data->downloadDir); } g_free (fname); } static void addTorrentFilters (GtkFileChooser * chooser) { GtkFileFilter * filter; filter = gtk_file_filter_new (); gtk_file_filter_set_name (filter, _("Torrent files")); gtk_file_filter_add_pattern (filter, "*.torrent"); gtk_file_chooser_add_filter (chooser, filter); filter = gtk_file_filter_new (); gtk_file_filter_set_name (filter, _("All files")); gtk_file_filter_add_pattern (filter, "*"); gtk_file_chooser_add_filter (chooser, filter); } /**** ***** ****/ GtkWidget* gtr_torrent_options_dialog_new (GtkWindow * parent, TrCore * core, tr_ctor * ctor) { const char * str; GtkWidget * w; GtkWidget * d; GtkGrid * grid; int row; GtkWidget * l; GtkWidget * source_chooser; struct OpenData * data; bool flag; GSList * list; GSList * walk; /* make the dialog */ d = gtk_dialog_new_with_buttons (_("Torrent Options"), parent, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); gtk_dialog_set_default_response (GTK_DIALOG (d), GTK_RESPONSE_ACCEPT); gtk_dialog_set_alternative_button_order (GTK_DIALOG (d), GTK_RESPONSE_ACCEPT, GTK_RESPONSE_CANCEL, -1); if (tr_ctorGetDownloadDir (ctor, TR_FORCE, &str)) g_assert_not_reached (); g_assert (str); data = g_new0 (struct OpenData, 1); data->core = core; data->ctor = ctor; data->filename = g_strdup (tr_ctorGetSourceFile (ctor)); data->downloadDir = g_strdup (str); data->file_list = gtr_file_list_new (core, 0); str = _("Mo_ve .torrent file to the trash"); data->trash_check = gtk_check_button_new_with_mnemonic (str); str = _("_Start when added"); data->run_check = gtk_check_button_new_with_mnemonic (str); w = data->priority_combo = gtr_priority_combo_new (); gtr_priority_combo_set_value (GTK_COMBO_BOX (w), TR_PRI_NORMAL); g_signal_connect (G_OBJECT (d), "response", G_CALLBACK (addResponseCB), data); row = 0; grid = GTK_GRID (gtk_grid_new ()); gtk_container_set_border_width (GTK_CONTAINER (grid), GUI_PAD_BIG); gtk_grid_set_row_spacing (grid, GUI_PAD); gtk_grid_set_column_spacing (grid, GUI_PAD_BIG); /* "torrent file" row */ l = gtk_label_new_with_mnemonic (_("_Torrent file:")); gtk_misc_set_alignment (GTK_MISC (l), 0.0f, 0.5f); gtk_grid_attach (grid, l, 0, row, 1, 1); w = gtk_file_chooser_button_new (_("Select Source File"), GTK_FILE_CHOOSER_ACTION_OPEN); source_chooser = w; gtk_widget_set_hexpand (w, TRUE); gtk_grid_attach_next_to (grid, w, l, GTK_POS_RIGHT, 1, 1); gtk_label_set_mnemonic_widget (GTK_LABEL (l), w); addTorrentFilters (GTK_FILE_CHOOSER (w)); g_signal_connect (w, "selection-changed", G_CALLBACK (sourceChanged), data); /* "destination folder" row */ row++; l = gtk_label_new_with_mnemonic (_("_Destination folder:")); gtk_misc_set_alignment (GTK_MISC (l), 0.0f, 0.5f); gtk_grid_attach (grid, l, 0, row, 1, 1); w = gtk_file_chooser_button_new (_("Select Destination Folder"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); if (!gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (w), data->downloadDir)) g_warning ("couldn't select '%s'", data->downloadDir); list = get_recent_destinations (); for (walk = list; walk; walk = walk->next) gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (w), walk->data, NULL); g_slist_free (list); gtk_grid_attach_next_to (grid, w, l, GTK_POS_RIGHT, 1, 1); gtk_label_set_mnemonic_widget (GTK_LABEL (l), w); g_signal_connect (w, "selection-changed", G_CALLBACK (downloadDirChanged), data); row++; l = data->freespace_label = gtr_freespace_label_new (core, data->downloadDir); gtk_widget_set_margin_bottom (l, GUI_PAD_BIG); gtk_misc_set_alignment (GTK_MISC (l), 1.0f, 0.5f); gtk_grid_attach (grid, l, 0, row, 2, 1); /* file list row */ row++; w = data->file_list; gtk_widget_set_vexpand (w, TRUE); gtk_widget_set_size_request (w, 466u, 300u); gtk_grid_attach (grid, w, 0, row, 2, 1); /* torrent priority row */ row++; l = gtk_label_new_with_mnemonic (_("Torrent _priority:")); gtk_misc_set_alignment (GTK_MISC (l), 0.0f, 0.5f); gtk_grid_attach (grid, l, 0, row, 1, 1); w = data->priority_combo; gtk_label_set_mnemonic_widget (GTK_LABEL (l), w); gtk_grid_attach_next_to (grid, w, l, GTK_POS_RIGHT, 1, 1); /* torrent priority row */ row++; w = data->run_check; if (tr_ctorGetPaused (ctor, TR_FORCE, &flag)) g_assert_not_reached (); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), !flag); gtk_grid_attach (grid, w, 0, row, 2, 1); /* "trash .torrent file" row */ row++; w = data->trash_check; if (tr_ctorGetDeleteSource (ctor, &flag)) g_assert_not_reached (); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), flag); gtk_grid_attach (grid, w, 0, row, 2, 1); /* trigger sourceChanged, either directly or indirectly, * so that it creates the tor/gtor objects */ w = source_chooser; if (data->filename) gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (w), data->filename); else sourceChanged (GTK_FILE_CHOOSER_BUTTON (w), data); gtr_dialog_set_content (GTK_DIALOG (d), GTK_WIDGET (grid)); w = gtk_dialog_get_widget_for_response (GTK_DIALOG (d), GTK_RESPONSE_ACCEPT); gtk_widget_grab_focus (w); return d; } /**** ***** ****/ static void onOpenDialogResponse (GtkDialog * dialog, int response, gpointer core) { char * folder; /* remember this folder the next time we use this dialog */ folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog)); gtr_pref_string_set (TR_KEY_open_dialog_dir, folder); g_free (folder); if (response == GTK_RESPONSE_ACCEPT) { GtkFileChooser * chooser = GTK_FILE_CHOOSER (dialog); GtkWidget * w = gtk_file_chooser_get_extra_widget (chooser); GtkToggleButton * tb = GTK_TOGGLE_BUTTON (w); const gboolean do_start = gtr_pref_flag_get (TR_KEY_start_added_torrents); const gboolean do_prompt = gtk_toggle_button_get_active (tb); const gboolean do_notify = FALSE; GSList * files = gtk_file_chooser_get_files (chooser); gtr_core_add_files (core, files, do_start, do_prompt, do_notify); g_slist_foreach (files, (GFunc)g_object_unref, NULL); g_slist_free (files); } gtk_widget_destroy (GTK_WIDGET (dialog)); } GtkWidget* gtr_torrent_open_from_file_dialog_new (GtkWindow * parent, TrCore * core) { GtkWidget * w; GtkWidget * c; const char * folder; w = gtk_file_chooser_dialog_new (_("Open a Torrent"), parent, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); gtk_dialog_set_alternative_button_order (GTK_DIALOG (w), GTK_RESPONSE_ACCEPT, GTK_RESPONSE_CANCEL, -1); gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (w), TRUE); addTorrentFilters (GTK_FILE_CHOOSER (w)); g_signal_connect (w, "response", G_CALLBACK (onOpenDialogResponse), core); if ((folder = gtr_pref_string_get (TR_KEY_open_dialog_dir))) gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (w), folder); c = gtk_check_button_new_with_mnemonic (_("Show _options dialog")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (c), gtr_pref_flag_get (TR_KEY_show_options_window)); gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (w), c); gtk_widget_show (c); return w; } /*** **** ***/ static void onOpenURLResponse (GtkDialog * dialog, int response, gpointer user_data) { bool handled = false; if (response == GTK_RESPONSE_ACCEPT) { GtkWidget * e = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), "url-entry")); char * url = g_strdup (gtk_entry_get_text (GTK_ENTRY (e))); g_strstrip (url); if (url) { handled = gtr_core_add_from_url (user_data, url); if (!handled) gtr_unrecognized_url_dialog (GTK_WIDGET (dialog), url); g_free (url); } } else if (response == GTK_RESPONSE_CANCEL) { handled = TRUE; } if (handled) gtk_widget_destroy (GTK_WIDGET (dialog)); } GtkWidget* gtr_torrent_open_from_url_dialog_new (GtkWindow * parent, TrCore * core) { guint row; GtkWidget * e; GtkWidget * t; GtkWidget * w; w = gtk_dialog_new_with_buttons (_("Open URL"), parent, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); gtk_dialog_set_alternative_button_order (GTK_DIALOG (w), GTK_RESPONSE_ACCEPT, GTK_RESPONSE_CANCEL, -1); g_signal_connect (w, "response", G_CALLBACK (onOpenURLResponse), core); row = 0; t = hig_workarea_create (); hig_workarea_add_section_title (t, &row, _("Open torrent from URL")); e = gtk_entry_new (); gtk_widget_set_size_request (e, 400, -1); gtr_paste_clipboard_url_into_entry (e); g_object_set_data (G_OBJECT (w), "url-entry", e); hig_workarea_add_row (t, &row, _("_URL"), e, NULL); gtr_dialog_set_content (GTK_DIALOG (w), t); if (gtk_entry_get_text_length (GTK_ENTRY (e)) == 0) gtk_widget_grab_focus (e); else gtk_widget_grab_focus (gtk_dialog_get_widget_for_response (GTK_DIALOG (w), GTK_RESPONSE_ACCEPT)); return w; }