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

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

janitorial: tr_handle -> tr_session

  • Property svn:keywords set to Date Rev Author Id
File size: 16.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 6978 2008-10-28 19:49:33Z 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 "conf.h"
22#include "hig.h"
23#include "makemeta-ui.h"
24#include "tracker-list.h"
25#include "util.h"
26
27#define UPDATE_INTERVAL_MSEC 200
28
29#define UI_KEY "ui"
30#define ANNOUNCE_KEY "recent-announce-url"
31
32typedef struct
33{
34    GtkWidget * filename_entry;
35    GtkWidget * size_lb;
36    GtkWidget * pieces_lb;
37    GtkWidget * announce_list;
38    GtkWidget * comment_entry;
39    GtkWidget * progressbar;
40    GtkWidget * private_check;
41    GtkWidget * dialog;
42
43    tr_metainfo_builder   *  builder;
44    tr_session            *  session;
45
46    gboolean               isBuilding;
47}
48MakeMetaUI;
49
50static void
51freeMetaUI( gpointer p )
52{
53    MakeMetaUI * ui = p;
54
55    memset( ui, ~0, sizeof( MakeMetaUI ) );
56    g_free( ui );
57}
58
59static void
60refreshButtons( MakeMetaUI * ui )
61{
62    GtkDialog * d = GTK_DIALOG( ui->dialog );
63
64    gtk_dialog_set_response_sensitive(
65         d, GTK_RESPONSE_ACCEPT, !ui->isBuilding && ( ui->builder != NULL ) );
66    gtk_dialog_set_response_sensitive( d, GTK_RESPONSE_CLOSE,
67                                       !ui->isBuilding );
68    gtk_dialog_set_response_sensitive( d, GTK_RESPONSE_CANCEL,
69                                       ui->isBuilding );
70}
71
72static void
73setIsBuilding( MakeMetaUI * ui,
74               gboolean     isBuilding )
75{
76    ui->isBuilding = isBuilding;
77
78    if( ui->builder != NULL )
79        ui->builder->result = TR_MAKEMETA_OK;
80
81    if( !isBuilding )
82        gtk_progress_bar_set_fraction( GTK_PROGRESS_BAR(
83                                           ui->progressbar ), 0 );
84
85    refreshButtons( ui );
86}
87
88static gboolean
89refresh_cb( gpointer user_data )
90{
91    int              denom;
92    char             buf[1024];
93    double           fraction;
94    MakeMetaUI *     ui = user_data;
95    GtkProgressBar * p = GTK_PROGRESS_BAR( ui->progressbar );
96
97    denom = ui->builder->pieceCount ? ui->builder->pieceCount : 1;
98    fraction = (double)ui->builder->pieceIndex / denom;
99    gtk_progress_bar_set_fraction( p, fraction );
100    g_snprintf( buf, sizeof( buf ), "%s.torrent (%d%%)", ui->builder->top,
101               (int)( fraction * 100 ) );
102    gtk_progress_bar_set_text( p, buf );
103
104    if( ui->builder->isDone )
105    {
106        char * txt = NULL;
107
108        switch( ui->builder->result )
109        {
110            case TR_MAKEMETA_OK:
111                txt = g_strdup( _( "Torrent created!" ) );
112                break;
113
114            case TR_MAKEMETA_URL:
115                txt = g_strdup_printf( _(
116                                          "Torrent creation failed: %s" ),
117                                      _( "Invalid URL" ) );
118                break;
119
120            case TR_MAKEMETA_CANCELLED:
121                txt = g_strdup_printf( _( "Torrent creation cancelled" ) );
122                break;
123
124            case TR_MAKEMETA_IO_READ:
125            {
126                char * tmp =
127                    g_strdup_printf( _(
128                                        "Couldn't read \"%1$s\": %2$s" ),
129                                    ui->builder->errfile,
130                                    g_strerror( ui->builder->my_errno ) );
131                txt = g_strdup_printf( _(
132                                           "Torrent creation failed: %s" ),
133                                       tmp );
134                g_free( tmp  );
135                break;
136            }
137
138            case TR_MAKEMETA_IO_WRITE:
139            {
140                char * tmp =
141                    g_strdup_printf( _(
142                                        "Couldn't create \"%1$s\": %2$s" ),
143                                    ui->builder->errfile,
144                                    g_strerror( ui->builder->my_errno ) );
145                txt = g_strdup_printf( _(
146                                           "Torrent creation failed: %s" ),
147                                       tmp );
148                g_free( tmp  );
149                break;
150            }
151        }
152
153        gtk_progress_bar_set_fraction(
154            p, ui->builder->result == TR_MAKEMETA_OK ? 1.0 : 0.0 );
155        gtk_progress_bar_set_text( p, txt );
156        setIsBuilding( ui, FALSE );
157        g_free( txt );
158    }
159
160    return !ui->builder->isDone;
161}
162
163static void
164remove_tag( gpointer tag )
165{
166    g_source_remove ( GPOINTER_TO_UINT( tag ) ); /* stop the periodic refresh */
167}
168
169static void
170response_cb( GtkDialog* d,
171             int        response,
172             gpointer   user_data )
173{
174    MakeMetaUI *      ui = user_data;
175    char *            tmp;
176    char              buf[1024];
177    guint             tag;
178    tr_tracker_info * trackers = NULL;
179    int               i;
180    int               trackerCount = 0;
181
182    if( response != GTK_RESPONSE_ACCEPT )
183    {
184        if( ui->builder == NULL )
185        {
186            gtk_widget_destroy( GTK_WIDGET( d ) );
187            return;
188        }
189
190        if( ui->builder->isDone || !ui->isBuilding )
191        {
192            gtk_widget_destroy( ui->dialog );
193        }
194        else
195        {
196            ui->builder->abortFlag = TRUE;
197        }
198
199        return;
200    }
201
202    if( ui->builder == NULL || ui->isBuilding )
203        return;
204
205    setIsBuilding( ui, TRUE );
206
207    tmp = g_path_get_basename ( ui->builder->top );
208    g_snprintf( buf, sizeof( buf ), "%s.torrent (%d%%)", ui->builder->top,
209                0 );
210
211    gtk_progress_bar_set_text( GTK_PROGRESS_BAR( ui->progressbar ), buf );
212    g_free( tmp );
213
214    trackers = tracker_list_get_trackers( ui->announce_list, &trackerCount );
215
216    pref_int_set( ANNOUNCE_KEY"-count", trackerCount );
217    for( i=0; i<trackerCount; ++i )
218    {
219        char key[512];
220        g_snprintf( key, sizeof( key ), ANNOUNCE_KEY"-%d-tier", i );
221        pref_int_set( key, trackers[i].tier );
222        g_snprintf( key, sizeof( key ), ANNOUNCE_KEY"-%d-announce", i );
223        pref_string_set( key, trackers[i].announce );
224    }
225
226    tr_makeMetaInfo( ui->builder,
227                    NULL,
228                    trackers, trackerCount,
229                    gtk_entry_get_text( GTK_ENTRY( ui->comment_entry ) ),
230                    gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( ui->
231                                                                     private_check ) ) );
232
233    tag = g_timeout_add ( UPDATE_INTERVAL_MSEC, refresh_cb, ui );
234    g_object_set_data_full ( G_OBJECT( d ), "tag", GUINT_TO_POINTER(
235                                 tag ), remove_tag );
236
237    /* cleanup */
238    for( i = 0; i < trackerCount; ++i )
239        g_free( trackers[i].announce );
240    g_free( trackers );
241}
242
243/***
244****
245***/
246
247static void
248refreshFromBuilder( MakeMetaUI * ui )
249{
250    char                  sizeStr[128];
251    char                * buf;
252    tr_metainfo_builder * builder = ui->builder;
253    const char *          filename = builder ? builder->top : NULL;
254
255
256    /* update the progressbar */
257    if( !filename )
258        buf = g_strdup( _( "No source selected" ) );
259    else
260        buf = g_strdup_printf( "%s.torrent (%d%%)", filename, 0 );
261    gtk_progress_bar_set_text( GTK_PROGRESS_BAR( ui->progressbar ), buf );
262    refreshButtons( ui );
263    g_free( buf );
264
265    /* update the size label */
266    if( !filename )
267        buf = g_strdup( "<i>No source selected</i>" );
268    else {
269        tr_strlsize( sizeStr, builder->totalSize, sizeof( sizeStr ) );
270        buf = g_strdup_printf( /* %1$s is the torrent size
271                                  %2$'d is its number of files */
272                               ngettext( "<i>%1$s; %2$'d File</i>",
273                                         "<i>%1$s; %2$'d Files</i>",
274                                         builder->fileCount ),
275                               sizeStr, builder->fileCount );
276    }
277    gtk_label_set_markup ( GTK_LABEL( ui->size_lb ), buf );
278    g_free( buf );
279
280    /* update the pieces label */
281    if( !filename )
282        buf = g_strdup( "" );
283    else {
284        char * countStr = g_strdup_printf( ngettext( "%'d Piece", "%'d Pieces",
285                                                     builder->pieceCount ),
286                                           builder->pieceCount );
287        tr_strlsize( sizeStr, builder->pieceSize, sizeof( sizeStr ) );
288        buf = g_strdup_printf( /* %1$s is number of pieces;
289                                  %2$s is how big each piece is */
290                               _( "%1$s @ %2$s" ), countStr, sizeStr );
291        g_free( countStr );
292    }
293    gtk_label_set_markup ( GTK_LABEL( ui->pieces_lb ), buf );
294    g_free( buf );
295}
296
297static void
298onSourceActivated( GtkEditable * editable,
299                   gpointer      gui )
300{
301    const char * filename = gtk_entry_get_text( GTK_ENTRY( editable ) );
302    MakeMetaUI * ui = gui;
303
304    if( ui->builder )
305        tr_metaInfoBuilderFree( ui->builder );
306    ui->builder = tr_metaInfoBuilderCreate( ui->session, filename );
307    refreshFromBuilder( ui );
308}
309
310static gboolean
311onSourceLostFocus( GtkWidget *           w,
312                   GdkEventFocus * focus UNUSED,
313                   gpointer              gui )
314{
315    onSourceActivated( GTK_EDITABLE( w ), gui );
316    return FALSE;
317}
318
319static void
320onChooseClicked( GtkButton *          button,
321                 gpointer             gui,
322                 const char *         title,
323                 GtkFileChooserAction chooserAction )
324{
325    GtkWidget * top = gtk_widget_get_toplevel( GTK_WIDGET( button ) );
326    GtkWidget * d = gtk_file_chooser_dialog_new( title,
327                                                 GTK_WINDOW(
328                                                     top ),
329                                                 chooserAction,
330                                                 GTK_STOCK_CANCEL,
331                                                 GTK_RESPONSE_CANCEL,
332                                                 GTK_STOCK_ADD,
333                                                 GTK_RESPONSE_ACCEPT,
334                                                 NULL );
335
336    if( gtk_dialog_run( GTK_DIALOG( d ) ) == GTK_RESPONSE_ACCEPT )
337    {
338        MakeMetaUI * ui = gui;
339        char *       filename = gtk_file_chooser_get_filename(
340             GTK_FILE_CHOOSER( d ) );
341        gtk_entry_set_text( GTK_ENTRY( ui->filename_entry ), filename );
342        onSourceActivated( GTK_EDITABLE( ui->filename_entry ), gui );
343        g_free( filename );
344    }
345
346    gtk_widget_destroy( d );
347}
348
349static void
350onChooseDirectoryClicked( GtkButton * b,
351                          gpointer    gui )
352{
353    onChooseClicked( b, gui, _(
354                         "Choose Directory" ),
355                     GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER );
356}
357
358static void
359onChooseFileClicked( GtkButton * b,
360                     gpointer    gui )
361{
362    onChooseClicked( b, gui, _(
363                         "Choose File" ), GTK_FILE_CHOOSER_ACTION_OPEN );
364}
365
366GtkWidget*
367make_meta_ui( GtkWindow  * parent,
368              tr_session * session )
369{
370    int          n;
371    int          row = 0;
372    GtkWidget *  d, *t, *w, *h, *h2, *v, *focusMe, *extras;
373    GtkBox *     main_vbox;
374    MakeMetaUI * ui = g_new0 ( MakeMetaUI, 1 );
375
376    ui->session = session;
377
378    d = gtk_dialog_new_with_buttons( _(
379                                         "New Torrent" ),
380                                     parent,
381                                     GTK_DIALOG_DESTROY_WITH_PARENT |
382                                     GTK_DIALOG_NO_SEPARATOR,
383                                     GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
384                                     GTK_STOCK_NEW, GTK_RESPONSE_ACCEPT,
385                                     GTK_STOCK_STOP, GTK_RESPONSE_CANCEL,
386                                     NULL );
387    g_signal_connect( d, "response", G_CALLBACK( response_cb ), ui );
388    g_object_set_data_full( G_OBJECT( d ), "ui", ui, freeMetaUI );
389    ui->dialog = d;
390    main_vbox = GTK_BOX( GTK_DIALOG( d )->vbox );
391
392    t = hig_workarea_create ( );
393
394    hig_workarea_add_section_title ( t, &row, _( "Source" ) );
395
396    h = gtk_hbox_new( FALSE, GUI_PAD );
397    v = gtk_vbox_new( FALSE, GUI_PAD_SMALL );
398    w = ui->filename_entry = gtk_entry_new( );
399    g_signal_connect( w, "activate", G_CALLBACK( onSourceActivated ), ui );
400    g_signal_connect( w, "focus-out-event", G_CALLBACK(
401                          onSourceLostFocus ), ui );
402    gtk_box_pack_start( GTK_BOX( v ), w, FALSE, FALSE, 0 );
403    h2 = gtk_hbox_new( FALSE, GUI_PAD_SMALL );
404    w = ui->size_lb = gtk_label_new ( NULL );
405    gtk_label_set_markup ( GTK_LABEL( w ), _( "<i>No source selected</i>" ) );
406    gtk_box_pack_start( GTK_BOX( h2 ), w, FALSE, FALSE, GUI_PAD_SMALL );
407    w = ui->pieces_lb = gtk_label_new ( NULL );
408    gtk_box_pack_end( GTK_BOX( h2 ), w, FALSE, FALSE, GUI_PAD_SMALL );
409    w = gtk_alignment_new( 0.0f, 0.0f, 0.0f, 0.0f );
410    gtk_widget_set_size_request ( w, 2 * GUI_PAD_BIG, 0 );
411    gtk_box_pack_start_defaults ( GTK_BOX( h2 ), w );
412    gtk_box_pack_start( GTK_BOX( v ), h2, FALSE, FALSE, 0 );
413    gtk_box_pack_start_defaults( GTK_BOX( h ), v );
414    v = gtk_vbox_new( FALSE, GUI_PAD_SMALL );
415    w = gtr_button_new_from_stock( GTK_STOCK_DIRECTORY, _( "F_older" ) );
416    focusMe = w;
417    g_signal_connect( w, "clicked", G_CALLBACK(
418                          onChooseDirectoryClicked ), ui );
419    gtk_box_pack_start_defaults( GTK_BOX( v ), w );
420    w = gtr_button_new_from_stock( GTK_STOCK_FILE, _( "_File" ) );
421    g_signal_connect( w, "clicked", G_CALLBACK( onChooseFileClicked ), ui );
422    gtk_box_pack_start_defaults( GTK_BOX( v ), w );
423    gtk_box_pack_start( GTK_BOX( h ), v, FALSE, FALSE, 0 );
424    hig_workarea_add_wide_control( t, &row, h );
425
426    hig_workarea_add_section_divider( t, &row );
427    hig_workarea_add_section_title( t, &row, _( "Trackers" ) );
428
429    w = tracker_list_new( NULL );
430
431    n = pref_int_get( ANNOUNCE_KEY"-count" );
432    if( n > 0 )
433    {
434        int i;
435        int trackerCount = 0;
436        tr_tracker_info * trackers = g_new0( tr_tracker_info, n );
437         
438        for( i=0; i<n; ++i )
439        {
440            char key[512];
441            int tier;
442            const char * announce;
443            g_snprintf( key, sizeof( key ), ANNOUNCE_KEY"-%d-tier", i );
444            tier = pref_int_get( key );
445            g_snprintf( key, sizeof( key ), ANNOUNCE_KEY"-%d-announce", i );
446            announce = pref_string_get( key );
447            if( tier >= 0 && announce && *announce ) {
448                trackers[trackerCount].tier = tier;
449                trackers[trackerCount++].announce = (char*) announce;
450            }
451        }
452
453        if( trackerCount > 0 )
454            tracker_list_add_trackers( w, trackers, trackerCount );
455
456        g_free( trackers );
457    }
458
459    ui->announce_list = w;
460    hig_workarea_add_wide_control( t, &row, w );
461
462    hig_workarea_add_section_divider( t, &row );
463    w = extras = gtk_expander_new_with_mnemonic( _( "<b>E_xtras</b>" ) );
464    gtk_expander_set_use_markup( GTK_EXPANDER( w ), TRUE );
465    hig_workarea_add_section_title_widget( t, &row, w );
466
467    {
468        int         row2 = 0;
469        GtkWidget * t2 = hig_workarea_create( );
470        w = ui->comment_entry = gtk_entry_new( );
471        hig_workarea_add_row( t2, &row2, _( "Commen_t:" ), w, NULL );
472        w =
473            hig_workarea_add_wide_checkbutton( t2, &row2, _(
474                                                   "_Private torrent" ),
475                                               FALSE );
476        ui->private_check = w;
477        hig_workarea_finish( t2, &row2 );
478        gtk_container_add( GTK_CONTAINER( extras ), t2 );
479    }
480
481    hig_workarea_finish( t, &row );
482    gtk_box_pack_start_defaults( main_vbox, t );
483
484    w = gtk_frame_new( NULL );
485    gtk_frame_set_shadow_type( GTK_FRAME( w ), GTK_SHADOW_NONE );
486    gtk_container_set_border_width( GTK_CONTAINER( w ), GUI_PAD );
487    gtk_container_add( GTK_CONTAINER( w ), gtk_hseparator_new( ) );
488    gtk_box_pack_start( main_vbox, w, FALSE, FALSE, 0 );
489
490    w = gtk_frame_new( NULL );
491    gtk_frame_set_shadow_type( GTK_FRAME( w ), GTK_SHADOW_NONE );
492    gtk_container_set_border_width( GTK_CONTAINER( w ), GUI_PAD );
493    ui->progressbar = gtk_progress_bar_new( );
494    gtk_progress_bar_set_text( GTK_PROGRESS_BAR( ui->progressbar ),
495                              _( "No source selected" ) );
496    gtk_container_add( GTK_CONTAINER( w ), ui->progressbar );
497    gtk_box_pack_start( main_vbox, w, FALSE, FALSE, 0 );
498
499    gtk_window_set_default_size( GTK_WINDOW( d ), 500, 0 );
500    gtk_widget_show_all( GTK_DIALOG( d )->vbox );
501    setIsBuilding( ui, FALSE );
502    gtk_widget_grab_focus( focusMe );
503    return d;
504}
505
Note: See TracBrowser for help on using the repository browser.