source: trunk/gtk/dialogs.c @ 70

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

Rename a few files now that we're using subversion and it's easy.

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