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