source: trunk/gtk/dialogs.c @ 86

Last change on this file since 86 was 86, checked in by joshe, 16 years ago

Add internationalization support for the GTK GUI.

File size: 13.9 KB
Line 
1/*
2  Copyright (c) 2005-2006 Joshua Elsasser. All rights reserved.
3   
4  Redistribution and use in source and binary forms, with or without
5  modification, are permitted provided that the following conditions
6  are met:
7   
8   1. Redistributions of source code must retain the above copyright
9      notice, this list of conditions and the following disclaimer.
10   2. Redistributions in binary form must reproduce the above copyright
11      notice, this list of conditions and the following disclaimer in the
12      documentation and/or other materials provided with the distribution.
13   
14  THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS "AS IS" AND
15  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24  POSSIBILITY OF SUCH DAMAGE.
25*/
26
27#include <assert.h>
28#include <errno.h>
29#include <stdlib.h>
30#include <string.h>
31
32#include <gtk/gtk.h>
33#include <glib/gi18n.h>
34
35#include "conf.h"
36#include "dialogs.h"
37#include "transmission.h"
38#include "util.h"
39
40struct prefdata {
41  GtkSpinButton *port;
42  GtkCheckButton *uselimit;
43  GtkSpinButton *limit;
44  GtkFileChooser *dir;
45  GtkWindow *parent;
46  tr_handle_t *tr;
47};
48
49struct addcb {
50  add_torrent_func_t addfunc;
51  GtkWindow *parent;
52  tr_handle_t *tr;
53  torrents_added_func_t donefunc;
54  void *donedata;
55  gboolean autostart;
56  gboolean usingaltdir;
57  GtkFileChooser *altdir;
58  GtkButtonBox *altbox;
59};
60
61static void
62clicklimitbox(GtkWidget *widget, gpointer gdata);
63static void
64clickdialog(GtkWidget *widget, int resp, gpointer gdata);
65static void
66autoclick(GtkWidget *widget, gpointer gdata);
67static void
68dirclick(GtkWidget *widget, gpointer gdata);
69static void
70addresp(GtkWidget *widget, gint resp, gpointer gdata);
71
72void
73makeprefwindow(GtkWindow *parent, tr_handle_t *tr) {
74  char *title = g_strdup_printf(_("%s Preferences"), g_get_application_name());
75  GtkWidget *wind = gtk_dialog_new_with_buttons(title, parent,
76   GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
77   GTK_STOCK_APPLY, GTK_RESPONSE_APPLY, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
78   GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
79  GtkWidget *table = gtk_table_new(4, 2, FALSE);
80  GtkWidget *portnum = gtk_spin_button_new_with_range(1, 0xffff, 1);
81  GtkWidget *limitbox = gtk_check_button_new_with_label(_("Limit upload speed"));
82  GtkWidget *limitnum = gtk_spin_button_new_with_range(0, G_MAXLONG, 1);
83  GtkWidget *dirstr = gtk_file_chooser_button_new(_("Choose download directory"),
84    GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
85  GtkWidget *label;
86  GtkWidget **array;
87  const char *pref;
88  struct prefdata *data = g_new0(struct prefdata, 1);
89
90  g_free(title);
91  gtk_table_set_col_spacings(GTK_TABLE(table), 12);
92  gtk_table_set_row_spacings(GTK_TABLE(table), 12);
93  gtk_dialog_set_default_response(GTK_DIALOG(wind), GTK_RESPONSE_OK);
94  gtk_container_set_border_width(GTK_CONTAINER(table), 12);
95
96  data->port = GTK_SPIN_BUTTON(portnum);
97  data->uselimit = GTK_CHECK_BUTTON(limitbox);
98  data->limit = GTK_SPIN_BUTTON(limitnum);
99  data->dir = GTK_FILE_CHOOSER(dirstr);
100  data->parent = parent;
101  data->tr = tr;
102
103  /* port label and entry */
104  label = gtk_label_new(_("Listening port:"));
105  gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
106  pref = cf_getpref(PREF_PORT);
107  gtk_spin_button_set_value(GTK_SPIN_BUTTON(portnum),
108    (NULL == pref ? TR_DEFAULT_PORT : strtol(pref, NULL, 10)));
109  gtk_table_attach_defaults(GTK_TABLE(table), label,            0, 1, 0, 1);
110  gtk_table_attach_defaults(GTK_TABLE(table), portnum,          1, 2, 0, 1);
111
112  /* limit checkbox */
113  pref = cf_getpref(PREF_USELIMIT);
114  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(limitbox),
115    (NULL == pref ? TRUE : strbool(pref)));
116  array = g_new(GtkWidget*, 2);
117  g_signal_connect_data(limitbox, "clicked", G_CALLBACK(clicklimitbox),
118                        array, (GClosureNotify)g_free, 0);
119  gtk_table_attach_defaults(GTK_TABLE(table), limitbox,         0, 2, 1, 2);
120
121  /* limit label and entry */
122  label = gtk_label_new(_("Maximum upload speed:"));
123  gtk_misc_set_alignment(GTK_MISC(label), 0, 1.0/3.0);
124  pref = cf_getpref(PREF_LIMIT);
125  gtk_spin_button_set_value(GTK_SPIN_BUTTON(limitnum),
126    (NULL == pref ? DEFAULT_UPLIMIT : strtol(pref,NULL,10)));
127  gtk_table_attach_defaults(GTK_TABLE(table), label,            0, 1, 2, 3);
128  gtk_table_attach_defaults(GTK_TABLE(table), limitnum,         1, 2, 2, 3);
129  array[0] = label;
130  array[1] = limitnum;
131  clicklimitbox(limitbox, array);
132
133  /* directory label and chooser */
134  label = gtk_label_new(_("Download Directory:"));
135  gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
136  if(NULL != (pref = cf_getpref(PREF_DIR)))
137    gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dirstr), pref);
138  gtk_table_attach_defaults(GTK_TABLE(table), label,            0, 1, 3, 4);
139  gtk_table_attach_defaults(GTK_TABLE(table), dirstr,           1, 2, 3, 4);
140
141  gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(wind)->vbox), table);
142  g_signal_connect_data(wind, "response", G_CALLBACK(clickdialog),
143                        data, (GClosureNotify)g_free, 0);
144  gtk_widget_show_all(wind);
145}
146
147static void
148clicklimitbox(GtkWidget *widget, gpointer gdata) {
149  GtkWidget **widgets = gdata;
150  int ii;
151
152  for(ii = 0; 2 > ii; ii++)
153    gtk_widget_set_sensitive(widgets[ii],
154      gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
155}
156
157static void
158clickdialog(GtkWidget *widget, int resp, gpointer gdata) {
159  struct prefdata *data = gdata;
160  int intval;
161  const char *strval;
162  char *strnum, *errstr;
163  gboolean boolval;
164
165  if(GTK_RESPONSE_OK == resp) {
166    /* check directory */
167    if(NULL != (strval = gtk_file_chooser_get_current_folder(data->dir))) {
168      if(!mkdir_p(strval, 0777)) {
169        errmsg(data->parent,
170               _("An error occurred while creating the directory %s:\n%s"),
171               strval, strerror(errno));
172        return;
173      }
174
175      /* save dir pref */
176      cf_setpref(PREF_DIR, strval);
177    }
178
179    /* save port pref */
180    strnum = g_strdup_printf("%i",
181      gtk_spin_button_get_value_as_int(data->port));
182    cf_setpref(PREF_PORT, strnum);
183    g_free(strnum);
184
185    /* save uselimit pref */
186    boolval = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->uselimit));
187    cf_setpref(PREF_USELIMIT, (boolval ? "yes" : "no"));
188
189    /* save limit pref */
190    intval = gtk_spin_button_get_value_as_int(data->limit);
191    strnum = g_strdup_printf("%i", intval);
192    cf_setpref(PREF_LIMIT, strnum);
193
194    /* save prefs */
195    if(!cf_saveprefs(&errstr)) {
196      errmsg(data->parent, "%s", errstr);
197      g_free(strnum);
198      g_free(errstr);
199    }
200
201    tr_setBindPort(data->tr, gtk_spin_button_get_value_as_int(data->port));
202    setlimit(data->tr);
203  }
204
205  gtk_widget_destroy(widget);
206}
207
208void
209setlimit(tr_handle_t *tr) {
210  const char *pref;
211
212  if(NULL != (pref = cf_getpref(PREF_USELIMIT)) && !strbool(pref))
213    tr_setUploadLimit(tr, -1);
214  else if(NULL != (pref = cf_getpref(PREF_LIMIT)))
215    tr_setUploadLimit(tr, strtol(pref, NULL, 10));
216  else
217    tr_setUploadLimit(tr, DEFAULT_UPLIMIT);
218}
219
220void
221makeaddwind(add_torrent_func_t addfunc, GtkWindow *parent, tr_handle_t *tr,
222            torrents_added_func_t donefunc, void *donedata) {
223  GtkWidget *wind = gtk_file_chooser_dialog_new(_("Add a Torrent"), parent,
224    GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
225    GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
226  struct addcb *data = g_new(struct addcb, 1);
227  GtkWidget *vbox = gtk_vbox_new(FALSE, 3);
228  GtkWidget *bbox = gtk_hbutton_box_new();
229  GtkWidget *autocheck = gtk_check_button_new_with_label(
230    _("Automatically start torrent"));
231  GtkWidget *dircheck = gtk_check_button_new_with_label(
232    _("Use alternate download directory"));
233  GtkFileFilter *filter = gtk_file_filter_new();
234  GtkFileFilter *unfilter = gtk_file_filter_new();
235  GtkWidget *getdir = gtk_file_chooser_button_new(
236    _("Choose a download directory"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
237  const char *pref;
238
239  data->addfunc = addfunc;
240  data->parent = parent;
241  data->tr = tr;
242  data->donefunc = donefunc;
243  data->donedata = donedata;
244  data->autostart = TRUE;
245  data->usingaltdir = FALSE;
246  data->altdir = GTK_FILE_CHOOSER(getdir);
247  data->altbox = GTK_BUTTON_BOX(bbox);
248
249  gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_START);
250  gtk_box_pack_start_defaults(GTK_BOX(bbox), dircheck);
251  gtk_box_pack_start_defaults(GTK_BOX(bbox), getdir);
252
253  gtk_box_pack_start_defaults(GTK_BOX(vbox), autocheck);
254  gtk_box_pack_start_defaults(GTK_BOX(vbox), bbox);
255
256  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(autocheck), TRUE);
257  if(NULL != (pref = cf_getpref(PREF_DIR)))
258    gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(getdir), pref);
259
260  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dircheck), FALSE);
261
262  gtk_file_filter_set_name(filter, _("Torrent files"));
263  gtk_file_filter_add_pattern(filter, "*.torrent");
264  gtk_file_filter_set_name(unfilter, _("All files"));
265  gtk_file_filter_add_pattern(unfilter, "*");
266
267  gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(wind), filter);
268  gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(wind), unfilter);
269  gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(wind), TRUE);
270  gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(wind), vbox);
271
272  g_signal_connect(G_OBJECT(autocheck), "clicked", G_CALLBACK(autoclick),data);
273  g_signal_connect(G_OBJECT(dircheck), "clicked", G_CALLBACK(dirclick), data);
274  g_signal_connect(G_OBJECT(wind), "response", G_CALLBACK(addresp), data);
275
276  gtk_widget_show_all(wind);
277  gtk_widget_hide(getdir);
278}
279
280static void
281autoclick(GtkWidget *widget, gpointer gdata) {
282  struct addcb *data = gdata;
283
284  data->autostart = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
285}
286
287static void
288dirclick(GtkWidget *widget, gpointer gdata) {
289  struct addcb *data = gdata;
290
291  data->usingaltdir = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
292  gtk_button_box_set_layout(data->altbox,
293    (data->usingaltdir ? GTK_BUTTONBOX_EDGE : GTK_BUTTONBOX_START));
294  if(data->usingaltdir)
295    gtk_widget_show(GTK_WIDGET(data->altdir));
296  else
297    gtk_widget_hide(GTK_WIDGET(data->altdir));
298}
299
300static void
301addresp(GtkWidget *widget, gint resp, gpointer gdata) {
302  struct addcb *data = gdata;
303  GSList *files, *ii;
304  gboolean added = FALSE;
305  char *dir = NULL;
306
307  if(GTK_RESPONSE_ACCEPT == resp) {
308    if(data->usingaltdir)
309      dir = gtk_file_chooser_get_filename(data->altdir);
310    files = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget));
311    for(ii = files; NULL != ii; ii = ii->next)
312      if(data->addfunc(data->tr, data->parent, ii->data, dir,
313                       !data->autostart))
314        added = TRUE;
315    if(added)
316      data->donefunc(data->donedata);
317    if(NULL != dir)
318      g_free(dir);
319  }
320
321  gtk_widget_destroy(widget);
322}
323
324#define INFOLINE(tab, ii, nam, val) \
325  do { \
326    char *txt = g_markup_printf_escaped("<b>%s</b>", nam); \
327    GtkWidget *wid = gtk_label_new(NULL); \
328    gtk_misc_set_alignment(GTK_MISC(wid), 1, .5); \
329    gtk_label_set_markup(GTK_LABEL(wid), txt); \
330    gtk_table_attach_defaults(GTK_TABLE(tab), wid, 0, 1, ii, ii + 1); \
331    wid = gtk_label_new(val); \
332    gtk_misc_set_alignment(GTK_MISC(wid), 0, .5); \
333    gtk_table_attach_defaults(GTK_TABLE(tab), wid, 1, 2, ii, ii + 1); \
334    ii++; \
335    g_free(txt); \
336  } while(0);
337
338#define INFOLINEF(tab, ii, fmt, nam, val) \
339  do { \
340    char *buf = g_strdup_printf(fmt, val); \
341    INFOLINE(tab, ii, nam, buf); \
342    g_free(buf); \
343  } while(0);
344
345#define INFOLINEA(tab, ii, nam, val) \
346  do { \
347    char *buf = val; \
348    INFOLINE(tab, ii, nam, buf); \
349    g_free(buf); \
350  } while(0);
351
352#define INFOSEP(tab, ii) \
353  do { \
354    GtkWidget *wid = gtk_hseparator_new(); \
355    gtk_table_attach_defaults(GTK_TABLE(tab), wid, 0, 2, ii, ii + 1); \
356    ii++; \
357  } while(0);
358
359void
360makeinfowind(GtkWindow *parent, tr_handle_t *tr, int id) {
361  tr_stat_t *sb;
362  GtkWidget *wind, *table, *label;
363  int ii;
364  char *str;
365  const int rowcount = 12;
366
367  /* XXX would be nice to be able to stat just one */
368  if(id >= tr_torrentStat(tr, &sb))
369    assert(!"XXX ");
370  str = g_strdup_printf(_("%s Properties"), sb[id].info.name);
371  wind = gtk_dialog_new_with_buttons(str, parent,
372    GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
373    GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
374  g_free(str);
375
376  table = gtk_table_new(rowcount, 2, FALSE);
377  gtk_table_set_col_spacings(GTK_TABLE(table), 12);
378  gtk_table_set_row_spacings(GTK_TABLE(table), 12);
379
380  label = gtk_label_new(NULL);
381  str = g_markup_printf_escaped("<big>%s</big>", sb[id].info.name);
382  gtk_label_set_markup(GTK_LABEL(label), str);
383  g_free(str);
384  gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 2, 0, 1);
385
386  ii = 1;
387
388  INFOSEP(table, ii);
389
390  INFOLINEA(table, ii, _("Tracker:"), g_strdup_printf("http://%s:%i",
391            sb[id].info.trackerAddress, sb[id].info.trackerPort));
392  INFOLINE(table, ii, _("Announce:"), sb[id].info.trackerAnnounce);
393  INFOLINEA(table, ii, _("Piece Size:"), readablesize(sb[id].info.pieceSize, 1));
394  INFOLINEF(table, ii, "%i", _("Pieces:"), sb[id].info.pieceCount);
395  INFOLINEA(table, ii, _("Total Size:"), readablesize(sb[id].info.totalSize, 1));
396
397  INFOSEP(table, ii);
398
399  INFOLINE(table, ii, _("Directory:"), sb[id].folder);
400  INFOLINEA(table, ii, _("Downloaded:"), readablesize(sb[id].downloaded, 1));
401  INFOLINEA(table, ii, _("Uploaded:"), readablesize(sb[id].uploaded, 1));
402
403  INFOSEP(table, ii);
404
405  assert(rowcount == ii);
406
407  gtk_container_set_border_width(GTK_CONTAINER(table), 12);
408  gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(wind)->vbox), table);
409  g_signal_connect(G_OBJECT(wind), "response",
410                   G_CALLBACK(gtk_widget_destroy), NULL);
411  gtk_widget_show_all(wind);
412  free(sb);
413}
Note: See TracBrowser for help on using the repository browser.