source: trunk/gtk/dialogs.c @ 162

Last change on this file since 162 was 162, checked in by titer, 16 years ago

Merge from branches/new_api:r161

File size: 15.2 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  torrents_added_func_t donefunc;
53  void *data;
54  gboolean autostart;
55  gboolean usingaltdir;
56  GtkFileChooser *altdir;
57  GtkButtonBox *altbox;
58};
59
60static void
61windclosed(GtkWidget *widget SHUTUP, gpointer gdata);
62static void
63clicklimitbox(GtkWidget *widget, gpointer gdata);
64static void
65clickdialog(GtkWidget *widget, int resp, gpointer gdata);
66static void
67autoclick(GtkWidget *widget, gpointer gdata);
68static void
69dirclick(GtkWidget *widget, gpointer gdata);
70static void
71addresp(GtkWidget *widget, gint resp, gpointer gdata);
72
73void
74makeprefwindow(GtkWindow *parent, tr_handle_t *tr, gboolean *opened) {
75  char *title = g_strdup_printf(_("%s Preferences"), g_get_application_name());
76  GtkWidget *wind = gtk_dialog_new_with_buttons(title, parent,
77   GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
78   GTK_STOCK_APPLY, GTK_RESPONSE_APPLY, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
79   GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
80  GtkWidget *table = gtk_table_new(4, 2, FALSE);
81  GtkWidget *portnum = gtk_spin_button_new_with_range(1, 0xffff, 1);
82  GtkWidget *limitbox = gtk_check_button_new_with_mnemonic(
83    _("_Limit upload speed"));
84  GtkWidget *limitnum = gtk_spin_button_new_with_range(0, G_MAXLONG, 1);
85  GtkWidget *dirstr = gtk_file_chooser_button_new(
86    _("Choose download directory"),
87    GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
88  GtkWidget *label;
89  GtkWidget **array;
90  const char *pref;
91  struct prefdata *data = g_new0(struct prefdata, 1);
92
93  *opened = TRUE;
94
95  g_free(title);
96  gtk_widget_set_name(wind, "TransmissionDialog");
97  gtk_table_set_col_spacings(GTK_TABLE(table), 12);
98  gtk_table_set_row_spacings(GTK_TABLE(table), 12);
99  gtk_dialog_set_default_response(GTK_DIALOG(wind), GTK_RESPONSE_OK);
100  gtk_container_set_border_width(GTK_CONTAINER(table), 6);
101  gtk_window_set_resizable(GTK_WINDOW(wind), FALSE);
102
103  data->port = GTK_SPIN_BUTTON(portnum);
104  data->uselimit = GTK_CHECK_BUTTON(limitbox);
105  data->limit = GTK_SPIN_BUTTON(limitnum);
106  data->dir = GTK_FILE_CHOOSER(dirstr);
107  data->parent = parent;
108  data->tr = tr;
109
110  /* limit checkbox */
111  pref = cf_getpref(PREF_USELIMIT);
112  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(limitbox),
113    (NULL == pref ? TRUE : strbool(pref)));
114  array = g_new(GtkWidget*, 2);
115  g_signal_connect_data(limitbox, "clicked", G_CALLBACK(clicklimitbox),
116                        array, (GClosureNotify)g_free, 0);
117  gtk_table_attach_defaults(GTK_TABLE(table), limitbox,         0, 2, 0, 1);
118
119  /* limit label and entry */
120  label = gtk_label_new_with_mnemonic(_("Maximum _upload speed:"));
121  gtk_label_set_mnemonic_widget(GTK_LABEL(label), limitnum);
122  gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
123  pref = cf_getpref(PREF_LIMIT);
124  gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(limitnum), TRUE);
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, 1, 2);
128  gtk_table_attach_defaults(GTK_TABLE(table), limitnum,         1, 2, 1, 2);
129  array[0] = label;
130  array[1] = limitnum;
131  clicklimitbox(limitbox, array);
132
133  /* directory label and chooser */
134  label = gtk_label_new_with_mnemonic(_("_Download directory:"));
135  gtk_label_set_mnemonic_widget(GTK_LABEL(label), dirstr);
136  gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
137  if(NULL != (pref = cf_getpref(PREF_DIR)))
138    gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dirstr), pref);
139  gtk_table_attach_defaults(GTK_TABLE(table), label,            0, 1, 2, 3);
140  gtk_table_attach_defaults(GTK_TABLE(table), dirstr,           1, 2, 2, 3);
141
142  /* port label and entry */
143  label = gtk_label_new_with_mnemonic(_("Listening _port:"));
144  gtk_label_set_mnemonic_widget(GTK_LABEL(label), portnum);
145  gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
146  pref = cf_getpref(PREF_PORT);
147  gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(portnum), TRUE);
148  gtk_spin_button_set_value(GTK_SPIN_BUTTON(portnum),
149    (NULL == pref ? TR_DEFAULT_PORT : strtol(pref, NULL, 10)));
150  gtk_table_attach_defaults(GTK_TABLE(table), label,            0, 1, 3, 4);
151  gtk_table_attach_defaults(GTK_TABLE(table), portnum,          1, 2, 3, 4);
152
153  gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(wind)->vbox), table);
154  g_signal_connect_data(wind, "response", G_CALLBACK(clickdialog),
155                        data, (GClosureNotify)g_free, 0);
156  g_signal_connect(wind, "destroy", G_CALLBACK(windclosed), opened);
157  gtk_widget_show_all(wind);
158}
159
160static void
161windclosed(GtkWidget *widget SHUTUP, gpointer gdata) {
162  gboolean *preachy_gcc = gdata;
163 
164  *preachy_gcc = FALSE;
165}
166
167static void
168clicklimitbox(GtkWidget *widget, gpointer gdata) {
169  GtkWidget **widgets = gdata;
170  int ii;
171
172  for(ii = 0; 2 > ii; ii++)
173    gtk_widget_set_sensitive(widgets[ii],
174      gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
175}
176
177static void
178clickdialog(GtkWidget *widget, int resp, gpointer gdata) {
179  struct prefdata *data = gdata;
180  int intval;
181  const char *strval;
182  char *strnum, *errstr;
183  gboolean boolval;
184
185  if(GTK_RESPONSE_APPLY == resp || GTK_RESPONSE_OK == resp) {
186    /* check directory */
187    if(NULL != (strval = gtk_file_chooser_get_current_folder(data->dir))) {
188      if(!mkdir_p(strval, 0777)) {
189        errmsg(data->parent,
190               _("Failed to create the directory %s:\n%s"),
191               strval, strerror(errno));
192        return;
193      }
194
195      /* save dir pref */
196      cf_setpref(PREF_DIR, strval);
197    }
198
199    /* save port pref */
200    strnum = g_strdup_printf("%i",
201      gtk_spin_button_get_value_as_int(data->port));
202    cf_setpref(PREF_PORT, strnum);
203    g_free(strnum);
204
205    /* save uselimit pref */
206    boolval = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->uselimit));
207    cf_setpref(PREF_USELIMIT, (boolval ? "yes" : "no"));
208
209    /* save limit pref */
210    intval = gtk_spin_button_get_value_as_int(data->limit);
211    strnum = g_strdup_printf("%i", intval);
212    cf_setpref(PREF_LIMIT, strnum);
213
214    /* save prefs */
215    if(!cf_saveprefs(&errstr)) {
216      errmsg(data->parent, "%s", errstr);
217      g_free(strnum);
218      g_free(errstr);
219    }
220
221    /* XXX would be nice to have errno strings, are they printed to stdout? */
222    tr_setBindPort(data->tr, gtk_spin_button_get_value_as_int(data->port));
223    setlimit(data->tr);
224  }
225
226  if(GTK_RESPONSE_APPLY != resp)
227    gtk_widget_destroy(widget);
228}
229
230void
231setlimit(tr_handle_t *tr) {
232  const char *pref;
233
234  if(NULL != (pref = cf_getpref(PREF_USELIMIT)) && !strbool(pref))
235    tr_setUploadLimit(tr, -1);
236  else if(NULL != (pref = cf_getpref(PREF_LIMIT)))
237    tr_setUploadLimit(tr, strtol(pref, NULL, 10));
238  else
239    tr_setUploadLimit(tr, DEFAULT_UPLIMIT);
240}
241
242void
243makeaddwind(GtkWindow *parent, add_torrent_func_t addfunc,
244            torrents_added_func_t donefunc, void *cbdata) {
245  GtkWidget *wind = gtk_file_chooser_dialog_new(_("Add a Torrent"), parent,
246    GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
247    GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
248  struct addcb *data = g_new(struct addcb, 1);
249  GtkWidget *vbox = gtk_vbox_new(FALSE, 3);
250  GtkWidget *bbox = gtk_hbutton_box_new();
251  GtkWidget *autocheck = gtk_check_button_new_with_mnemonic(
252    _("Automatically _start torrent"));
253  GtkWidget *dircheck = gtk_check_button_new_with_mnemonic(
254    _("Use alternate _download directory"));
255  GtkFileFilter *filter = gtk_file_filter_new();
256  GtkFileFilter *unfilter = gtk_file_filter_new();
257  GtkWidget *getdir = gtk_file_chooser_button_new(
258    _("Choose a download directory"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
259  const char *pref;
260
261  data->addfunc = addfunc;
262  data->parent = parent;
263  data->donefunc = donefunc;
264  data->data = cbdata;
265  data->autostart = TRUE;
266  data->usingaltdir = FALSE;
267  data->altdir = GTK_FILE_CHOOSER(getdir);
268  data->altbox = GTK_BUTTON_BOX(bbox);
269
270  gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_EDGE);
271  gtk_box_pack_start_defaults(GTK_BOX(bbox), dircheck);
272  gtk_box_pack_start_defaults(GTK_BOX(bbox), getdir);
273
274  gtk_box_pack_start_defaults(GTK_BOX(vbox), autocheck);
275  gtk_box_pack_start_defaults(GTK_BOX(vbox), bbox);
276
277  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(autocheck), TRUE);
278  if(NULL != (pref = cf_getpref(PREF_DIR)))
279    gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(getdir), pref);
280
281  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dircheck), FALSE);
282  gtk_widget_set_sensitive(getdir, FALSE);
283
284  gtk_file_filter_set_name(filter, _("Torrent files"));
285  gtk_file_filter_add_pattern(filter, "*.torrent");
286  gtk_file_filter_set_name(unfilter, _("All files"));
287  gtk_file_filter_add_pattern(unfilter, "*");
288
289  gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(wind), filter);
290  gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(wind), unfilter);
291  gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(wind), TRUE);
292  gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(wind), vbox);
293
294  g_signal_connect(G_OBJECT(autocheck), "clicked", G_CALLBACK(autoclick),data);
295  g_signal_connect(G_OBJECT(dircheck), "clicked", G_CALLBACK(dirclick), data);
296  g_signal_connect(G_OBJECT(wind), "response", G_CALLBACK(addresp), data);
297
298  gtk_widget_show_all(wind);
299}
300
301static void
302autoclick(GtkWidget *widget, gpointer gdata) {
303  struct addcb *data = gdata;
304
305  data->autostart = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
306}
307
308static void
309dirclick(GtkWidget *widget, gpointer gdata) {
310  struct addcb *data = gdata;
311
312  data->usingaltdir = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
313  gtk_widget_set_sensitive(GTK_WIDGET(data->altdir), data->usingaltdir);
314}
315
316static void
317addresp(GtkWidget *widget, gint resp, gpointer gdata) {
318  struct addcb *data = gdata;
319  GSList *files, *ii;
320  gboolean added = FALSE;
321  char *dir = NULL;
322
323  if(GTK_RESPONSE_ACCEPT == resp) {
324    if(data->usingaltdir)
325      dir = gtk_file_chooser_get_filename(data->altdir);
326    files = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget));
327    for(ii = files; NULL != ii; ii = ii->next)
328      if(data->addfunc(data->data, ii->data, dir,
329                       /* XXX need to group errors here */
330                       !data->autostart, NULL))
331        added = TRUE;
332    if(added)
333      data->donefunc(data->data);
334    if(NULL != dir)
335      g_free(dir);
336  }
337
338  gtk_widget_destroy(widget);
339}
340
341#define INFOLINE(tab, ii, nam, val) \
342  do { \
343    char *txt = g_markup_printf_escaped("<b>%s</b>", nam); \
344    GtkWidget *wid = gtk_label_new(NULL); \
345    gtk_misc_set_alignment(GTK_MISC(wid), 1, .5); \
346    gtk_label_set_markup(GTK_LABEL(wid), txt); \
347    gtk_table_attach_defaults(GTK_TABLE(tab), wid, 0, 1, ii, ii + 1); \
348    wid = gtk_label_new(val); \
349    gtk_label_set_selectable(GTK_LABEL(wid), TRUE); \
350    gtk_misc_set_alignment(GTK_MISC(wid), 0, .5); \
351    gtk_table_attach_defaults(GTK_TABLE(tab), wid, 1, 2, ii, ii + 1); \
352    ii++; \
353    g_free(txt); \
354  } while(0)
355
356#define INFOLINEF(tab, ii, fmt, nam, val) \
357  do { \
358    char *buf = g_strdup_printf(fmt, val); \
359    INFOLINE(tab, ii, nam, buf); \
360    g_free(buf); \
361  } while(0)
362
363#define INFOLINEA(tab, ii, nam, val) \
364  do { \
365    char *buf = val; \
366    INFOLINE(tab, ii, nam, buf); \
367    g_free(buf); \
368  } while(0)
369
370#define INFOSEP(tab, ii) \
371  do { \
372    GtkWidget *wid = gtk_hseparator_new(); \
373    gtk_table_attach_defaults(GTK_TABLE(tab), wid, 0, 2, ii, ii + 1); \
374    ii++; \
375  } while(0)
376
377void
378makeinfowind(GtkWindow *parent, tr_torrent_t *tor) {
379  tr_stat_t *sb;
380  tr_info_t *in;
381  GtkWidget *wind, *label;
382  int ii;
383  char *str;
384  const int rowcount = 14;
385  GtkWidget *table = gtk_table_new(rowcount, 2, FALSE);
386
387  sb = tr_torrentStat(tor);
388  in = tr_torrentInfo(tor);
389  str = g_strdup_printf(_("%s Properties"), in->name);
390  wind = gtk_dialog_new_with_buttons(str, parent,
391    GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
392    GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
393  g_free(str);
394
395  gtk_widget_set_name(wind, "TransmissionDialog");
396  gtk_table_set_col_spacings(GTK_TABLE(table), 12);
397  gtk_table_set_row_spacings(GTK_TABLE(table), 12);
398  gtk_dialog_set_default_response(GTK_DIALOG(wind), GTK_RESPONSE_ACCEPT);
399  gtk_container_set_border_width(GTK_CONTAINER(table), 6);
400  gtk_window_set_resizable(GTK_WINDOW(wind), FALSE);
401
402  label = gtk_label_new(NULL);
403  gtk_label_set_selectable(GTK_LABEL(label), TRUE);
404  str = g_markup_printf_escaped("<big>%s</big>", in->name);
405  gtk_label_set_markup(GTK_LABEL(label), str);
406  g_free(str);
407  gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 2, 0, 1);
408
409  ii = 1;
410
411  INFOSEP(table, ii);
412
413  if(80 == in->trackerPort)
414    INFOLINEA(table, ii, _("Tracker:"), g_strdup_printf("http://%s",
415              in->trackerAddress));
416  else
417    INFOLINEA(table, ii, _("Tracker:"), g_strdup_printf("http://%s:%i",
418              in->trackerAddress, in->trackerPort));
419  INFOLINE(table, ii, _("Announce:"), in->trackerAnnounce);
420  INFOLINEA(table, ii, _("Piece Size:"), readablesize(in->pieceSize));
421  INFOLINEF(table, ii, "%i", _("Pieces:"), in->pieceCount);
422  INFOLINEA(table, ii, _("Total Size:"), readablesize(in->totalSize));
423  if(0 > sb->seeders)
424    INFOLINE(table, ii, _("Seeders:"), _("?"));
425  else
426    INFOLINEF(table, ii, "%i", _("Seeders:"), sb->seeders);
427  if(0 > sb->leechers)
428    INFOLINE(table, ii, _("Leechers:"), _("?"));
429  else
430    INFOLINEF(table, ii, "%i", _("Leechers:"), sb->leechers);
431
432  INFOSEP(table, ii);
433
434  INFOLINE(table, ii, _("Directory:"), tr_torrentGetFolder(tor));
435  INFOLINEA(table, ii, _("Downloaded:"), readablesize(sb->downloaded));
436  INFOLINEA(table, ii, _("Uploaded:"), readablesize(sb->uploaded));
437
438  INFOSEP(table, ii);
439
440  assert(rowcount == ii);
441
442  gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(wind)->vbox), table);
443  g_signal_connect(G_OBJECT(wind), "response",
444                   G_CALLBACK(gtk_widget_destroy), NULL);
445  gtk_widget_show_all(wind);
446}
Note: See TracBrowser for help on using the repository browser.