1/*
2 * This file Copyright (C) Mnemosyne LLC
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: relocate.c 13388 2012-07-14 19:26:55Z jordan $
11 */
12
13#include <libtransmission/transmission.h>
14
15#include <glib/gi18n.h>
16#include <gtk/gtk.h>
17
18#include "conf.h" /* gtr_pref_string_get */
19#include "hig.h"
20#include "relocate.h"
21#include "util.h"
22
23#define DATA_KEY "gtr-relocate-data"
24
25static char * previousLocation = NULL;
26
27struct relocate_dialog_data
28{
29    int done;
30    bool do_move;
31    TrCore * core;
32    GSList * torrent_ids;
33    GtkWidget * message_dialog;
34    GtkWidget * chooser_dialog;
35};
36
37static void
38data_free( gpointer gdata )
39{
40    struct relocate_dialog_data * data = gdata;
41    g_slist_free( data->torrent_ids );
42    g_free( data );
43}
44
45/***
46****
47***/
48
49static void
50startMovingNextTorrent( struct relocate_dialog_data * data )
51{
52    char * str;
53    const int id = GPOINTER_TO_INT( data->torrent_ids->data );
54
55    tr_torrent * tor = gtr_core_find_torrent( data->core, id );
56    if( tor != NULL )
57        tr_torrentSetLocation( tor, previousLocation, data->do_move, NULL, &data->done );
58
59    data->torrent_ids = g_slist_delete_link( data->torrent_ids,
60                                             data->torrent_ids );
61
62    str = g_strdup_printf( _( "Moving \"%s\"" ), tr_torrentName( tor ) );
63    gtk_message_dialog_set_markup( GTK_MESSAGE_DIALOG( data->message_dialog ), str );
64    g_free( str );
65}
66
67/* every once in awhile, check to see if the move is done.
68 * if so, delete the dialog */
69static gboolean
70onTimer( gpointer gdata )
71{
72    struct relocate_dialog_data * data = gdata;
73    const int done = data->done;
74
75    if( done == TR_LOC_ERROR )
76    {
77        const int flags = GTK_DIALOG_MODAL
78                        | GTK_DIALOG_DESTROY_WITH_PARENT;
79        GtkWidget * w = gtk_message_dialog_new( GTK_WINDOW( data->message_dialog ),
80                                                flags,
81                                                GTK_MESSAGE_ERROR,
82                                                GTK_BUTTONS_CLOSE,
83                                                "%s",
84                                                _( "Couldn't move torrent" ) );
85        gtk_dialog_run( GTK_DIALOG( w ) );
86        gtk_widget_destroy( GTK_WIDGET( data->message_dialog ) );
87        return FALSE;
88    }
89    else if( done == TR_LOC_DONE )
90    {
91        if( data->torrent_ids != NULL )
92        {
93            startMovingNextTorrent( data );
94        }
95        else
96        {
97            gtk_widget_destroy( GTK_WIDGET( data->chooser_dialog ) );
98            return FALSE;
99        }
100    }
101
102    return TRUE; /* keep looping */
103}
104
105static void
106onResponse( GtkDialog * dialog, int response, gpointer unused UNUSED )
107{
108    if( response == GTK_RESPONSE_APPLY )
109    {
110        GtkWidget * w;
111        GObject * d = G_OBJECT( dialog );
112        struct relocate_dialog_data * data = g_object_get_data( d, DATA_KEY );
113        GtkFileChooser * chooser = g_object_get_data( d, "chooser" );
114        GtkToggleButton * move_tb = g_object_get_data( d, "move_rb" );
115        char * location = gtk_file_chooser_get_filename( chooser );
116
117        data->do_move = gtk_toggle_button_get_active( move_tb );
118
119        /* pop up a dialog saying that the work is in progress */
120        w = gtk_message_dialog_new( GTK_WINDOW( dialog ),
121                                    GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
122                                    GTK_MESSAGE_INFO,
123                                    GTK_BUTTONS_CLOSE,
124                                    NULL );
125        gtk_message_dialog_format_secondary_text( GTK_MESSAGE_DIALOG( w ), _( "This may take a moment���" ) );
126        gtk_dialog_set_response_sensitive( GTK_DIALOG( w ), GTK_RESPONSE_CLOSE, FALSE );
127        gtk_widget_show( w );
128
129        /* remember this location so that it can be the default next time */
130        g_free( previousLocation );
131        previousLocation = location;
132
133        /* start the move and periodically check its status */
134        data->message_dialog = w;
135        data->done = TR_LOC_DONE;
136        onTimer( data );
137        gdk_threads_add_timeout_seconds( 1, onTimer, data );
138    }
139    else
140    {
141        gtk_widget_destroy( GTK_WIDGET( dialog ) );
142    }
143}
144
145GtkWidget*
146gtr_relocate_dialog_new( GtkWindow * parent,
147                         TrCore    * core,
148                         GSList    * torrent_ids )
149{
150    guint row;
151    GtkWidget * w;
152    GtkWidget * d;
153    GtkWidget * t;
154    struct relocate_dialog_data * data;
155
156    d = gtk_dialog_new_with_buttons( _( "Set Torrent Location" ), parent,
157                                     GTK_DIALOG_DESTROY_WITH_PARENT |
158                                     GTK_DIALOG_MODAL,
159                                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
160                                     GTK_STOCK_APPLY, GTK_RESPONSE_APPLY,
161                                     NULL );
162    gtk_dialog_set_default_response( GTK_DIALOG( d ),
163                                     GTK_RESPONSE_CANCEL );
164    gtk_dialog_set_alternative_button_order( GTK_DIALOG( d ),
165                                             GTK_RESPONSE_APPLY,
166                                             GTK_RESPONSE_CANCEL,
167                                             -1 );
168    g_signal_connect( d, "response", G_CALLBACK( onResponse ), NULL );
169
170    row = 0;
171    t = hig_workarea_create( );
172    hig_workarea_add_section_title( t, &row, _( "Location" ) );
173
174    if( previousLocation == NULL )
175        previousLocation = g_strdup( gtr_pref_string_get( TR_PREFS_KEY_DOWNLOAD_DIR ) );
176    w = gtk_file_chooser_button_new( _( "Set Torrent Location" ), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER );
177    gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( w ), previousLocation );
178    g_object_set_data( G_OBJECT( d ), "chooser", w );
179    hig_workarea_add_row( t, &row, _( "Torrent _location:" ), w, NULL );
180    w = gtk_radio_button_new_with_mnemonic( NULL, _( "_Move from the current folder" ) );
181    g_object_set_data( G_OBJECT( d ), "move_rb", w );
182    hig_workarea_add_wide_control( t, &row, w );
183    w = gtk_radio_button_new_with_mnemonic_from_widget( GTK_RADIO_BUTTON( w ), _( "Local data is _already there" ) );
184    hig_workarea_add_wide_control( t, &row, w );
185    gtr_dialog_set_content( GTK_DIALOG( d ), t );
186
187    data = g_new0( struct relocate_dialog_data, 1 );
188    data->core = core;
189    data->torrent_ids = torrent_ids;
190    data->chooser_dialog = d;
191    g_object_set_data_full( G_OBJECT( d ), DATA_KEY, data, data_free );
192
193    return d;
194}
195