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

Last change on this file since 8889 was 8889, checked in by charles, 12 years ago

(trunk) remove trailing spaces

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