source: trunk/gtk/dialogs.c @ 96

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

Show seeders and leechers in properties window.
Show ratio instead of download rate when torrent is finished.

File size: 15.1 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
62windclosed(GtkWidget *widget SHUTUP, gpointer gdata);
63static void
64clicklimitbox(GtkWidget *widget, gpointer gdata);
65static void
66clickdialog(GtkWidget *widget, int resp, gpointer gdata);
67static void
68autoclick(GtkWidget *widget, gpointer gdata);
69static void
70dirclick(GtkWidget *widget, gpointer gdata);
71static void
72addresp(GtkWidget *widget, gint resp, gpointer gdata);
73
74void
75makeprefwindow(GtkWindow *parent, tr_handle_t *tr, gboolean *opened) {
76  char *title = g_strdup_printf(_("%s Preferences"), g_get_application_name());
77  GtkWidget *wind = gtk_dialog_new_with_buttons(title, parent,
78   GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
79   GTK_STOCK_APPLY, GTK_RESPONSE_APPLY, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
80   GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
81  GtkWidget *table = gtk_table_new(4, 2, FALSE);
82  GtkWidget *portnum = gtk_spin_button_new_with_range(1, 0xffff, 1);
83  GtkWidget *limitbox = gtk_check_button_new_with_mnemonic(
84    _("_Limit upload speed"));
85  GtkWidget *limitnum = gtk_spin_button_new_with_range(0, G_MAXLONG, 1);
86  GtkWidget *dirstr = gtk_file_chooser_button_new(
87    _("Choose download directory"),
88    GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
89  GtkWidget *label;
90  GtkWidget **array;
91  const char *pref;
92  struct prefdata *data = g_new0(struct prefdata, 1);
93
94  *opened = TRUE;
95
96  g_free(title);
97  gtk_widget_set_name(wind, "TransmissionDialog");
98  gtk_table_set_col_spacings(GTK_TABLE(table), 12);
99  gtk_table_set_row_spacings(GTK_TABLE(table), 12);
100  gtk_dialog_set_default_response(GTK_DIALOG(wind), GTK_RESPONSE_OK);
101  gtk_container_set_border_width(GTK_CONTAINER(table), 6);
102  gtk_window_set_resizable(GTK_WINDOW(wind), FALSE);
103
104  data->port = GTK_SPIN_BUTTON(portnum);
105  data->uselimit = GTK_CHECK_BUTTON(limitbox);
106  data->limit = GTK_SPIN_BUTTON(limitnum);
107  data->dir = GTK_FILE_CHOOSER(dirstr);
108  data->parent = parent;
109  data->tr = tr;
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, 0, 1);
119
120  /* limit label and entry */
121  label = gtk_label_new_with_mnemonic(_("Maximum _upload speed:"));
122  gtk_label_set_mnemonic_widget(GTK_LABEL(label), limitnum);
123  gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
124  pref = cf_getpref(PREF_LIMIT);
125  gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(limitnum), TRUE);
126  gtk_spin_button_set_value(GTK_SPIN_BUTTON(limitnum),
127    (NULL == pref ? DEFAULT_UPLIMIT : strtol(pref,NULL,10)));
128  gtk_table_attach_defaults(GTK_TABLE(table), label,            0, 1, 1, 2);
129  gtk_table_attach_defaults(GTK_TABLE(table), limitnum,         1, 2, 1, 2);
130  array[0] = label;
131  array[1] = limitnum;
132  clicklimitbox(limitbox, array);
133
134  /* directory label and chooser */
135  label = gtk_label_new_with_mnemonic(_("_Download directory:"));
136  gtk_label_set_mnemonic_widget(GTK_LABEL(label), dirstr);
137  gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
138  if(NULL != (pref = cf_getpref(PREF_DIR)))
139    gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dirstr), pref);
140  gtk_table_attach_defaults(GTK_TABLE(table), label,            0, 1, 2, 3);
141  gtk_table_attach_defaults(GTK_TABLE(table), dirstr,           1, 2, 2, 3);
142
143  /* port label and entry */
144  label = gtk_label_new_with_mnemonic(_("Listening _port:"));
145  gtk_label_set_mnemonic_widget(GTK_LABEL(label), portnum);
146  gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
147  pref = cf_getpref(PREF_PORT);
148  gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(portnum), TRUE);
149  gtk_spin_button_set_value(GTK_SPIN_BUTTON(portnum),
150    (NULL == pref ? TR_DEFAULT_PORT : strtol(pref, NULL, 10)));
151  gtk_table_attach_defaults(GTK_TABLE(table), label,            0, 1, 3, 4);
152  gtk_table_attach_defaults(GTK_TABLE(table), portnum,          1, 2, 3, 4);
153
154  gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(wind)->vbox), table);
155  g_signal_connect_data(wind, "response", G_CALLBACK(clickdialog),
156                        data, (GClosureNotify)g_free, 0);
157  g_signal_connect(wind, "destroy", G_CALLBACK(windclosed), opened);
158  gtk_widget_show_all(wind);
159}
160
161static void
162windclosed(GtkWidget *widget SHUTUP, gpointer gdata) {
163  gboolean *preachy_gcc = gdata;
164 
165  *preachy_gcc = FALSE;
166}
167
168static void
169clicklimitbox(GtkWidget *widget, gpointer gdata) {
170  GtkWidget **widgets = gdata;
171  int ii;
172
173  for(ii = 0; 2 > ii; ii++)
174    gtk_widget_set_sensitive(widgets[ii],
175      gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
176}
177
178static void
179clickdialog(GtkWidget *widget, int resp, gpointer gdata) {
180  struct prefdata *data = gdata;
181  int intval;
182  const char *strval;
183  char *strnum, *errstr;
184  gboolean boolval;
185
186  if(GTK_RESPONSE_APPLY == resp || GTK_RESPONSE_OK == resp) {
187    /* check directory */
188    if(NULL != (strval = gtk_file_chooser_get_current_folder(data->dir))) {
189      if(!mkdir_p(strval, 0777)) {
190        errmsg(data->parent,
191               _("Failed to create the directory %s:\n%s"),
192               strval, strerror(errno));
193        return;
194      }
195
196      /* save dir pref */
197      cf_setpref(PREF_DIR, strval);
198    }
199
200    /* save port pref */
201    strnum = g_strdup_printf("%i",
202      gtk_spin_button_get_value_as_int(data->port));
203    cf_setpref(PREF_PORT, strnum);
204    g_free(strnum);
205
206    /* save uselimit pref */
207    boolval = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->uselimit));
208    cf_setpref(PREF_USELIMIT, (boolval ? "yes" : "no"));
209
210    /* save limit pref */
211    intval = gtk_spin_button_get_value_as_int(data->limit);
212    strnum = g_strdup_printf("%i", intval);
213    cf_setpref(PREF_LIMIT, strnum);
214
215    /* save prefs */
216    if(!cf_saveprefs(&errstr)) {
217      errmsg(data->parent, "%s", errstr);
218      g_free(strnum);
219      g_free(errstr);
220    }
221
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(add_torrent_func_t addfunc, GtkWindow *parent, tr_handle_t *tr,
244            torrents_added_func_t donefunc, void *donedata) {
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->tr = tr;
264  data->donefunc = donefunc;
265  data->donedata = donedata;
266  data->autostart = TRUE;
267  data->usingaltdir = FALSE;
268  data->altdir = GTK_FILE_CHOOSER(getdir);
269  data->altbox = GTK_BUTTON_BOX(bbox);
270
271  gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_EDGE);
272  gtk_box_pack_start_defaults(GTK_BOX(bbox), dircheck);
273  gtk_box_pack_start_defaults(GTK_BOX(bbox), getdir);
274
275  gtk_box_pack_start_defaults(GTK_BOX(vbox), autocheck);
276  gtk_box_pack_start_defaults(GTK_BOX(vbox), bbox);
277
278  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(autocheck), TRUE);
279  if(NULL != (pref = cf_getpref(PREF_DIR)))
280    gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(getdir), pref);
281
282  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dircheck), FALSE);
283  gtk_widget_set_sensitive(getdir, FALSE);
284
285  gtk_file_filter_set_name(filter, _("Torrent files"));
286  gtk_file_filter_add_pattern(filter, "*.torrent");
287  gtk_file_filter_set_name(unfilter, _("All files"));
288  gtk_file_filter_add_pattern(unfilter, "*");
289
290  gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(wind), filter);
291  gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(wind), unfilter);
292  gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(wind), TRUE);
293  gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(wind), vbox);
294
295  g_signal_connect(G_OBJECT(autocheck), "clicked", G_CALLBACK(autoclick),data);
296  g_signal_connect(G_OBJECT(dircheck), "clicked", G_CALLBACK(dirclick), data);
297  g_signal_connect(G_OBJECT(wind), "response", G_CALLBACK(addresp), data);
298
299  gtk_widget_show_all(wind);
300}
301
302static void
303autoclick(GtkWidget *widget, gpointer gdata) {
304  struct addcb *data = gdata;
305
306  data->autostart = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
307}
308
309static void
310dirclick(GtkWidget *widget, gpointer gdata) {
311  struct addcb *data = gdata;
312
313  data->usingaltdir = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
314  gtk_widget_set_sensitive(GTK_WIDGET(data->altdir), data->usingaltdir);
315}
316
317static void
318addresp(GtkWidget *widget, gint resp, gpointer gdata) {
319  struct addcb *data = gdata;
320  GSList *files, *ii;
321  gboolean added = FALSE;
322  char *dir = NULL;
323
324  if(GTK_RESPONSE_ACCEPT == resp) {
325    if(data->usingaltdir)
326      dir = gtk_file_chooser_get_filename(data->altdir);
327    files = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget));
328    for(ii = files; NULL != ii; ii = ii->next)
329      if(data->addfunc(data->tr, data->parent, ii->data, dir,
330                       !data->autostart, NULL))
331        added = TRUE;
332    if(added)
333      data->donefunc(data->donedata);
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_handle_t *tr, int id) {
379  tr_stat_t *sb;
380  GtkWidget *wind, *label;
381  int ii;
382  char *str;
383  const int rowcount = 14;
384  GtkWidget *table = gtk_table_new(rowcount, 2, FALSE);
385
386  /* XXX would be nice to be able to stat just one */
387  if(id >= tr_torrentStat(tr, &sb))
388    assert(!"XXX ");
389  str = g_strdup_printf(_("%s Properties"), sb[id].info.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>", sb[id].info.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 == sb[id].info.trackerPort)
414    INFOLINEA(table, ii, _("Tracker:"), g_strdup_printf("http://%s",
415              sb[id].info.trackerAddress));
416  else
417    INFOLINEA(table, ii, _("Tracker:"), g_strdup_printf("http://%s:%i",
418              sb[id].info.trackerAddress, sb[id].info.trackerPort));
419  INFOLINE(table, ii, _("Announce:"), sb[id].info.trackerAnnounce);
420  INFOLINEA(table, ii, _("Piece Size:"), readablesize(sb[id].info.pieceSize, 1));
421  INFOLINEF(table, ii, "%i", _("Pieces:"), sb[id].info.pieceCount);
422  INFOLINEA(table, ii, _("Total Size:"), readablesize(sb[id].info.totalSize, 1));
423  INFOLINEF(table, ii, "%i", _("Seeders:"), sb[id].seeders);
424  INFOLINEF(table, ii, "%i", _("Leechers:"), sb[id].leechers);
425
426  INFOSEP(table, ii);
427
428  INFOLINE(table, ii, _("Directory:"), sb[id].folder);
429  INFOLINEA(table, ii, _("Downloaded:"), readablesize(sb[id].downloaded, 1));
430  INFOLINEA(table, ii, _("Uploaded:"), readablesize(sb[id].uploaded, 1));
431
432  INFOSEP(table, ii);
433
434  assert(rowcount == ii);
435
436  gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(wind)->vbox), table);
437  g_signal_connect(G_OBJECT(wind), "response",
438                   G_CALLBACK(gtk_widget_destroy), NULL);
439  gtk_widget_show_all(wind);
440  free(sb);
441}
Note: See TracBrowser for help on using the repository browser.