source: trunk/gtk/dialogs.c @ 330

Last change on this file since 330 was 330, checked in by joshe, 15 years ago

Fix a recently-introduced memory leak.

  • Property svn:keywords set to Date Rev Author Id
File size: 20.5 KB
Line 
1/*
2  $Id: dialogs.c 330 2006-06-11 16:20:56Z joshe $
3
4  Copyright (c) 2005-2006 Joshua Elsasser. All rights reserved.
5   
6  Redistribution and use in source and binary forms, with or without
7  modification, are permitted provided that the following conditions
8  are met:
9   
10   1. Redistributions of source code must retain the above copyright
11      notice, this list of conditions and the following disclaimer.
12   2. Redistributions in binary form must reproduce the above copyright
13      notice, this list of conditions and the following disclaimer in the
14      documentation and/or other materials provided with the distribution.
15   
16  THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS "AS IS" AND
17  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  POSSIBILITY OF SUCH DAMAGE.
27*/
28
29#include <errno.h>
30#include <stdlib.h>
31#include <string.h>
32
33#include <gtk/gtk.h>
34#include <glib/gi18n.h>
35
36#include "conf.h"
37#include "dialogs.h"
38#include "transmission.h"
39#include "util.h"
40
41#define PREFNAME                "transmission-dialog-pref-name"
42
43/* default values for a couple prefs */
44#define DEF_DOWNLIMIT           100
45#define DEF_USEDOWNLIMIT        FALSE
46#define DEF_UPLIMIT             20
47#define DEF_USEUPLIMIT          TRUE
48
49struct prefdata {
50  GList *prefwidgets;
51  GtkWindow *parent;
52  TrBackend *back;
53};
54
55struct addcb {
56  add_torrents_func_t addfunc;
57  GtkWindow *parent;
58  void *data;
59  gboolean autostart;
60  gboolean usingaltdir;
61  GtkFileChooser *altdir;
62  GtkButtonBox *altbox;
63};
64
65static void
66windclosed(GtkWidget *widget SHUTUP, gpointer gdata);
67static void
68clicklimitbox(GtkWidget *widget, gpointer gdata);
69static void
70freedata(gpointer gdata, GClosure *closure);
71static void
72clickdialog(GtkWidget *widget, int resp, gpointer gdata);
73static void
74autoclick(GtkWidget *widget, gpointer gdata);
75static void
76dirclick(GtkWidget *widget, gpointer gdata);
77static void
78addresp(GtkWidget *widget, gint resp, gpointer gdata);
79
80static void
81setupprefwidget(GtkWidget *widget, const char *prefname, ...) {
82  const char *pref = cf_getpref(prefname);
83  GtkTreeModel *model;
84  GtkTreeIter iter;
85  guint prefsflag, modelflag;
86  va_list ap;
87
88  g_object_set_data_full(G_OBJECT(widget), PREFNAME,
89                         g_strdup(prefname), (GDestroyNotify)g_free);
90
91  va_start(ap, prefname);
92
93  if(ISA(widget, GTK_TYPE_FILE_CHOOSER)) {
94    if(NULL != pref)
95      gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(widget), pref);
96  }
97  else if(ISA(widget, GTK_TYPE_SPIN_BUTTON))
98    gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget),
99      (NULL == pref ? va_arg(ap, long) : strtol(pref, NULL, 10)));
100  else if(ISA(widget, GTK_TYPE_TOGGLE_BUTTON))
101    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
102      (NULL == pref ? va_arg(ap, gboolean) : strbool(pref)));
103  else if(ISA(widget, GTK_TYPE_COMBO_BOX)) {
104    model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
105    prefsflag = addactionflag(pref);
106    if(gtk_tree_model_get_iter_first(model, &iter))
107      do {
108        gtk_tree_model_get(model, &iter, 1, &modelflag, -1);
109        if(modelflag == prefsflag) {
110          gtk_combo_box_set_active_iter(GTK_COMBO_BOX(widget), &iter);
111          break;
112        }
113      } while(gtk_tree_model_iter_next(model, &iter));
114  }
115  else {
116    g_assert_not_reached();
117  }
118
119  va_end(ap);
120}
121
122static void
123saveprefwidget(GtkWindow *parent, GtkWidget *widget) {
124  char *prefname;
125  const char *strval;
126  char *freeablestr;
127  GtkTreeModel *model;
128  GtkTreeIter iter;
129  guint uintval;
130
131  strval = NULL;
132  freeablestr = NULL;
133  if(ISA(widget, GTK_TYPE_FILE_CHOOSER)) {
134    strval = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(widget));
135    if(NULL != strval) {
136      if(!mkdir_p(strval, 0777)) {
137        errmsg(parent, _("Failed to create the directory %s:\n%s"),
138               strval, strerror(errno));
139        return;
140      }
141    }
142  }
143  else if(ISA(widget, GTK_TYPE_SPIN_BUTTON))
144    freeablestr = g_strdup_printf("%i",
145      gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget)));
146  else if(ISA(widget, GTK_TYPE_TOGGLE_BUTTON))
147    strval = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)) ?
148              "yes" : "no");
149  else if(ISA(widget, GTK_TYPE_COMBO_BOX)) {
150    if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget), &iter)) {
151      model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
152      gtk_tree_model_get(model, &iter, 1, &uintval, -1);
153      strval = addactionname(uintval);
154    }
155  }
156  else {
157    g_assert_not_reached();
158    return;
159  }
160
161  prefname = g_object_get_data(G_OBJECT(widget), PREFNAME);
162  g_assert(NULL != prefname);
163
164  if(NULL != strval)
165    cf_setpref(prefname, strval);
166  else if(NULL != freeablestr) {
167    cf_setpref(prefname, freeablestr);
168    g_free(freeablestr);
169  }
170}
171
172void
173makeprefwindow(GtkWindow *parent, TrBackend *back, gboolean *opened) {
174  char *title = g_strdup_printf(_("%s Preferences"), g_get_application_name());
175  GtkWidget *wind = gtk_dialog_new_with_buttons(title, parent,
176   GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
177   GTK_STOCK_APPLY, GTK_RESPONSE_APPLY, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
178   GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
179  const unsigned int rowcount = 8;
180  GtkWidget *table = gtk_table_new(rowcount, 2, FALSE);
181  GtkWidget *portnum = gtk_spin_button_new_with_range(1, 0xffff, 1);
182  GtkWidget *dirstr = gtk_file_chooser_button_new(
183    _("Choose a download directory"),
184    GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
185  GtkWidget *addstd = gtk_combo_box_new();
186  GtkWidget *addipc = gtk_combo_box_new();
187  GtkWidget *label;
188  GtkWidget **array;
189  struct prefdata *data = g_new0(struct prefdata, 1);
190  struct { GtkWidget *on; GtkWidget *num; GtkWidget *label; gboolean defuse;
191    const char *usepref; const char *numpref; long def; } lim[] = {
192    { gtk_check_button_new_with_mnemonic(_("_Limit download speed")),
193      gtk_spin_button_new_with_range(0, G_MAXLONG, 1),
194      gtk_label_new_with_mnemonic(_("Maximum _download speed:")),
195      DEF_USEDOWNLIMIT, PREF_USEDOWNLIMIT, PREF_DOWNLIMIT, DEF_DOWNLIMIT, },
196    { gtk_check_button_new_with_mnemonic(_("Li_mit upload speed")),
197      gtk_spin_button_new_with_range(0, G_MAXLONG, 1),
198      gtk_label_new_with_mnemonic(_("Maximum _upload speed:")),
199      DEF_USEUPLIMIT, PREF_USEUPLIMIT, PREF_UPLIMIT, DEF_UPLIMIT, },
200  };
201  unsigned int ii;
202  GtkTreeModel *model;
203  GtkTreeIter iter;
204  GtkCellRenderer *rend;
205
206  *opened = TRUE;
207
208  g_free(title);
209  gtk_widget_set_name(wind, "TransmissionDialog");
210  gtk_table_set_col_spacings(GTK_TABLE(table), 8);
211  gtk_table_set_row_spacings(GTK_TABLE(table), 8);
212  gtk_dialog_set_default_response(GTK_DIALOG(wind), GTK_RESPONSE_OK);
213  gtk_container_set_border_width(GTK_CONTAINER(table), 6);
214  gtk_window_set_resizable(GTK_WINDOW(wind), FALSE);
215
216  data->prefwidgets = makeglist(portnum, lim[0].on, lim[0].num, lim[1].on,
217    lim[1].num, dirstr, addstd, addipc, NULL);
218  data->parent = parent;
219  data->back = back;
220  g_object_ref(G_OBJECT(back));
221
222#define RN(n) (n), (n) + 1
223
224  for(ii = 0; ii < ALEN(lim); ii++) {
225    /* limit checkbox */
226    setupprefwidget(lim[ii].on, lim[ii].usepref, (gboolean)lim[ii].defuse);
227    array = g_new(GtkWidget*, 2);
228    g_signal_connect_data(lim[ii].on, "clicked", G_CALLBACK(clicklimitbox),
229                          array, (GClosureNotify)g_free, 0);
230    gtk_table_attach_defaults(GTK_TABLE(table), lim[ii].on,    0, 2, RN(ii*2));
231
232    /* limit label and entry */
233    gtk_label_set_mnemonic_widget(GTK_LABEL(lim[ii].label), lim[ii].num);
234    gtk_misc_set_alignment(GTK_MISC(lim[ii].label), 0, .5);
235    gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(lim[ii].num), TRUE);
236    setupprefwidget(lim[ii].num, lim[ii].numpref, (long)lim[ii].def);
237    gtk_table_attach_defaults(GTK_TABLE(table), lim[ii].label, 0,1,RN(ii*2+1));
238    gtk_table_attach_defaults(GTK_TABLE(table), lim[ii].num,   1,2,RN(ii*2+1));
239    array[0] = lim[ii].label;
240    array[1] = lim[ii].num;
241    clicklimitbox(lim[ii].on, array);
242  }
243  ii *= 2;
244
245  /* directory label and chooser */
246  label = gtk_label_new_with_mnemonic(_("Download di_rectory:"));
247  gtk_label_set_mnemonic_widget(GTK_LABEL(label), dirstr);
248  gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
249  setupprefwidget(dirstr, PREF_DIR);
250  gtk_table_attach_defaults(GTK_TABLE(table), label,           0, 1, RN(ii));
251  gtk_table_attach_defaults(GTK_TABLE(table), dirstr,          1, 2, RN(ii));
252  ii++;
253
254  /* port label and entry */
255  label = gtk_label_new_with_mnemonic(_("Listening _port:"));
256  gtk_label_set_mnemonic_widget(GTK_LABEL(label), portnum);
257  gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
258  gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(portnum), TRUE);
259  setupprefwidget(portnum, PREF_PORT, (long)TR_DEFAULT_PORT);
260  gtk_table_attach_defaults(GTK_TABLE(table), label,           0, 1, RN(ii));
261  gtk_table_attach_defaults(GTK_TABLE(table), portnum,         1, 2, RN(ii));
262  ii++;
263
264  /* create the model used by the three popup menus */
265  model = GTK_TREE_MODEL(gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT));
266  gtk_list_store_append(GTK_LIST_STORE(model), &iter);
267  gtk_list_store_set(GTK_LIST_STORE(model), &iter, 1, 0, 0,
268    _("Use the torrent file where it is"), -1);
269  gtk_list_store_append(GTK_LIST_STORE(model), &iter);
270  gtk_list_store_set(GTK_LIST_STORE(model), &iter, 1, TR_TORNEW_SAVE_COPY, 0,
271    _("Keep a copy of the torrent file"), -1);
272  gtk_list_store_append(GTK_LIST_STORE(model), &iter);
273  gtk_list_store_set(GTK_LIST_STORE(model), &iter, 1, TR_TORNEW_SAVE_MOVE, 0,
274    _("Keep a copy and remove the original"), -1);
275
276  /* std */
277  label = gtk_label_new_with_mnemonic(_("For torrents added _normally:"));
278  gtk_label_set_mnemonic_widget(GTK_LABEL(label), addstd);
279  gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
280  gtk_combo_box_set_model(GTK_COMBO_BOX(addstd), model);
281  rend = gtk_cell_renderer_text_new();
282  gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(addstd), rend, TRUE);
283  gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(addstd), rend, "text", 0);
284  setupprefwidget(addstd, PREF_ADDSTD);
285  gtk_table_attach_defaults(GTK_TABLE(table), label,           0, 1, RN(ii));
286  gtk_table_attach_defaults(GTK_TABLE(table), addstd,          1, 2, RN(ii));
287  ii++;
288
289  /* ipc */
290  label = gtk_label_new_with_mnemonic(
291    _("For torrents added e_xternally\n(via the command-line):"));
292  gtk_label_set_mnemonic_widget(GTK_LABEL(label), addipc);
293  gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
294  gtk_combo_box_set_model(GTK_COMBO_BOX(addipc), model);
295  rend = gtk_cell_renderer_text_new();
296  gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(addipc), rend, TRUE);
297  gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(addipc), rend, "text", 0);
298  setupprefwidget(addipc, PREF_ADDIPC);
299  gtk_table_attach_defaults(GTK_TABLE(table), label,           0, 1, RN(ii));
300  gtk_table_attach_defaults(GTK_TABLE(table), addipc,          1, 2, RN(ii));
301  ii++;
302
303#undef RN
304  g_assert(rowcount == ii);
305
306  gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(wind)->vbox), table);
307  g_signal_connect_data(wind, "response", G_CALLBACK(clickdialog),
308                        data, freedata, 0);
309  g_signal_connect(wind, "destroy", G_CALLBACK(windclosed), opened);
310  gtk_widget_show_all(wind);
311}
312
313static void
314windclosed(GtkWidget *widget SHUTUP, gpointer gdata) {
315  gboolean *preachy_gcc = gdata;
316 
317  *preachy_gcc = FALSE;
318}
319
320static void
321clicklimitbox(GtkWidget *widget, gpointer gdata) {
322  GtkWidget **widgets = gdata;
323  int ii;
324
325  for(ii = 0; 2 > ii; ii++)
326    gtk_widget_set_sensitive(widgets[ii],
327      gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
328}
329
330static void
331freedata(gpointer gdata, GClosure *closure SHUTUP) {
332  struct prefdata *data = gdata;
333
334  g_list_free(data->prefwidgets);
335  g_object_unref(G_OBJECT(data->back));
336  g_free(data);
337}
338
339static void
340clickdialog(GtkWidget *widget, int resp, gpointer gdata) {
341  struct prefdata *data = gdata;
342  char *errstr;
343  GList *ii;
344
345  if(GTK_RESPONSE_APPLY == resp || GTK_RESPONSE_OK == resp) {
346    /* save all the prefs */
347    for(ii = g_list_first(data->prefwidgets); NULL != ii; ii = ii->next)
348      saveprefwidget(data->parent, ii->data);
349
350    /* write prefs to disk */
351    cf_saveprefs(&errstr);
352    if(NULL != errstr) {
353      errmsg(data->parent, "%s", errstr);
354      g_free(errstr);
355    }
356
357    /* XXX would be nice to have errno strings, are they printed to stdout? */
358
359    tr_setBindPort(tr_backend_handle(data->back),
360                   strtol(cf_getpref(PREF_PORT), NULL, 10));
361    setlimit(data->back);
362  }
363
364  if(GTK_RESPONSE_APPLY != resp)
365    gtk_widget_destroy(widget);
366}
367
368void
369setlimit(TrBackend *back) {
370  struct { void (*func)(tr_handle_t*, int);
371    const char *use; const char *num; gboolean defuse; long def; } lim[] = {
372    {tr_setDownloadLimit, PREF_USEDOWNLIMIT, PREF_DOWNLIMIT,
373                          DEF_USEDOWNLIMIT,  DEF_DOWNLIMIT},
374    {tr_setUploadLimit,   PREF_USEUPLIMIT,   PREF_UPLIMIT,
375                          DEF_USEUPLIMIT,    DEF_UPLIMIT},
376  };
377  const char *pref;
378  unsigned int ii;
379  tr_handle_t *tr = tr_backend_handle(back);
380
381  for(ii = 0; ii < ALEN(lim); ii++) {
382    pref = cf_getpref(lim[ii].use);
383    if(!(NULL == pref ? lim[ii].defuse : strbool(pref)))
384      lim[ii].func(tr, -1);
385    else {
386      pref = cf_getpref(lim[ii].num);
387      lim[ii].func(tr, (NULL == pref ? lim[ii].def : strtol(pref, NULL, 10)));
388    }
389  }
390}
391
392void
393makeaddwind(GtkWindow *parent, add_torrents_func_t addfunc, void *cbdata) {
394  GtkWidget *wind = gtk_file_chooser_dialog_new(_("Add a Torrent"), parent,
395    GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
396    GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
397  struct addcb *data = g_new(struct addcb, 1);
398  GtkWidget *vbox = gtk_vbox_new(FALSE, 3);
399  GtkWidget *bbox = gtk_hbutton_box_new();
400  GtkWidget *autocheck = gtk_check_button_new_with_mnemonic(
401    _("Automatically _start torrent"));
402  GtkWidget *dircheck = gtk_check_button_new_with_mnemonic(
403    _("Use alternate _download directory"));
404  GtkFileFilter *filter = gtk_file_filter_new();
405  GtkFileFilter *unfilter = gtk_file_filter_new();
406  GtkWidget *getdir = gtk_file_chooser_button_new(
407    _("Choose a download directory"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
408  const char *pref;
409
410  data->addfunc = addfunc;
411  data->parent = parent;
412  data->data = cbdata;
413  data->autostart = TRUE;
414  data->usingaltdir = FALSE;
415  data->altdir = GTK_FILE_CHOOSER(getdir);
416  data->altbox = GTK_BUTTON_BOX(bbox);
417
418  gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_EDGE);
419  gtk_box_pack_start_defaults(GTK_BOX(bbox), dircheck);
420  gtk_box_pack_start_defaults(GTK_BOX(bbox), getdir);
421
422  gtk_box_pack_start_defaults(GTK_BOX(vbox), autocheck);
423  gtk_box_pack_start_defaults(GTK_BOX(vbox), bbox);
424
425  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(autocheck), TRUE);
426  if(NULL != (pref = cf_getpref(PREF_DIR)))
427    gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(getdir), pref);
428
429  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dircheck), FALSE);
430  gtk_widget_set_sensitive(getdir, FALSE);
431
432  gtk_file_filter_set_name(filter, _("Torrent files"));
433  gtk_file_filter_add_pattern(filter, "*.torrent");
434  gtk_file_filter_set_name(unfilter, _("All files"));
435  gtk_file_filter_add_pattern(unfilter, "*");
436
437  gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(wind), filter);
438  gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(wind), unfilter);
439  gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(wind), TRUE);
440  gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(wind), vbox);
441
442  g_signal_connect(G_OBJECT(autocheck), "clicked", G_CALLBACK(autoclick),data);
443  g_signal_connect(G_OBJECT(dircheck), "clicked", G_CALLBACK(dirclick), data);
444  g_signal_connect(G_OBJECT(wind), "response", G_CALLBACK(addresp), data);
445
446  gtk_widget_show_all(wind);
447}
448
449static void
450autoclick(GtkWidget *widget, gpointer gdata) {
451  struct addcb *data = gdata;
452
453  data->autostart = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
454}
455
456static void
457dirclick(GtkWidget *widget, gpointer gdata) {
458  struct addcb *data = gdata;
459
460  data->usingaltdir = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
461  gtk_widget_set_sensitive(GTK_WIDGET(data->altdir), data->usingaltdir);
462}
463
464static void
465addresp(GtkWidget *widget, gint resp, gpointer gdata) {
466  struct addcb *data = gdata;
467  GSList *files, *ii;
468  GList *stupidgtk;
469  gboolean paused;
470  char *dir;
471
472  if(GTK_RESPONSE_ACCEPT == resp) {
473    dir = NULL;
474    if(data->usingaltdir)
475      dir = gtk_file_chooser_get_filename(data->altdir);
476    files = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget));
477    stupidgtk = NULL;
478    for(ii = files; NULL != ii; ii = ii->next)
479      stupidgtk = g_list_append(stupidgtk, ii->data);
480    paused = !data->autostart;
481    data->addfunc(data->data, NULL, stupidgtk, dir,
482                  addactionflag(cf_getpref(PREF_ADDSTD)));
483    if(NULL != dir)
484      g_free(dir);
485    g_slist_free(files);
486    freestrlist(stupidgtk);
487  }
488
489  gtk_widget_destroy(widget);
490}
491
492#define INFOLINE(tab, ii, nam, val) \
493  do { \
494    char *txt = g_markup_printf_escaped("<b>%s</b>", nam); \
495    GtkWidget *wid = gtk_label_new(NULL); \
496    gtk_misc_set_alignment(GTK_MISC(wid), 0, .5); \
497    gtk_label_set_markup(GTK_LABEL(wid), txt); \
498    gtk_table_attach_defaults(GTK_TABLE(tab), wid, 0, 1, ii, ii + 1); \
499    wid = gtk_label_new(val); \
500    gtk_label_set_selectable(GTK_LABEL(wid), TRUE); \
501    gtk_misc_set_alignment(GTK_MISC(wid), 0, .5); \
502    gtk_table_attach_defaults(GTK_TABLE(tab), wid, 1, 2, ii, ii + 1); \
503    ii++; \
504    g_free(txt); \
505  } while(0)
506
507#define INFOLINEF(tab, ii, fmt, nam, val) \
508  do { \
509    char *buf = g_strdup_printf(fmt, val); \
510    INFOLINE(tab, ii, nam, buf); \
511    g_free(buf); \
512  } while(0)
513
514#define INFOLINEA(tab, ii, nam, val) \
515  do { \
516    char *buf = val; \
517    INFOLINE(tab, ii, nam, buf); \
518    g_free(buf); \
519  } while(0)
520
521#define INFOSEP(tab, ii) \
522  do { \
523    GtkWidget *wid = gtk_hseparator_new(); \
524    gtk_table_attach_defaults(GTK_TABLE(tab), wid, 0, 2, ii, ii + 1); \
525    ii++; \
526  } while(0)
527
528void
529makeinfowind(GtkWindow *parent, TrTorrent *tor) {
530  tr_stat_t *sb;
531  tr_info_t *in;
532  GtkWidget *wind, *label;
533  int ii;
534  char *str;
535  const int rowcount = 14;
536  GtkWidget *table = gtk_table_new(rowcount, 2, FALSE);
537
538  /* XXX should use model and update this window regularly */
539
540  sb = tr_torrent_stat(tor);
541  in = tr_torrent_info(tor);
542  str = g_strdup_printf(_("%s Properties"), in->name);
543  wind = gtk_dialog_new_with_buttons(str, parent,
544    GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
545    GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
546  g_free(str);
547
548  gtk_widget_set_name(wind, "TransmissionDialog");
549  gtk_table_set_col_spacings(GTK_TABLE(table), 12);
550  gtk_table_set_row_spacings(GTK_TABLE(table), 12);
551  gtk_dialog_set_default_response(GTK_DIALOG(wind), GTK_RESPONSE_ACCEPT);
552  gtk_container_set_border_width(GTK_CONTAINER(table), 6);
553  gtk_window_set_resizable(GTK_WINDOW(wind), FALSE);
554
555  label = gtk_label_new(NULL);
556  gtk_label_set_selectable(GTK_LABEL(label), TRUE);
557  str = g_markup_printf_escaped("<big>%s</big>", in->name);
558  gtk_label_set_markup(GTK_LABEL(label), str);
559  g_free(str);
560  gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 2, 0, 1);
561
562  ii = 1;
563
564  INFOSEP(table, ii);
565
566  if(80 == in->trackerPort)
567    INFOLINEA(table, ii, _("Tracker:"), g_strdup_printf("http://%s",
568              in->trackerAddress));
569  else
570    INFOLINEA(table, ii, _("Tracker:"), g_strdup_printf("http://%s:%i",
571              in->trackerAddress, in->trackerPort));
572  INFOLINE(table, ii, _("Announce:"), in->trackerAnnounce);
573  INFOLINEA(table, ii, _("Piece Size:"), readablesize(in->pieceSize));
574  INFOLINEF(table, ii, "%i", _("Pieces:"), in->pieceCount);
575  INFOLINEA(table, ii, _("Total Size:"), readablesize(in->totalSize));
576  if(0 > sb->seeders)
577    INFOLINE(table, ii, _("Seeders:"), _("?"));
578  else
579    INFOLINEF(table, ii, "%i", _("Seeders:"), sb->seeders);
580  if(0 > sb->leechers)
581    INFOLINE(table, ii, _("Leechers:"), _("?"));
582  else
583    INFOLINEF(table, ii, "%i", _("Leechers:"), sb->leechers);
584
585  INFOSEP(table, ii);
586
587  INFOLINE(table, ii, _("Directory:"), tr_torrentGetFolder(tr_torrent_handle(tor)));
588  INFOLINEA(table, ii, _("Downloaded:"), readablesize(sb->downloaded));
589  INFOLINEA(table, ii, _("Uploaded:"), readablesize(sb->uploaded));
590
591  INFOSEP(table, ii);
592
593  g_assert(rowcount == ii);
594
595  gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(wind)->vbox), table);
596  g_signal_connect(G_OBJECT(wind), "response",
597                   G_CALLBACK(gtk_widget_destroy), NULL);
598  gtk_widget_show_all(wind);
599}
Note: See TracBrowser for help on using the repository browser.