1 /*
2  * This file Copyright (C) 2009-2014 Mnemosyne LLC
3  *
4  * It may be used under the GNU GPL versions 2 or 3
5  * or any future license endorsed by Mnemosyne LLC.
6  *
7  */
8 
9 #include <libtransmission/transmission.h>
10 
11 #include <glib/gi18n.h>
12 #include <gtk/gtk.h>
13 
14 #include "conf.h" /* gtr_pref_string_get */
15 #include "hig.h"
16 #include "relocate.h"
17 #include "util.h"
18 
19 #define DATA_KEY "gtr-relocate-data"
20 
21 static char* previousLocation = NULL;
22 
23 struct relocate_dialog_data
24 {
25     int done;
26     bool do_move;
27     guint timer;
28     TrCore* core;
29     GSList* torrent_ids;
30     GtkWidget* message_dialog;
31     GtkWidget* chooser_dialog;
32 };
33 
data_free(gpointer gdata)34 static void data_free(gpointer gdata)
35 {
36     struct relocate_dialog_data* data = gdata;
37     g_source_remove(data->timer);
38     g_slist_free(data->torrent_ids);
39     g_free(data);
40 }
41 
42 /***
43 ****
44 ***/
45 
startMovingNextTorrent(struct relocate_dialog_data * data)46 static void startMovingNextTorrent(struct relocate_dialog_data* data)
47 {
48     char* str;
49     int const id = GPOINTER_TO_INT(data->torrent_ids->data);
50 
51     tr_torrent* tor = gtr_core_find_torrent(data->core, id);
52 
53     if (tor != NULL)
54     {
55         tr_torrentSetLocation(tor, previousLocation, data->do_move, NULL, &data->done);
56     }
57 
58     data->torrent_ids = g_slist_delete_link(data->torrent_ids, data->torrent_ids);
59 
60     str = g_strdup_printf(_("Moving \"%s\""), tr_torrentName(tor));
61     gtk_message_dialog_set_markup(GTK_MESSAGE_DIALOG(data->message_dialog), str);
62     g_free(str);
63 }
64 
65 /* every once in awhile, check to see if the move is done.
66  * if so, delete the dialog */
onTimer(gpointer gdata)67 static gboolean onTimer(gpointer gdata)
68 {
69     struct relocate_dialog_data* data = gdata;
70     int const done = data->done;
71 
72     if (done == TR_LOC_ERROR)
73     {
74         int const flags = GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT;
75         GtkWidget* w = gtk_message_dialog_new(GTK_WINDOW(data->message_dialog), flags, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
76             "%s", _("Couldn't move torrent"));
77         gtk_dialog_run(GTK_DIALOG(w));
78         gtk_widget_destroy(GTK_WIDGET(data->message_dialog));
79     }
80     else if (done == TR_LOC_DONE)
81     {
82         if (data->torrent_ids != NULL)
83         {
84             startMovingNextTorrent(data);
85         }
86         else
87         {
88             gtk_widget_destroy(GTK_WIDGET(data->chooser_dialog));
89         }
90     }
91 
92     return G_SOURCE_CONTINUE;
93 }
94 
onResponse(GtkDialog * dialog,int response,gpointer unused UNUSED)95 static void onResponse(GtkDialog* dialog, int response, gpointer unused UNUSED)
96 {
97     if (response == GTK_RESPONSE_APPLY)
98     {
99         GtkWidget* w;
100         GObject* d = G_OBJECT(dialog);
101         struct relocate_dialog_data* data = g_object_get_data(d, DATA_KEY);
102         GtkFileChooser* chooser = g_object_get_data(d, "chooser");
103         GtkToggleButton* move_tb = g_object_get_data(d, "move_rb");
104         char* location = gtk_file_chooser_get_filename(chooser);
105 
106         data->do_move = gtk_toggle_button_get_active(move_tb);
107 
108         /* pop up a dialog saying that the work is in progress */
109         w = gtk_message_dialog_new(GTK_WINDOW(dialog), GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, GTK_MESSAGE_INFO,
110             GTK_BUTTONS_CLOSE, NULL);
111         gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(w), _("This may take a moment…"));
112         gtk_dialog_set_response_sensitive(GTK_DIALOG(w), GTK_RESPONSE_CLOSE, FALSE);
113         gtk_widget_show(w);
114 
115         /* remember this location so that it can be the default next time */
116         g_free(previousLocation);
117         previousLocation = location;
118 
119         /* start the move and periodically check its status */
120         data->message_dialog = w;
121         data->done = TR_LOC_DONE;
122         data->timer = gdk_threads_add_timeout_seconds(1, onTimer, data);
123         onTimer(data);
124     }
125     else
126     {
127         gtk_widget_destroy(GTK_WIDGET(dialog));
128     }
129 }
130 
gtr_relocate_dialog_new(GtkWindow * parent,TrCore * core,GSList * torrent_ids)131 GtkWidget* gtr_relocate_dialog_new(GtkWindow* parent, TrCore* core, GSList* torrent_ids)
132 {
133     guint row;
134     GtkWidget* w;
135     GtkWidget* d;
136     GtkWidget* t;
137     struct relocate_dialog_data* data;
138 
139     d = gtk_dialog_new_with_buttons(_("Set Torrent Location"), parent, GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
140         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_APPLY, GTK_RESPONSE_APPLY, NULL);
141     gtk_dialog_set_default_response(GTK_DIALOG(d), GTK_RESPONSE_CANCEL);
142     g_signal_connect(d, "response", G_CALLBACK(onResponse), NULL);
143 
144     row = 0;
145     t = hig_workarea_create();
146     hig_workarea_add_section_title(t, &row, _("Location"));
147 
148     if (previousLocation == NULL)
149     {
150         previousLocation = g_strdup(gtr_pref_string_get(TR_KEY_download_dir));
151     }
152 
153     w = gtk_file_chooser_button_new(_("Set Torrent Location"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
154     gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(w), previousLocation);
155     g_object_set_data(G_OBJECT(d), "chooser", w);
156     hig_workarea_add_row(t, &row, _("Torrent _location:"), w, NULL);
157     w = gtk_radio_button_new_with_mnemonic(NULL, _("_Move from the current folder"));
158     g_object_set_data(G_OBJECT(d), "move_rb", w);
159     hig_workarea_add_wide_control(t, &row, w);
160     w = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(w), _("Local data is _already there"));
161     hig_workarea_add_wide_control(t, &row, w);
162     gtr_dialog_set_content(GTK_DIALOG(d), t);
163 
164     data = g_new0(struct relocate_dialog_data, 1);
165     data->core = core;
166     data->torrent_ids = torrent_ids;
167     data->chooser_dialog = d;
168     g_object_set_data_full(G_OBJECT(d), DATA_KEY, data, data_free);
169 
170     return d;
171 }
172