source: trunk/gtk/makemeta-ui.c @ 6007

Last change on this file since 6007 was 6007, checked in by charles, 14 years ago

(gtk) rough draft of the preferences dialog's "Remote Access" tab: enable/disable RPC, port, ACL, password, and password toggle

  • Property svn:keywords set to Date Rev Author Id
File size: 13.5 KB
Line 
1/*
2 * This file Copyright (C) 2007-2008 Charles Kerr <charles@rebelbase.com>
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: makemeta-ui.c 6007 2008-06-02 21:02:38Z charles $
11 */
12
13#include <string.h>
14
15#include <glib/gi18n.h>
16#include <gtk/gtk.h>
17
18#include <libtransmission/transmission.h>
19#include <libtransmission/makemeta.h>
20
21#include "hig.h"
22#include "makemeta-ui.h"
23#include "tracker-list.h"
24#include "util.h"
25
26#define UPDATE_INTERVAL_MSEC 200
27
28#define UI_KEY "ui"
29
30typedef struct
31{
32    GtkWidget * filename_entry;
33    GtkWidget * size_lb;
34    GtkWidget * pieces_lb;
35    GtkWidget * announce_list;
36    GtkWidget * comment_entry;
37    GtkWidget * progressbar;
38    GtkWidget * private_check;
39    GtkWidget * dialog;
40
41    tr_metainfo_builder * builder;
42    tr_handle * handle;
43
44    gboolean isBuilding;
45}
46MakeMetaUI;
47
48static void
49freeMetaUI( gpointer p )
50{
51    MakeMetaUI * ui = p;
52    memset( ui, ~0, sizeof(MakeMetaUI) );
53    g_free( ui );
54}
55
56static void
57refreshButtons( MakeMetaUI * ui )
58{
59    GtkDialog * d = GTK_DIALOG( ui->dialog );
60    gtk_dialog_set_response_sensitive( d, GTK_RESPONSE_ACCEPT, !ui->isBuilding && ( ui->builder!=NULL ) );
61    gtk_dialog_set_response_sensitive( d, GTK_RESPONSE_CLOSE, !ui->isBuilding );
62    gtk_dialog_set_response_sensitive( d, GTK_RESPONSE_CANCEL, ui->isBuilding );
63}
64
65static void
66setIsBuilding( MakeMetaUI * ui, gboolean isBuilding )
67{
68    ui->isBuilding = isBuilding;
69
70    if( ui->builder != NULL )
71        ui->builder->result = TR_MAKEMETA_OK;
72
73    if( !isBuilding )
74        gtk_progress_bar_set_fraction( GTK_PROGRESS_BAR( ui->progressbar ), 0 );
75
76    refreshButtons( ui );
77}
78
79static gboolean
80refresh_cb ( gpointer user_data )
81{
82    int denom;
83    char buf[1024];
84    double fraction;
85    MakeMetaUI * ui = user_data;
86    GtkProgressBar * p = GTK_PROGRESS_BAR( ui->progressbar );
87
88    denom = ui->builder->pieceCount ? ui->builder->pieceCount : 1;
89    fraction = (double)ui->builder->pieceIndex / denom;
90    gtk_progress_bar_set_fraction( p, fraction );
91    g_snprintf( buf, sizeof(buf), "%s.torrent (%d%%)", ui->builder->top, (int)(fraction*100) );
92    gtk_progress_bar_set_text( p, buf );
93
94    if( ui->builder->isDone )
95    {
96        char * txt = NULL;
97
98        switch( ui->builder->result )
99        {
100            case TR_MAKEMETA_OK:
101                txt = g_strdup( _( "Torrent created!" ) );
102                break;
103
104            case TR_MAKEMETA_URL:
105                txt = g_strdup_printf( _( "Torrent creation failed: %s" ), _( "Invalid URL" ) );
106                break;
107
108            case TR_MAKEMETA_CANCELLED:
109                txt = g_strdup_printf( _( "Torrent creation cancelled" ) );
110                break;
111
112            case TR_MAKEMETA_IO_READ: {
113                char * tmp = g_strdup_printf( _( "Couldn't read \"%1$s\": %2$s" ), ui->builder->errfile, g_strerror( ui->builder->my_errno ) );
114                txt = g_strdup_printf( _( "Torrent creation failed: %s" ), tmp );
115                g_free( tmp  );
116                break;
117            }
118
119            case TR_MAKEMETA_IO_WRITE: {
120                char * tmp = g_strdup_printf( _( "Couldn't create \"%1$s\": %2$s" ), ui->builder->errfile, g_strerror( ui->builder->my_errno ) );
121                txt = g_strdup_printf( _( "Torrent creation failed: %s" ), tmp );
122                g_free( tmp  );
123                break;
124            }
125        }
126
127        gtk_progress_bar_set_fraction( p, ui->builder->result==TR_MAKEMETA_OK ? 1.0 : 0.0 );
128        gtk_progress_bar_set_text( p, txt );
129        setIsBuilding( ui, FALSE );
130        g_free( txt );
131    }
132
133    return !ui->builder->isDone;
134}
135
136static void
137remove_tag (gpointer tag)
138{
139  g_source_remove (GPOINTER_TO_UINT(tag)); /* stop the periodic refresh */
140}
141
142static void
143response_cb( GtkDialog* d, int response, gpointer user_data )
144{
145    MakeMetaUI * ui = user_data;
146    char *tmp;
147    char buf[1024];
148    guint tag;
149    tr_tracker_info * trackers = NULL;
150    int i;
151    int trackerCount = 0;
152
153    if( response != GTK_RESPONSE_ACCEPT )
154    {
155        if( ui->builder == NULL )
156        {
157            gtk_widget_destroy( GTK_WIDGET( d ) );
158            return;
159        }
160
161        if( ui->builder->isDone || !ui->isBuilding )
162        {
163            gtk_widget_destroy( ui->dialog );
164        }
165        else
166        {
167            ui->builder->abortFlag = TRUE;
168        }
169       
170        return;
171    }
172
173    if( ui->builder == NULL || ui->isBuilding )
174        return;
175
176    setIsBuilding( ui, TRUE );
177
178    tmp = g_path_get_basename (ui->builder->top);
179    g_snprintf( buf, sizeof(buf), "%s.torrent (%d%%)", ui->builder->top, 0 );
180
181    gtk_progress_bar_set_text( GTK_PROGRESS_BAR(ui->progressbar), buf );
182    g_free( tmp );
183
184    trackers = tracker_list_get_trackers( ui->announce_list, &trackerCount );
185
186    tr_makeMetaInfo( ui->builder,
187                     NULL, 
188                     trackers, trackerCount,
189                     gtk_entry_get_text( GTK_ENTRY( ui->comment_entry ) ),
190                     gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( ui->private_check ) ) );
191
192    tag = g_timeout_add (UPDATE_INTERVAL_MSEC, refresh_cb, ui);
193    g_object_set_data_full (G_OBJECT(d), "tag", GUINT_TO_POINTER(tag), remove_tag);
194
195    /* cleanup */
196    for( i=0; i<trackerCount; ++i )
197        g_free( trackers[i].announce );
198    g_free( trackers );
199}
200
201/***
202****
203***/
204
205static void
206refreshFromBuilder( MakeMetaUI * ui )
207{
208    char sizeStr[128];
209    char buf[MAX_PATH_LENGTH];
210    tr_metainfo_builder * builder = ui->builder;
211    const char * filename = builder ? builder->top : NULL;
212
213    if( !filename )
214        g_snprintf( buf, sizeof( buf ), _( "No source selected" ) );
215    else
216        g_snprintf( buf, sizeof(buf), "%s.torrent (%d%%)", filename, 0 );
217    gtk_progress_bar_set_text( GTK_PROGRESS_BAR( ui->progressbar ), buf );
218    refreshButtons( ui );
219
220    if( !filename )
221        g_snprintf( buf, sizeof( buf ), _( "<i>No source selected</i>" ) );
222    else {
223        tr_strlsize( sizeStr, builder->totalSize, sizeof(sizeStr) );
224        g_snprintf( buf, sizeof( buf ),
225                    /* %1$s is the torrent size
226                       %2$'d is its number of files */
227                    ngettext( "<i>%1$s; %2$'d File</i>",
228                              "<i>%1$s; %2$'d Files</i>", builder->fileCount ),
229                    sizeStr, builder->fileCount );
230    }
231    gtk_label_set_markup ( GTK_LABEL(ui->size_lb), buf );
232
233    if( !filename )
234        *buf = '\0';
235    else {
236        tr_strlsize( sizeStr, builder->pieceSize, sizeof(sizeStr) );
237        g_snprintf( buf, sizeof( buf ),
238                    /* %1$'s is number of pieces;
239                       %2$s is how big each piece is */
240                    ngettext( "<i>%1$'d Piece @ %2$s</i>",
241                              "<i>%1$'d Pieces @ %2$s</i>",
242                              builder->pieceCount ),
243                    builder->pieceCount, sizeStr );
244    }
245    gtk_label_set_markup ( GTK_LABEL(ui->pieces_lb), buf );
246}
247
248static void
249onSourceActivated( GtkEditable * editable, gpointer gui )
250{
251    const char * filename = gtk_entry_get_text( GTK_ENTRY( editable ) );
252    MakeMetaUI * ui = gui;
253
254    if( ui->builder )
255        tr_metaInfoBuilderFree( ui->builder );
256    ui->builder = tr_metaInfoBuilderCreate( ui->handle, filename );
257    refreshFromBuilder( ui );
258}
259
260static gboolean
261onSourceLostFocus( GtkWidget * w, GdkEventFocus * focus UNUSED, gpointer gui )
262{
263    onSourceActivated( GTK_EDITABLE( w ), gui );
264    return FALSE;
265}
266
267static void
268onChooseClicked( GtkButton              * button,
269                 gpointer                 gui,
270                 const char             * title,
271                 GtkFileChooserAction     chooserAction )
272{
273    GtkWidget * top = gtk_widget_get_toplevel( GTK_WIDGET( button ) );
274    GtkWidget * d = gtk_file_chooser_dialog_new( title,
275                                                 GTK_WINDOW( top ),
276                                                 chooserAction,
277                                                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
278                                                 GTK_STOCK_ADD, GTK_RESPONSE_ACCEPT,
279                                                 NULL );
280    if( gtk_dialog_run( GTK_DIALOG( d ) ) == GTK_RESPONSE_ACCEPT )
281    {
282        MakeMetaUI * ui = gui;
283        char * filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( d ) );
284        gtk_entry_set_text( GTK_ENTRY( ui->filename_entry ), filename );
285        onSourceActivated( GTK_EDITABLE( ui->filename_entry ), gui );
286        g_free( filename );
287    }
288
289    gtk_widget_destroy( d );
290}
291
292static void
293onChooseDirectoryClicked( GtkButton * b, gpointer gui )
294{
295    onChooseClicked( b, gui, _( "Choose Directory" ), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER );
296}
297
298static void
299onChooseFileClicked( GtkButton * b, gpointer gui )
300{
301    onChooseClicked( b, gui, _( "Choose File" ), GTK_FILE_CHOOSER_ACTION_OPEN );
302}
303
304GtkWidget*
305make_meta_ui( GtkWindow * parent, tr_handle * handle )
306{
307    int row = 0;
308    GtkWidget *b1, *b2, *d, *t, *w, *h, *h2, *v, *focusMe, *extras;
309    GtkBox * main_vbox;
310    MakeMetaUI * ui = g_new0 ( MakeMetaUI, 1 );
311    ui->handle = handle;
312    int width, height;
313
314    d = gtk_dialog_new_with_buttons( _("New Torrent"),
315                                     parent,
316                                     GTK_DIALOG_DESTROY_WITH_PARENT|GTK_DIALOG_NO_SEPARATOR,
317                                     GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
318                                     GTK_STOCK_NEW, GTK_RESPONSE_ACCEPT,
319                                     GTK_STOCK_STOP, GTK_RESPONSE_CANCEL,
320                                     NULL );
321    g_signal_connect( d, "response", G_CALLBACK(response_cb), ui );
322    g_object_set_data_full( G_OBJECT(d), "ui", ui, freeMetaUI );
323    ui->dialog = d;
324    main_vbox = GTK_BOX( GTK_DIALOG( d )->vbox );
325
326    t = hig_workarea_create ();
327
328    hig_workarea_add_section_title (t, &row, _( "Source" ));
329
330        h = gtk_hbox_new( FALSE, GUI_PAD );
331        v = gtk_vbox_new( FALSE, GUI_PAD_SMALL );
332        w = ui->filename_entry = gtk_entry_new( );
333        g_signal_connect( w, "activate", G_CALLBACK( onSourceActivated ), ui );
334        g_signal_connect( w, "focus-out-event", G_CALLBACK( onSourceLostFocus ), ui );
335        gtk_box_pack_start( GTK_BOX( v ), w, FALSE, FALSE, 0 );
336        h2 = gtk_hbox_new( FALSE, GUI_PAD_SMALL );
337        w = ui->size_lb = gtk_label_new (NULL);
338        gtk_label_set_markup ( GTK_LABEL(w), _( "<i>No source selected</i>" ) );
339        gtk_box_pack_start( GTK_BOX(h2), w, FALSE, FALSE, GUI_PAD_SMALL );
340        w = ui->pieces_lb = gtk_label_new (NULL);
341        gtk_box_pack_end( GTK_BOX(h2), w, FALSE, FALSE, GUI_PAD_SMALL );
342        w = gtk_alignment_new( 0.0f, 0.0f, 0.0f, 0.0f );
343        gtk_widget_set_size_request (w, 2 * GUI_PAD_BIG, 0);
344        gtk_box_pack_start_defaults ( GTK_BOX(h2), w );
345        gtk_box_pack_start( GTK_BOX( v ), h2, FALSE, FALSE, 0 );
346        gtk_box_pack_start_defaults( GTK_BOX( h ), v );
347        v = gtk_vbox_new( FALSE, GUI_PAD_SMALL );
348        w = b1 = tr_button_new_from_stock( GTK_STOCK_DIRECTORY, _( "F_older" ) );
349        focusMe = w;
350        g_signal_connect( w, "clicked", G_CALLBACK( onChooseDirectoryClicked ), ui );
351        gtk_box_pack_start_defaults( GTK_BOX( v ), w );
352        w = b2 = tr_button_new_from_stock( GTK_STOCK_FILE, _( "_File" ) );
353        g_signal_connect( w, "clicked", G_CALLBACK( onChooseFileClicked ), ui );
354        gtk_box_pack_start_defaults( GTK_BOX( v ), w );
355        gtk_box_pack_start( GTK_BOX( h ), v, FALSE, FALSE, 0 );
356        hig_workarea_add_wide_control( t, &row, h );
357
358    hig_workarea_add_section_divider( t, &row );
359    hig_workarea_add_section_title( t, &row, _( "Trackers" ) );
360
361        w = tracker_list_new( NULL );
362        ui->announce_list = w;
363        hig_workarea_add_wide_control( t, &row, w );
364        tracker_list_get_button_size( w, &width, &height );
365        gtk_widget_set_size_request( b1, width, height );
366        gtk_widget_set_size_request( b2, width, height );
367
368    hig_workarea_add_section_divider( t, &row );
369    w = extras = gtk_expander_new_with_mnemonic( _( "<b>E_xtras</b>" ) );
370    gtk_expander_set_use_markup( GTK_EXPANDER( w ), TRUE );
371    hig_workarea_add_section_title_widget( t, &row, w );
372
373        {
374        int row2 = 0;
375        GtkWidget * t2 = hig_workarea_create( );
376        w = ui->comment_entry = gtk_entry_new( );
377        hig_workarea_add_row( t2, &row2, _( "Commen_t:" ), w, NULL );
378        w = hig_workarea_add_wide_checkbutton( t2, &row2, _( "_Private torrent" ), FALSE );
379        ui->private_check = w;
380        hig_workarea_finish( t2, &row2 );
381        gtk_container_add( GTK_CONTAINER( extras ), t2 );
382        }
383
384    hig_workarea_finish( t, &row );
385    gtk_box_pack_start_defaults( main_vbox, t );
386
387    w = gtk_frame_new( NULL );
388    gtk_frame_set_shadow_type( GTK_FRAME( w ), GTK_SHADOW_NONE );
389    gtk_container_set_border_width( GTK_CONTAINER( w ), GUI_PAD );
390    gtk_container_add( GTK_CONTAINER( w ), gtk_hseparator_new( ) );
391    gtk_box_pack_start( main_vbox, w, FALSE, FALSE, 0 );
392
393    w = gtk_frame_new( NULL );
394    gtk_frame_set_shadow_type( GTK_FRAME( w ), GTK_SHADOW_NONE );
395    gtk_container_set_border_width( GTK_CONTAINER( w ), GUI_PAD );
396    ui->progressbar = gtk_progress_bar_new( );
397    gtk_progress_bar_set_text( GTK_PROGRESS_BAR( ui->progressbar), _( "No source selected" ) );
398    gtk_container_add( GTK_CONTAINER( w ), ui->progressbar );
399    gtk_box_pack_start( main_vbox, w, FALSE, FALSE, 0 );
400
401    gtk_window_set_default_size( GTK_WINDOW(d), 500, 0 );
402    gtk_widget_show_all( GTK_DIALOG(d)->vbox );
403    setIsBuilding( ui, FALSE );
404    gtk_widget_grab_focus( focusMe );
405    return d;
406}
Note: See TracBrowser for help on using the repository browser.