source: trunk/gtk/dialogs.c @ 3111

Last change on this file since 3111 was 3111, checked in by charles, 15 years ago

remove the backwards compatability typedefs at BentMyWookie?'s suggestion. update libT, gtk, daemon, and cli accordingly...

  • Property svn:keywords set to Date Rev Author Id
File size: 13.2 KB
Line 
1/******************************************************************************
2 * $Id: dialogs.c 3111 2007-09-20 20:14:13Z charles $
3 *
4 * Copyright (c) 2005-2007 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 <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29
30#include <gtk/gtk.h>
31#include <glib/gi18n.h>
32
33#include <libtransmission/transmission.h>
34
35#include "conf.h"
36#include "dialogs.h"
37#include "hig.h"
38#include "tr_cell_renderer_progress.h"
39#include "tr_core.h"
40#include "tr_icon.h"
41#include "tr_prefs.h"
42#include "util.h"
43
44#define UPDATE_INTERVAL         1000
45#define PREFNAME                "transmission-dialog-pref-name"
46#define FILESWIND_EXTRA_INDENT  4
47
48#define STRIPROOT( path )                                                     \
49    ( g_path_is_absolute( (path) ) ? g_path_skip_root( (path) ) : (path) )
50
51struct addcb
52{
53  GtkWidget * widget;
54  TrCore * core;
55  gboolean autostart;
56  gboolean usingaltdir;
57  GtkFileChooser *altdir;
58  GtkButtonBox *altbox;
59};
60
61struct dirdata
62{
63    GtkWidget             * widget;
64    TrCore                * core;
65    GList                 * files;
66    uint8_t               * data;
67    size_t                  size;
68    enum tr_torrent_action  action;
69    gboolean                paused;
70};
71
72struct infowind
73{
74    GtkWidget             * widget;
75    TrTorrent             * tor;
76    int64_t                 size;
77    GtkTreeModel          * model;
78    GtkTreeRowReference   * row;
79    GtkTreeModel          * filesmodel;
80    guint                   timer;
81    struct
82    {
83        tr_tracker_info   * track;
84        GtkLabel          * trackwid;
85        GtkLabel          * annwid;
86        GtkLabel          * scrwid;
87        int                 seed;
88        GtkLabel          * seedwid;
89        int                 leech;
90        GtkLabel          * leechwid;
91        int                 done;
92        GtkLabel          * donewid;
93        uint64_t            up;
94        GtkLabel          * upwid;
95        uint64_t            down;
96        GtkLabel          * downwid;
97        uint64_t            left;
98        GtkLabel          * leftwid;
99    }                       inf;
100};
101
102static void
103addwindnocore( gpointer gdata, GObject * core );
104static void
105autoclick(GtkWidget *widget, gpointer gdata);
106static void
107dirclick(GtkWidget *widget, gpointer gdata);
108static void
109addresp(GtkWidget *widget, gint resp, gpointer gdata);
110static void
111promptdirnocore( gpointer gdata, GObject * core );
112static void
113promptresp( GtkWidget * widget, gint resp, gpointer data );
114
115void
116makeaddwind( GtkWindow * parent, TrCore * core )
117{
118  GtkWidget *wind = gtk_file_chooser_dialog_new(_("Add a Torrent"), parent,
119    GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
120    GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
121  struct addcb *data = g_new(struct addcb, 1);
122  GtkWidget *vbox = gtk_vbox_new(FALSE, 3);
123  GtkWidget *bbox = gtk_hbutton_box_new();
124  GtkWidget *autocheck = gtk_check_button_new_with_mnemonic(
125    _("Automatically _start torrent"));
126  GtkWidget *dircheck = gtk_check_button_new_with_mnemonic(
127    _("Use alternate _download directory"));
128  GtkFileFilter *filter = gtk_file_filter_new();
129  GtkFileFilter *unfilter = gtk_file_filter_new();
130  GtkWidget *getdir = gtk_file_chooser_button_new(
131    _("Choose a download directory"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
132  const char * pref;
133
134  data->widget = wind;
135  data->core = core;
136  data->autostart = TRUE;
137  data->usingaltdir = FALSE;
138  data->altdir = GTK_FILE_CHOOSER(getdir);
139  data->altbox = GTK_BUTTON_BOX(bbox);
140
141  g_object_weak_ref( G_OBJECT( core ), addwindnocore, data );
142
143  gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_EDGE);
144  gtk_box_pack_start_defaults(GTK_BOX(bbox), dircheck);
145  gtk_box_pack_start_defaults(GTK_BOX(bbox), getdir);
146
147  gtk_box_pack_start_defaults(GTK_BOX(vbox), autocheck);
148  gtk_box_pack_start_defaults(GTK_BOX(vbox), bbox);
149
150  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(autocheck), TRUE);
151  pref = tr_prefs_get( PREF_ID_DIR );
152  if( NULL != pref )
153  {
154      gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( wind ), pref );
155  }
156
157  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dircheck), FALSE);
158  gtk_widget_set_sensitive(getdir, FALSE);
159
160  gtk_file_filter_set_name(filter, _("Torrent files"));
161  gtk_file_filter_add_pattern(filter, "*.torrent");
162  gtk_file_filter_set_name(unfilter, _("All files"));
163  gtk_file_filter_add_pattern(unfilter, "*");
164
165  gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(wind), filter);
166  gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(wind), unfilter);
167  gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(wind), TRUE);
168  gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(wind), vbox);
169
170  g_signal_connect(G_OBJECT(autocheck), "clicked", G_CALLBACK(autoclick),data);
171  g_signal_connect(G_OBJECT(dircheck), "clicked", G_CALLBACK(dirclick), data);
172  g_signal_connect(G_OBJECT(wind), "response", G_CALLBACK(addresp), data);
173
174  gtk_widget_show_all(wind);
175}
176
177void
178addwindnocore( gpointer gdata, GObject * core SHUTUP )
179{
180    struct addcb * data = gdata;
181
182    /* prevent the response callback from trying to remove the weak
183       reference which no longer exists */
184    data->core = NULL;
185
186    gtk_dialog_response( GTK_DIALOG( data->widget ), GTK_RESPONSE_NONE );
187}
188
189static void
190autoclick(GtkWidget *widget, gpointer gdata) {
191  struct addcb *data = gdata;
192
193  data->autostart = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
194}
195
196static void
197dirclick(GtkWidget *widget, gpointer gdata) {
198  struct addcb *data = gdata;
199
200  data->usingaltdir = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
201  gtk_widget_set_sensitive(GTK_WIDGET(data->altdir), data->usingaltdir);
202}
203
204static void
205addresp(GtkWidget *widget, gint resp, gpointer gdata) {
206  struct addcb *data = gdata;
207  GSList *files, *ii;
208  GList *stupidgtk;
209  char *dir;
210  enum tr_torrent_action action;
211
212  if(GTK_RESPONSE_ACCEPT == resp) {
213    dir = NULL;
214    if(data->usingaltdir)
215      dir = gtk_file_chooser_get_filename(data->altdir);
216    files = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget));
217    action = toraddaction( tr_prefs_get( PREF_ID_ADDSTD ) );
218    if( NULL == dir )
219    {
220        stupidgtk = NULL;
221        for( ii = files; NULL != ii; ii = ii->next )
222        {
223            stupidgtk = g_list_append( stupidgtk, ii->data );
224        }
225        tr_core_add_list( data->core, stupidgtk, action, !data->autostart );
226        freestrlist(stupidgtk);
227    }
228    else
229    {
230        for( ii = files; NULL != ii; ii = ii->next )
231        {
232            tr_core_add_dir( data->core, ii->data, dir,
233                             action, !data->autostart );
234            g_free( ii->data );
235        }
236        g_free( dir );
237    }
238    tr_core_torrents_added( data->core );
239    g_slist_free(files);
240  }
241
242  if( NULL != data->core )
243  {
244      g_object_weak_unref( G_OBJECT( data->core ), addwindnocore, data );
245  }
246
247  g_free( data );
248  gtk_widget_destroy(widget);
249}
250
251void
252fmtpeercount( GtkLabel * label, int count )
253{
254    char str[16];
255
256    if( 0 > count )
257    {
258        gtk_label_set_text( label, _("?") );
259    }
260    else
261    {
262        g_snprintf( str, sizeof str, "%i", count );
263        gtk_label_set_text( label, str );
264    }
265}
266
267void
268promptfordir( GtkWindow * parent, TrCore * core, GList * files, uint8_t * data,
269              size_t size, enum tr_torrent_action act, gboolean paused )
270{
271    struct dirdata * stuff;
272    GtkWidget      * wind;
273
274    stuff = g_new0( struct dirdata, 1 );
275    stuff->core    = core;
276    if( NULL != files )
277    {
278        stuff->files = dupstrlist( files );
279    }
280    if( NULL != data )
281    {
282        stuff->data = g_new( uint8_t, size );
283        memcpy( stuff->data, data, size );
284        stuff->size = size;
285    }
286    stuff->action  = act;
287    stuff->paused  = paused;
288
289    g_object_weak_ref( G_OBJECT( core ), promptdirnocore, stuff );
290
291    wind =  gtk_file_chooser_dialog_new( _("Choose a directory"), parent,
292                                         GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
293                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
294                                         GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
295                                         NULL );
296    gtk_file_chooser_set_local_only( GTK_FILE_CHOOSER( wind ), TRUE );
297    gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER( wind ), FALSE );
298    gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( wind ),
299                                   getdownloaddir() );
300
301    stuff->widget = wind;
302
303    g_signal_connect( G_OBJECT( wind ), "response",
304                      G_CALLBACK( promptresp ), stuff );
305
306    gtk_widget_show_all(wind);
307}
308
309void
310promptdirnocore( gpointer gdata, GObject * core SHUTUP )
311{
312    struct dirdata * stuff = gdata;
313
314    /* prevent the response callback from trying to remove the weak
315       reference which no longer exists */
316    stuff->core = NULL;
317
318    gtk_dialog_response( GTK_DIALOG( stuff->widget ), GTK_RESPONSE_NONE );
319}
320
321static void
322promptresp( GtkWidget * widget, gint resp, gpointer data )
323{
324    struct dirdata * stuff;
325    char           * dir;
326    GList          * ii;
327
328    stuff = data;
329
330    if( GTK_RESPONSE_ACCEPT == resp )
331    {
332        dir = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( widget ) );
333        /* it seems that we will always get a directory */
334        g_assert( NULL != dir );
335        for( ii = g_list_first( stuff->files ); NULL != ii; ii = ii->next )
336        {
337            tr_core_add_dir( stuff->core, ii->data, dir,
338                             stuff->action, stuff->paused );
339        }
340        if( NULL != stuff->data )
341        {
342            tr_core_add_data_dir( stuff->core, stuff->data, stuff->size, dir,
343                                  stuff->paused );
344        }
345        tr_core_torrents_added( stuff->core );
346        g_free( dir );
347    }
348
349    if( NULL != stuff->core )
350    {
351        g_object_weak_unref( G_OBJECT( stuff->core ), promptdirnocore, stuff );
352    }
353
354    freestrlist( stuff->files );
355    g_free( stuff->data );
356    g_free( stuff );
357    gtk_widget_destroy( widget );
358}
359
360/***
361****
362***/
363
364struct quitdata
365{
366    TrCore          * core;
367    callbackfunc_t    func;
368    void            * cbdata;
369    GtkWidget       * dontask;
370};
371
372static void
373quitresp( GtkWidget * widget, int response, gpointer data )
374{
375    struct quitdata * stuff;
376    gboolean doask;
377
378    stuff = data;
379
380    doask = !gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(stuff->dontask) );
381    tr_core_set_pref_bool( stuff->core, PREF_ID_ASKQUIT, doask );
382
383    if( response == GTK_RESPONSE_ACCEPT )
384        stuff->func( stuff->cbdata );
385
386    g_free( stuff );
387    gtk_widget_destroy( widget );
388}
389
390void
391askquit( TrCore          * core,
392         GtkWindow       * parent,
393         callbackfunc_t    func,
394         void            * cbdata )
395{
396    struct quitdata * stuff;
397    GtkWidget * wind;
398    GtkWidget * dontask;
399
400    if( !tr_prefs_get_bool_with_default( PREF_ID_ASKQUIT ) )
401    {
402        func( cbdata );
403        return;
404    }
405
406    stuff          = g_new( struct quitdata, 1 );
407    stuff->func    = func;
408    stuff->cbdata  = cbdata;
409    stuff->core    = core;
410
411    wind = gtk_message_dialog_new_with_markup( parent,
412                                               GTK_DIALOG_DESTROY_WITH_PARENT,
413                                               GTK_MESSAGE_QUESTION,
414                                               GTK_BUTTONS_NONE,
415                                               _("<b>Really Quit %s?</b>"),
416                                               g_get_application_name() );
417
418    gtk_message_dialog_format_secondary_text( GTK_MESSAGE_DIALOG(wind),
419                                              _("This will close all active torrents."));
420    gtk_dialog_add_buttons( GTK_DIALOG(wind),
421                            GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
422                            GTK_STOCK_QUIT, GTK_RESPONSE_ACCEPT,
423                            NULL );
424    gtk_dialog_set_default_response( GTK_DIALOG( wind ),
425                                     GTK_RESPONSE_ACCEPT );
426
427    dontask = gtk_check_button_new_with_mnemonic( _("_Don't Ask Me This Again") );
428    stuff->dontask = dontask;
429
430    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(wind)->vbox), dontask, FALSE, FALSE, GUI_PAD );
431
432    g_signal_connect( G_OBJECT( wind ), "response",
433                      G_CALLBACK( quitresp ), stuff );
434
435    gtk_widget_show_all( wind );
436}
Note: See TracBrowser for help on using the repository browser.