source: branches/joshe/gtk/dialogs.c @ 77

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

Add internationalization support.

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, _("Failed to create directory %s:\n%s"),
170               strval, strerror(errno));
171        return;
172      }
173
174      /* save dir pref */
175      cf_setpref(PREF_DIR, strval);
176    }
177
178    /* save port pref */
179    strnum = g_strdup_printf("%i",
180      gtk_spin_button_get_value_as_int(data->port));
181    cf_setpref(PREF_PORT, strnum);
182    g_free(strnum);
183
184    /* save uselimit pref */
185    boolval = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->uselimit));
186    cf_setpref(PREF_USELIMIT, (boolval ? "yes" : "no"));
187
188    /* save limit pref */
189    intval = gtk_spin_button_get_value_as_int(data->limit);
190    strnum = g_strdup_printf("%i", intval);
191    cf_setpref(PREF_LIMIT, strnum);
192
193    /* save prefs */
194    if(!cf_saveprefs(&errstr)) {
195      errmsg(data->parent, "%s", errstr);
196      g_free(strnum);
197      g_free(errstr);
198    }
199
200    tr_setBindPort(data->tr, gtk_spin_button_get_value_as_int(data->port));
201    setlimit(data->tr);
202  }
203
204  gtk_widget_destroy(widget);
205}
206
207void
208setlimit(tr_handle_t *tr) {
209  const char *pref;
210
211  if(NULL != (pref = cf_getpref(PREF_USELIMIT)) && !strbool(pref))
212    tr_setUploadLimit(tr, -1);
213  else if(NULL != (pref = cf_getpref(PREF_LIMIT)))
214    tr_setUploadLimit(tr, strtol(pref, NULL, 10));
215  else
216    tr_setUploadLimit(tr, DEFAULT_UPLIMIT);
217}
218
219void
220makeaddwind(add_torrent_func_t addfunc, GtkWindow *parent, tr_handle_t *tr,
221            torrents_added_func_t donefunc, void *donedata) {
222  GtkWidget *wind = gtk_file_chooser_dialog_new(_("Add a Torrent"), parent,
223    GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
224    GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
225  struct addcb *data = g_new(struct addcb, 1);
226  GtkWidget *vbox = gtk_vbox_new(FALSE, 3);
227  GtkWidget *bbox = gtk_hbutton_box_new();
228  GtkWidget *autocheck = gtk_check_button_new_with_label(
229    _("Automatically start torrent"));
230  GtkWidget *dircheck = gtk_check_button_new_with_label(
231    _("Use alternate download directory"));
232  GtkFileFilter *filter = gtk_file_filter_new();
233  GtkFileFilter *unfilter = gtk_file_filter_new();
234  GtkWidget *getdir = gtk_file_chooser_button_new(
235    _("Choose a download directory"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
236  const char *pref;
237
238  data->addfunc = addfunc;
239  data->parent = parent;
240  data->tr = tr;
241  data->donefunc = donefunc;
242  data->donedata = donedata;
243  data->autostart = TRUE;
244  data->usingaltdir = FALSE;
245  data->altdir = GTK_FILE_CHOOSER(getdir);
246  data->altbox = GTK_BUTTON_BOX(bbox);
247
248  gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_START);
249  gtk_box_pack_start_defaults(GTK_BOX(bbox), dircheck);
250  gtk_box_pack_start_defaults(GTK_BOX(bbox), getdir);
251
252  gtk_box_pack_start_defaults(GTK_BOX(vbox), autocheck);
253  gtk_box_pack_start_defaults(GTK_BOX(vbox), bbox);
254
255  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(autocheck), TRUE);
256  if(NULL != (pref = cf_getpref(PREF_DIR)))
257    gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(getdir), pref);
258
259  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dircheck), FALSE);
260
261  gtk_file_filter_set_name(filter, _("Torrent files"));
262  gtk_file_filter_add_pattern(filter, "*.torrent");
263  gtk_file_filter_set_name(unfilter, _("All files"));
264  gtk_file_filter_add_pattern(unfilter, "*");
265
266  gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(wind), filter);
267  gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(wind), unfilter);
268  gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(wind), TRUE);
269  gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(wind), vbox);
270
271  g_signal_connect(G_OBJECT(autocheck), "clicked", G_CALLBACK(autoclick),data);
272  g_signal_connect(G_OBJECT(dircheck), "clicked", G_CALLBACK(dirclick), data);
273  g_signal_connect(G_OBJECT(wind), "response", G_CALLBACK(addresp), data);
274
275  gtk_widget_show_all(wind);
276  gtk_widget_hide(getdir);
277}
278
279static void
280autoclick(GtkWidget *widget, gpointer gdata) {
281  struct addcb *data = gdata;
282
283  data->autostart = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
284}
285
286static void
287dirclick(GtkWidget *widget, gpointer gdata) {
288  struct addcb *data = gdata;
289
290  data->usingaltdir = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
291  gtk_button_box_set_layout(data->altbox,
292    (data->usingaltdir ? GTK_BUTTONBOX_EDGE : GTK_BUTTONBOX_START));
293  if(data->usingaltdir)
294    gtk_widget_show(GTK_WIDGET(data->altdir));
295  else
296    gtk_widget_hide(GTK_WIDGET(data->altdir));
297}
298
299static void
300addresp(GtkWidget *widget, gint resp, gpointer gdata) {
301  struct addcb *data = gdata;
302  GSList *files, *ii;
303  gboolean added = FALSE;
304  char *dir = NULL;
305
306  if(GTK_RESPONSE_ACCEPT == resp) {
307    if(data->usingaltdir)
308      dir = gtk_file_chooser_get_filename(data->altdir);
309    files = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget));
310    for(ii = files; NULL != ii; ii = ii->next)
311      if(data->addfunc(data->tr, data->parent, ii->data, dir,
312                       !data->autostart))
313        added = TRUE;
314    if(added)
315      data->donefunc(data->donedata);
316    if(NULL != dir)
317      g_free(dir);
318  }
319
320  gtk_widget_destroy(widget);
321}
322
323#define INFOLINE(tab, ii, nam, val) \
324  do { \
325    char *txt = g_markup_printf_escaped("<b>%s</b>", nam); \
326    GtkWidget *wid = gtk_label_new(NULL); \
327    gtk_misc_set_alignment(GTK_MISC(wid), 1, .5); \
328    gtk_label_set_markup(GTK_LABEL(wid), txt); \
329    gtk_table_attach_defaults(GTK_TABLE(tab), wid, 0, 1, ii, ii + 1); \
330    wid = gtk_label_new(val); \
331    gtk_misc_set_alignment(GTK_MISC(wid), 0, .5); \
332    gtk_table_attach_defaults(GTK_TABLE(tab), wid, 1, 2, ii, ii + 1); \
333    ii++; \
334    g_free(txt); \
335  } while(0);
336
337#define INFOLINEF(tab, ii, fmt, nam, val) \
338  do { \
339    char *buf = g_strdup_printf(fmt, val); \
340    INFOLINE(tab, ii, nam, buf); \
341    g_free(buf); \
342  } while(0);
343
344#define INFOLINEA(tab, ii, nam, val) \
345  do { \
346    char *buf = val; \
347    INFOLINE(tab, ii, nam, buf); \
348    g_free(buf); \
349  } while(0);
350
351#define INFOSEP(tab, ii) \
352  do { \
353    GtkWidget *wid = gtk_hseparator_new(); \
354    gtk_table_attach_defaults(GTK_TABLE(tab), wid, 0, 2, ii, ii + 1); \
355    ii++; \
356  } while(0);
357
358void
359makeinfowind(GtkWindow *parent, tr_handle_t *tr, int id) {
360  tr_stat_t *sb;
361  GtkWidget *wind, *table, *label;
362  int ii;
363  char *str;
364  const int rowcount = 12;
365
366  /* XXX would be nice to be able to stat just one */
367  if(id >= tr_torrentStat(tr, &sb))
368    assert(!"XXX ");
369  str = g_strdup_printf(_("%s Properties"), sb[id].info.name);
370  wind = gtk_dialog_new_with_buttons(str, parent,
371    GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
372    GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
373  g_free(str);
374
375  table = gtk_table_new(rowcount, 2, FALSE);
376  gtk_table_set_col_spacings(GTK_TABLE(table), 12);
377  gtk_table_set_row_spacings(GTK_TABLE(table), 12);
378
379  label = gtk_label_new(NULL);
380  str = g_markup_printf_escaped("<big>%s</big>", sb[id].info.name);
381  gtk_label_set_markup(GTK_LABEL(label), str);
382  g_free(str);
383  gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 2, 0, 1);
384
385  ii = 1;
386
387  INFOSEP(table, ii);
388
389  INFOLINEA(table, ii, _("Tracker:"), g_strdup_printf("http://%s:%i",
390            sb[id].info.trackerAddress, sb[id].info.trackerPort));
391  INFOLINE(table, ii, _("Announce:"), sb[id].info.trackerAnnounce);
392  INFOLINEA(table, ii, _("Piece Size:"), readablesize(sb[id].info.pieceSize, 1));
393  INFOLINEF(table, ii, "%i", _("Pieces:"), sb[id].info.pieceCount);
394  INFOLINEA(table, ii, _("Total Size:"), readablesize(sb[id].info.totalSize, 1));
395
396  INFOSEP(table, ii);
397
398  INFOLINE(table, ii, _("Directory:"), sb[id].folder);
399  INFOLINEA(table, ii, _("Downloaded:"), readablesize(sb[id].downloaded, 1));
400  INFOLINEA(table, ii, _("Uploaded:"), readablesize(sb[id].uploaded, 1));
401
402  INFOSEP(table, ii);
403
404  assert(rowcount == ii);
405
406  gtk_container_set_border_width(GTK_CONTAINER(table), 12);
407  gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(wind)->vbox), table);
408  g_signal_connect(G_OBJECT(wind), "response",
409                   G_CALLBACK(gtk_widget_destroy), NULL);
410  gtk_widget_show_all(wind);
411  free(sb);
412}
Note: See TracBrowser for help on using the repository browser.