source: trunk/gtk/dialogs.c @ 804

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

Add a debug output window.

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