| 1 /** |
|
| 2 * @file gtkft.c GTK+ File Transfer UI |
|
| 3 * @ingroup gtkui |
|
| 4 * |
|
| 5 * gaim |
|
| 6 * |
|
| 7 * Gaim is the legal property of its developers, whose names are too numerous |
|
| 8 * to list here. Please refer to the COPYRIGHT file distributed with this |
|
| 9 * source distribution. |
|
| 10 * |
|
| 11 * This program is free software; you can redistribute it and/or modify |
|
| 12 * it under the terms of the GNU General Public License as published by |
|
| 13 * the Free Software Foundation; either version 2 of the License, or |
|
| 14 * (at your option) any later version. |
|
| 15 * |
|
| 16 * This program is distributed in the hope that it will be useful, |
|
| 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 19 * GNU General Public License for more details. |
|
| 20 * |
|
| 21 * You should have received a copy of the GNU General Public License |
|
| 22 * along with this program; if not, write to the Free Software |
|
| 23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
| 24 */ |
|
| 25 #include "internal.h" |
|
| 26 #include "gtkgaim.h" |
|
| 27 |
|
| 28 #include "debug.h" |
|
| 29 #include "notify.h" |
|
| 30 #include "ft.h" |
|
| 31 #include "prpl.h" |
|
| 32 #include "util.h" |
|
| 33 |
|
| 34 #include "gtkcellrendererprogress.h" |
|
| 35 #include "gtkft.h" |
|
| 36 #include "prefs.h" |
|
| 37 #include "gtkexpander.h" |
|
| 38 #include "gtkstock.h" |
|
| 39 #include "gtkutils.h" |
|
| 40 |
|
| 41 #define GAIM_GTKXFER(xfer) \ |
|
| 42 (GaimGtkXferUiData *)(xfer)->ui_data |
|
| 43 |
|
| 44 struct _GaimGtkXferDialog |
|
| 45 { |
|
| 46 gboolean keep_open; |
|
| 47 gboolean auto_clear; |
|
| 48 |
|
| 49 gint num_transfers; |
|
| 50 |
|
| 51 GaimXfer *selected_xfer; |
|
| 52 |
|
| 53 GtkWidget *window; |
|
| 54 GtkWidget *tree; |
|
| 55 GtkListStore *model; |
|
| 56 |
|
| 57 GtkWidget *expander; |
|
| 58 |
|
| 59 GtkWidget *table; |
|
| 60 |
|
| 61 GtkWidget *local_user_desc_label; |
|
| 62 GtkWidget *local_user_label; |
|
| 63 GtkWidget *remote_user_desc_label; |
|
| 64 GtkWidget *remote_user_label; |
|
| 65 GtkWidget *protocol_label; |
|
| 66 GtkWidget *filename_label; |
|
| 67 GtkWidget *localfile_label; |
|
| 68 GtkWidget *status_label; |
|
| 69 GtkWidget *speed_label; |
|
| 70 GtkWidget *time_elapsed_label; |
|
| 71 GtkWidget *time_remaining_label; |
|
| 72 |
|
| 73 GtkWidget *progress; |
|
| 74 |
|
| 75 /* Buttons */ |
|
| 76 GtkWidget *open_button; |
|
| 77 GtkWidget *pause_button; |
|
| 78 GtkWidget *resume_button; |
|
| 79 GtkWidget *remove_button; |
|
| 80 GtkWidget *stop_button; |
|
| 81 GtkWidget *close_button; |
|
| 82 }; |
|
| 83 |
|
| 84 typedef struct |
|
| 85 { |
|
| 86 GtkTreeIter iter; |
|
| 87 time_t start_time; |
|
| 88 time_t last_updated_time; |
|
| 89 time_t end_time; |
|
| 90 gboolean in_list; |
|
| 91 |
|
| 92 char *name; |
|
| 93 |
|
| 94 } GaimGtkXferUiData; |
|
| 95 |
|
| 96 static GaimGtkXferDialog *xfer_dialog = NULL; |
|
| 97 |
|
| 98 enum |
|
| 99 { |
|
| 100 COLUMN_STATUS = 0, |
|
| 101 COLUMN_PROGRESS, |
|
| 102 COLUMN_FILENAME, |
|
| 103 COLUMN_SIZE, |
|
| 104 COLUMN_REMAINING, |
|
| 105 COLUMN_DATA, |
|
| 106 NUM_COLUMNS |
|
| 107 }; |
|
| 108 |
|
| 109 |
|
| 110 /************************************************************************** |
|
| 111 * Utility Functions |
|
| 112 **************************************************************************/ |
|
| 113 static void |
|
| 114 get_xfer_info_strings(GaimXfer *xfer, char **kbsec, char **time_elapsed, |
|
| 115 char **time_remaining) |
|
| 116 { |
|
| 117 GaimGtkXferUiData *data; |
|
| 118 double kb_sent, kb_rem; |
|
| 119 double kbps = 0.0; |
|
| 120 time_t elapsed, now; |
|
| 121 |
|
| 122 data = GAIM_GTKXFER(xfer); |
|
| 123 |
|
| 124 if (data->end_time == -1 && |
|
| 125 (gaim_xfer_is_canceled(xfer) || gaim_xfer_is_completed(xfer))) |
|
| 126 data->end_time = time(NULL); |
|
| 127 |
|
| 128 if (data->end_time != -1) |
|
| 129 now = data->end_time; |
|
| 130 else |
|
| 131 now = time(NULL); |
|
| 132 |
|
| 133 kb_sent = gaim_xfer_get_bytes_sent(xfer) / 1024.0; |
|
| 134 kb_rem = gaim_xfer_get_bytes_remaining(xfer) / 1024.0; |
|
| 135 elapsed = (now - data->start_time); |
|
| 136 kbps = (elapsed > 0 ? (kb_sent / elapsed) : 0); |
|
| 137 |
|
| 138 if (kbsec != NULL) { |
|
| 139 *kbsec = g_strdup_printf(_("%.2f KB/s"), kbps); |
|
| 140 } |
|
| 141 |
|
| 142 if (time_elapsed != NULL) { |
|
| 143 int h, m, s; |
|
| 144 int secs_elapsed; |
|
| 145 |
|
| 146 secs_elapsed = now - data->start_time; |
|
| 147 |
|
| 148 h = secs_elapsed / 3600; |
|
| 149 m = (secs_elapsed % 3600) / 60; |
|
| 150 s = secs_elapsed % 60; |
|
| 151 |
|
| 152 *time_elapsed = g_strdup_printf("%d:%02d:%02d", h, m, s); |
|
| 153 } |
|
| 154 |
|
| 155 if (time_remaining != NULL) { |
|
| 156 if (gaim_xfer_get_size(xfer) == 0) { |
|
| 157 *time_remaining = g_strdup(_("Unknown")); |
|
| 158 } |
|
| 159 else if (gaim_xfer_is_completed(xfer)) { |
|
| 160 *time_remaining = g_strdup(_("Finished")); |
|
| 161 } |
|
| 162 else if (gaim_xfer_is_canceled(xfer)) { |
|
| 163 *time_remaining = g_strdup(_("Canceled")); |
|
| 164 } |
|
| 165 else if (kb_sent <= 0) { |
|
| 166 *time_remaining = g_strdup(_("Waiting for transfer to begin")); |
|
| 167 } |
|
| 168 else { |
|
| 169 int h, m, s; |
|
| 170 int secs_remaining; |
|
| 171 |
|
| 172 secs_remaining = (int)(kb_rem / kbps); |
|
| 173 |
|
| 174 h = secs_remaining / 3600; |
|
| 175 m = (secs_remaining % 3600) / 60; |
|
| 176 s = secs_remaining % 60; |
|
| 177 |
|
| 178 *time_remaining = g_strdup_printf("%d:%02d:%02d", h, m, s); |
|
| 179 } |
|
| 180 } |
|
| 181 } |
|
| 182 |
|
| 183 static void |
|
| 184 update_detailed_info(GaimGtkXferDialog *dialog, GaimXfer *xfer) |
|
| 185 { |
|
| 186 GaimGtkXferUiData *data; |
|
| 187 char *kbsec, *time_elapsed, *time_remaining; |
|
| 188 char *status, *utf8; |
|
| 189 |
|
| 190 if (dialog == NULL || xfer == NULL) |
|
| 191 return; |
|
| 192 |
|
| 193 data = GAIM_GTKXFER(xfer); |
|
| 194 |
|
| 195 get_xfer_info_strings(xfer, &kbsec, &time_elapsed, &time_remaining); |
|
| 196 |
|
| 197 status = g_strdup_printf("%ld%% (%ld of %ld bytes)", |
|
| 198 (unsigned long)(gaim_xfer_get_progress(xfer)*100), |
|
| 199 (unsigned long)gaim_xfer_get_bytes_sent(xfer), |
|
| 200 (unsigned long)gaim_xfer_get_size(xfer)); |
|
| 201 |
|
| 202 if (gaim_xfer_is_completed(xfer)) { |
|
| 203 |
|
| 204 GdkPixbuf *pixbuf = NULL; |
|
| 205 |
|
| 206 pixbuf = gtk_widget_render_icon(xfer_dialog->window, |
|
| 207 GAIM_STOCK_FILE_DONE, |
|
| 208 GTK_ICON_SIZE_MENU, NULL); |
|
| 209 |
|
| 210 gtk_list_store_set(GTK_LIST_STORE(xfer_dialog->model), &data->iter, |
|
| 211 COLUMN_STATUS, pixbuf, |
|
| 212 -1); |
|
| 213 |
|
| 214 g_object_unref(pixbuf); |
|
| 215 } |
|
| 216 |
|
| 217 if (gaim_xfer_get_type(xfer) == GAIM_XFER_RECEIVE) { |
|
| 218 gtk_label_set_markup(GTK_LABEL(dialog->local_user_desc_label), |
|
| 219 _("<b>Receiving As:</b>")); |
|
| 220 gtk_label_set_markup(GTK_LABEL(dialog->remote_user_desc_label), |
|
| 221 _("<b>Receiving From:</b>")); |
|
| 222 } |
|
| 223 else { |
|
| 224 gtk_label_set_markup(GTK_LABEL(dialog->remote_user_desc_label), |
|
| 225 _("<b>Sending To:</b>")); |
|
| 226 gtk_label_set_markup(GTK_LABEL(dialog->local_user_desc_label), |
|
| 227 _("<b>Sending As:</b>")); |
|
| 228 } |
|
| 229 |
|
| 230 gtk_label_set_text(GTK_LABEL(dialog->local_user_label), |
|
| 231 gaim_account_get_username(xfer->account)); |
|
| 232 gtk_label_set_text(GTK_LABEL(dialog->remote_user_label), xfer->who); |
|
| 233 gtk_label_set_text(GTK_LABEL(dialog->protocol_label), |
|
| 234 gaim_account_get_protocol_name(xfer->account)); |
|
| 235 |
|
| 236 if (gaim_xfer_get_type(xfer) == GAIM_XFER_RECEIVE) { |
|
| 237 gtk_label_set_text(GTK_LABEL(dialog->filename_label), |
|
| 238 gaim_xfer_get_filename(xfer)); |
|
| 239 } else { |
|
| 240 char *tmp; |
|
| 241 |
|
| 242 tmp = g_path_get_basename(gaim_xfer_get_local_filename(xfer)); |
|
| 243 utf8 = g_filename_to_utf8(tmp, -1, NULL, NULL, NULL); |
|
| 244 g_free(tmp); |
|
| 245 |
|
| 246 gtk_label_set_text(GTK_LABEL(dialog->filename_label), utf8); |
|
| 247 g_free(utf8); |
|
| 248 } |
|
| 249 |
|
| 250 utf8 = g_filename_to_utf8((gaim_xfer_get_local_filename(xfer)), -1, NULL, NULL, NULL); |
|
| 251 gtk_label_set_text(GTK_LABEL(dialog->localfile_label), utf8); |
|
| 252 g_free(utf8); |
|
| 253 |
|
| 254 gtk_label_set_text(GTK_LABEL(dialog->status_label), status); |
|
| 255 |
|
| 256 gtk_label_set_text(GTK_LABEL(dialog->speed_label), kbsec); |
|
| 257 gtk_label_set_text(GTK_LABEL(dialog->time_elapsed_label), time_elapsed); |
|
| 258 gtk_label_set_text(GTK_LABEL(dialog->time_remaining_label), |
|
| 259 time_remaining); |
|
| 260 |
|
| 261 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(dialog->progress), |
|
| 262 gaim_xfer_get_progress(xfer)); |
|
| 263 |
|
| 264 g_free(kbsec); |
|
| 265 g_free(time_elapsed); |
|
| 266 g_free(time_remaining); |
|
| 267 g_free(status); |
|
| 268 } |
|
| 269 |
|
| 270 static void |
|
| 271 update_buttons(GaimGtkXferDialog *dialog, GaimXfer *xfer) |
|
| 272 { |
|
| 273 if (dialog->selected_xfer == NULL) { |
|
| 274 gtk_widget_set_sensitive(dialog->expander, FALSE); |
|
| 275 gtk_widget_set_sensitive(dialog->open_button, FALSE); |
|
| 276 gtk_widget_set_sensitive(dialog->pause_button, FALSE); |
|
| 277 gtk_widget_set_sensitive(dialog->resume_button, FALSE); |
|
| 278 gtk_widget_set_sensitive(dialog->stop_button, FALSE); |
|
| 279 |
|
| 280 gtk_widget_show(dialog->stop_button); |
|
| 281 gtk_widget_hide(dialog->remove_button); |
|
| 282 |
|
| 283 return; |
|
| 284 } |
|
| 285 |
|
| 286 if (dialog->selected_xfer != xfer) |
|
| 287 return; |
|
| 288 |
|
| 289 if (gaim_xfer_is_completed(xfer)) { |
|
| 290 gtk_widget_hide(dialog->stop_button); |
|
| 291 gtk_widget_show(dialog->remove_button); |
|
| 292 |
|
| 293 #ifdef _WIN32 |
|
| 294 /* If using Win32... */ |
|
| 295 if (gaim_xfer_get_type(xfer) == GAIM_XFER_RECEIVE) { |
|
| 296 gtk_widget_set_sensitive(dialog->open_button, TRUE); |
|
| 297 } else { |
|
| 298 gtk_widget_set_sensitive(dialog->open_button, FALSE); |
|
| 299 } |
|
| 300 #else |
|
| 301 if (gaim_xfer_get_type(xfer) == GAIM_XFER_RECEIVE) { |
|
| 302 gtk_widget_set_sensitive(dialog->open_button, TRUE); |
|
| 303 } else { |
|
| 304 gtk_widget_set_sensitive (dialog->open_button, FALSE); |
|
| 305 } |
|
| 306 #endif |
|
| 307 gtk_widget_set_sensitive(dialog->pause_button, FALSE); |
|
| 308 gtk_widget_set_sensitive(dialog->resume_button, FALSE); |
|
| 309 |
|
| 310 gtk_widget_set_sensitive(dialog->remove_button, TRUE); |
|
| 311 } else if (gaim_xfer_is_canceled(xfer)) { |
|
| 312 gtk_widget_hide(dialog->stop_button); |
|
| 313 gtk_widget_show(dialog->remove_button); |
|
| 314 |
|
| 315 gtk_widget_set_sensitive(dialog->open_button, FALSE); |
|
| 316 gtk_widget_set_sensitive(dialog->pause_button, FALSE); |
|
| 317 gtk_widget_set_sensitive(dialog->resume_button, FALSE); |
|
| 318 |
|
| 319 gtk_widget_set_sensitive(dialog->remove_button, TRUE); |
|
| 320 } else { |
|
| 321 gtk_widget_show(dialog->stop_button); |
|
| 322 gtk_widget_hide(dialog->remove_button); |
|
| 323 |
|
| 324 gtk_widget_set_sensitive(dialog->open_button, FALSE); |
|
| 325 |
|
| 326 /* TODO: If the transfer can pause, blah blah */ |
|
| 327 gtk_widget_set_sensitive(dialog->pause_button, FALSE); |
|
| 328 gtk_widget_set_sensitive(dialog->resume_button, FALSE); |
|
| 329 gtk_widget_set_sensitive(dialog->stop_button, TRUE); |
|
| 330 } |
|
| 331 } |
|
| 332 |
|
| 333 static void |
|
| 334 ensure_row_selected(GaimGtkXferDialog *dialog) |
|
| 335 { |
|
| 336 GtkTreeIter iter; |
|
| 337 GtkTreeSelection *selection; |
|
| 338 |
|
| 339 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->tree)); |
|
| 340 |
|
| 341 if (gtk_tree_selection_get_selected(selection, NULL, &iter)) |
|
| 342 return; |
|
| 343 |
|
| 344 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(dialog->model), &iter)) |
|
| 345 gtk_tree_selection_select_iter(selection, &iter); |
|
| 346 } |
|
| 347 |
|
| 348 /************************************************************************** |
|
| 349 * Callbacks |
|
| 350 **************************************************************************/ |
|
| 351 static gint |
|
| 352 delete_win_cb(GtkWidget *w, GdkEventAny *e, gpointer d) |
|
| 353 { |
|
| 354 GaimGtkXferDialog *dialog; |
|
| 355 |
|
| 356 dialog = (GaimGtkXferDialog *)d; |
|
| 357 |
|
| 358 gaim_gtkxfer_dialog_hide(dialog); |
|
| 359 |
|
| 360 return TRUE; |
|
| 361 } |
|
| 362 |
|
| 363 static void |
|
| 364 toggle_keep_open_cb(GtkWidget *w, GaimGtkXferDialog *dialog) |
|
| 365 { |
|
| 366 dialog->keep_open = !dialog->keep_open; |
|
| 367 gaim_prefs_set_bool("/gaim/gtk/filetransfer/keep_open", |
|
| 368 dialog->keep_open); |
|
| 369 } |
|
| 370 |
|
| 371 static void |
|
| 372 toggle_clear_finished_cb(GtkWidget *w, GaimGtkXferDialog *dialog) |
|
| 373 { |
|
| 374 dialog->auto_clear = !dialog->auto_clear; |
|
| 375 gaim_prefs_set_bool("/gaim/gtk/filetransfer/clear_finished", |
|
| 376 dialog->auto_clear); |
|
| 377 } |
|
| 378 |
|
| 379 static void |
|
| 380 selection_changed_cb(GtkTreeSelection *selection, GaimGtkXferDialog *dialog) |
|
| 381 { |
|
| 382 GtkTreeIter iter; |
|
| 383 GaimXfer *xfer = NULL; |
|
| 384 |
|
| 385 if (gtk_tree_selection_get_selected(selection, NULL, &iter)) { |
|
| 386 GValue val; |
|
| 387 |
|
| 388 gtk_widget_set_sensitive(dialog->expander, TRUE); |
|
| 389 |
|
| 390 val.g_type = 0; |
|
| 391 gtk_tree_model_get_value(GTK_TREE_MODEL(dialog->model), |
|
| 392 &iter, COLUMN_DATA, &val); |
|
| 393 |
|
| 394 xfer = g_value_get_pointer(&val); |
|
| 395 |
|
| 396 update_detailed_info(dialog, xfer); |
|
| 397 |
|
| 398 dialog->selected_xfer = xfer; |
|
| 399 } |
|
| 400 else { |
|
| 401 gtk_expander_set_expanded(GTK_EXPANDER(dialog->expander), |
|
| 402 FALSE); |
|
| 403 |
|
| 404 gtk_widget_set_sensitive(dialog->expander, FALSE); |
|
| 405 |
|
| 406 dialog->selected_xfer = NULL; |
|
| 407 } |
|
| 408 |
|
| 409 update_buttons(dialog, xfer); |
|
| 410 } |
|
| 411 |
|
| 412 static void |
|
| 413 open_button_cb(GtkButton *button, GaimGtkXferDialog *dialog) |
|
| 414 { |
|
| 415 #ifdef _WIN32 |
|
| 416 /* If using Win32... */ |
|
| 417 int code; |
|
| 418 if (G_WIN32_HAVE_WIDECHAR_API ()) { |
|
| 419 wchar_t *wc_filename = g_utf8_to_utf16( |
|
| 420 gaim_xfer_get_local_filename( |
|
| 421 dialog->selected_xfer), |
|
| 422 -1, NULL, NULL, NULL); |
|
| 423 |
|
| 424 code = (int) ShellExecuteW(NULL, NULL, wc_filename, NULL, NULL, |
|
| 425 SW_SHOW); |
|
| 426 |
|
| 427 g_free(wc_filename); |
|
| 428 } else { |
|
| 429 char *l_filename = g_locale_from_utf8( |
|
| 430 gaim_xfer_get_local_filename( |
|
| 431 dialog->selected_xfer), |
|
| 432 -1, NULL, NULL, NULL); |
|
| 433 |
|
| 434 code = (int) ShellExecuteA(NULL, NULL, l_filename, NULL, NULL, |
|
| 435 SW_SHOW); |
|
| 436 |
|
| 437 g_free(l_filename); |
|
| 438 } |
|
| 439 |
|
| 440 if (code == SE_ERR_ASSOCINCOMPLETE || code == SE_ERR_NOASSOC) |
|
| 441 { |
|
| 442 gaim_notify_error(dialog, NULL, |
|
| 443 _("There is no application configured to open this type of file."), NULL); |
|
| 444 } |
|
| 445 else if (code < 32) |
|
| 446 { |
|
| 447 gaim_notify_error(dialog, NULL, |
|
| 448 _("An error occurred while opening the file."), NULL); |
|
| 449 gaim_debug_warning("ft", "filename: %s; code: %d\n", |
|
| 450 gaim_xfer_get_local_filename(dialog->selected_xfer), code); |
|
| 451 } |
|
| 452 #else |
|
| 453 const char *filename = gaim_xfer_get_local_filename(dialog->selected_xfer); |
|
| 454 char *command = NULL; |
|
| 455 char *tmp = NULL; |
|
| 456 GError *error = NULL; |
|
| 457 |
|
| 458 if (gaim_running_gnome()) |
|
| 459 { |
|
| 460 char *escaped = g_shell_quote(filename); |
|
| 461 command = g_strdup_printf("gnome-open %s", escaped); |
|
| 462 g_free(escaped); |
|
| 463 } |
|
| 464 else if (gaim_running_kde()) |
|
| 465 { |
|
| 466 char *escaped = g_shell_quote(filename); |
|
| 467 |
|
| 468 if (gaim_str_has_suffix(filename, ".desktop")) |
|
| 469 command = g_strdup_printf("kfmclient openURL %s 'text/plain'", escaped); |
|
| 470 else |
|
| 471 command = g_strdup_printf("kfmclient openURL %s", escaped); |
|
| 472 g_free(escaped); |
|
| 473 } |
|
| 474 else |
|
| 475 { |
|
| 476 gaim_notify_uri(NULL, filename); |
|
| 477 return; |
|
| 478 } |
|
| 479 |
|
| 480 if (gaim_program_is_valid(command)) |
|
| 481 { |
|
| 482 gint exit_status; |
|
| 483 if (!g_spawn_command_line_sync(command, NULL, NULL, &exit_status, &error)) |
|
| 484 { |
|
| 485 tmp = g_strdup_printf(_("Error launching %s: %s"), |
|
| 486 gaim_xfer_get_local_filename(dialog->selected_xfer), |
|
| 487 error->message); |
|
| 488 gaim_notify_error(dialog, NULL, _("Unable to open file."), tmp); |
|
| 489 g_free(tmp); |
|
| 490 g_error_free(error); |
|
| 491 } |
|
| 492 if (exit_status != 0) |
|
| 493 { |
|
| 494 char *primary = g_strdup_printf(_("Error running %s"), command); |
|
| 495 char *secondary = g_strdup_printf(_("Process returned error code %d"), |
|
| 496 exit_status); |
|
| 497 gaim_notify_error(dialog, NULL, primary, secondary); |
|
| 498 g_free(tmp); |
|
| 499 } |
|
| 500 } |
|
| 501 #endif |
|
| 502 } |
|
| 503 |
|
| 504 static void |
|
| 505 pause_button_cb(GtkButton *button, GaimGtkXferDialog *dialog) |
|
| 506 { |
|
| 507 } |
|
| 508 |
|
| 509 static void |
|
| 510 resume_button_cb(GtkButton *button, GaimGtkXferDialog *dialog) |
|
| 511 { |
|
| 512 } |
|
| 513 |
|
| 514 static void |
|
| 515 remove_button_cb(GtkButton *button, GaimGtkXferDialog *dialog) |
|
| 516 { |
|
| 517 gaim_gtkxfer_dialog_remove_xfer(dialog, dialog->selected_xfer); |
|
| 518 } |
|
| 519 |
|
| 520 static void |
|
| 521 stop_button_cb(GtkButton *button, GaimGtkXferDialog *dialog) |
|
| 522 { |
|
| 523 gaim_xfer_cancel_local(dialog->selected_xfer); |
|
| 524 } |
|
| 525 |
|
| 526 static void |
|
| 527 close_button_cb(GtkButton *button, GaimGtkXferDialog *dialog) |
|
| 528 { |
|
| 529 gaim_gtkxfer_dialog_hide(dialog); |
|
| 530 } |
|
| 531 |
|
| 532 /************************************************************************** |
|
| 533 * Dialog Building Functions |
|
| 534 **************************************************************************/ |
|
| 535 static GtkWidget * |
|
| 536 setup_tree(GaimGtkXferDialog *dialog) |
|
| 537 { |
|
| 538 GtkWidget *sw; |
|
| 539 GtkWidget *tree; |
|
| 540 GtkListStore *model; |
|
| 541 GtkCellRenderer *renderer; |
|
| 542 GtkTreeViewColumn *column; |
|
| 543 GtkTreeSelection *selection; |
|
| 544 |
|
| 545 /* Create the scrolled window. */ |
|
| 546 sw = gtk_scrolled_window_new(0, 0); |
|
| 547 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), |
|
| 548 GTK_SHADOW_IN); |
|
| 549 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), |
|
| 550 GTK_POLICY_AUTOMATIC, |
|
| 551 GTK_POLICY_ALWAYS); |
|
| 552 gtk_widget_show(sw); |
|
| 553 |
|
| 554 /* Build the tree model */ |
|
| 555 /* Transfer type, Progress Bar, Filename, Size, Remaining */ |
|
| 556 model = gtk_list_store_new(NUM_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_DOUBLE, |
|
| 557 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, |
|
| 558 G_TYPE_POINTER); |
|
| 559 dialog->model = model; |
|
| 560 |
|
| 561 /* Create the treeview */ |
|
| 562 dialog->tree = tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model)); |
|
| 563 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree), TRUE); |
|
| 564 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)); |
|
| 565 /* gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE); */ |
|
| 566 |
|
| 567 gtk_widget_show(tree); |
|
| 568 |
|
| 569 g_signal_connect(G_OBJECT(selection), "changed", |
|
| 570 G_CALLBACK(selection_changed_cb), dialog); |
|
| 571 |
|
| 572 g_object_unref(G_OBJECT(model)); |
|
| 573 |
|
| 574 |
|
| 575 /* Columns */ |
|
| 576 |
|
| 577 /* Transfer Type column */ |
|
| 578 renderer = gtk_cell_renderer_pixbuf_new(); |
|
| 579 column = gtk_tree_view_column_new_with_attributes(NULL, renderer, |
|
| 580 "pixbuf", COLUMN_STATUS, NULL); |
|
| 581 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column), |
|
| 582 GTK_TREE_VIEW_COLUMN_FIXED); |
|
| 583 gtk_tree_view_column_set_fixed_width(GTK_TREE_VIEW_COLUMN(column), 25); |
|
| 584 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE); |
|
| 585 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); |
|
| 586 |
|
| 587 /* Progress bar column */ |
|
| 588 renderer = gaim_gtk_cell_renderer_progress_new(); |
|
| 589 column = gtk_tree_view_column_new_with_attributes(_("Progress"), renderer, |
|
| 590 "percentage", COLUMN_PROGRESS, NULL); |
|
| 591 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE); |
|
| 592 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); |
|
| 593 |
|
| 594 /* Filename column */ |
|
| 595 renderer = gtk_cell_renderer_text_new(); |
|
| 596 column = gtk_tree_view_column_new_with_attributes(_("Filename"), renderer, |
|
| 597 "text", COLUMN_FILENAME, NULL); |
|
| 598 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE); |
|
| 599 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); |
|
| 600 |
|
| 601 /* File Size column */ |
|
| 602 renderer = gtk_cell_renderer_text_new(); |
|
| 603 column = gtk_tree_view_column_new_with_attributes(_("Size"), renderer, |
|
| 604 "text", COLUMN_SIZE, NULL); |
|
| 605 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE); |
|
| 606 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); |
|
| 607 |
|
| 608 /* Bytes Remaining column */ |
|
| 609 renderer = gtk_cell_renderer_text_new(); |
|
| 610 column = gtk_tree_view_column_new_with_attributes(_("Remaining"), |
|
| 611 renderer, "text", COLUMN_REMAINING, NULL); |
|
| 612 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE); |
|
| 613 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); |
|
| 614 |
|
| 615 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(tree)); |
|
| 616 |
|
| 617 gtk_container_add(GTK_CONTAINER(sw), tree); |
|
| 618 gtk_widget_show(tree); |
|
| 619 |
|
| 620 return sw; |
|
| 621 } |
|
| 622 |
|
| 623 static GtkWidget * |
|
| 624 make_info_table(GaimGtkXferDialog *dialog) |
|
| 625 { |
|
| 626 GtkWidget *table; |
|
| 627 GtkWidget *label; |
|
| 628 int i; |
|
| 629 |
|
| 630 struct |
|
| 631 { |
|
| 632 GtkWidget **desc_label; |
|
| 633 GtkWidget **val_label; |
|
| 634 const char *desc; |
|
| 635 |
|
| 636 } labels[] = |
|
| 637 { |
|
| 638 { &dialog->local_user_desc_label, &dialog->local_user_label, NULL }, |
|
| 639 { &dialog->remote_user_desc_label, &dialog->remote_user_label, NULL }, |
|
| 640 { &label, &dialog->protocol_label, _("Protocol:") }, |
|
| 641 { &label, &dialog->filename_label, _("Filename:") }, |
|
| 642 { &label, &dialog->localfile_label, _("Local File:") }, |
|
| 643 { &label, &dialog->status_label, _("Status:") }, |
|
| 644 { &label, &dialog->speed_label, _("Speed:") }, |
|
| 645 { &label, &dialog->time_elapsed_label, _("Time Elapsed:") }, |
|
| 646 { &label, &dialog->time_remaining_label, _("Time Remaining:") } |
|
| 647 }; |
|
| 648 |
|
| 649 /* Setup the initial table */ |
|
| 650 dialog->table = table = gtk_table_new(9, 2, FALSE); |
|
| 651 gtk_table_set_row_spacings(GTK_TABLE(table), GAIM_HIG_BOX_SPACE); |
|
| 652 gtk_table_set_col_spacings(GTK_TABLE(table), GAIM_HIG_BOX_SPACE); |
|
| 653 |
|
| 654 /* Setup the labels */ |
|
| 655 for (i = 0; i < sizeof(labels) / sizeof(*labels); i++) { |
|
| 656 GtkWidget *label; |
|
| 657 char buf[256]; |
|
| 658 |
|
| 659 g_snprintf(buf, sizeof(buf), "<b>%s</b>", |
|
| 660 labels[i].desc != NULL ? labels[i].desc : ""); |
|
| 661 |
|
| 662 *labels[i].desc_label = label = gtk_label_new(NULL); |
|
| 663 gtk_label_set_markup(GTK_LABEL(label), buf); |
|
| 664 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT); |
|
| 665 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); |
|
| 666 gtk_table_attach(GTK_TABLE(table), label, 0, 1, i, i + 1, |
|
| 667 GTK_FILL, 0, 0, 0); |
|
| 668 gtk_widget_show(label); |
|
| 669 |
|
| 670 *labels[i].val_label = label = gtk_label_new(NULL); |
|
| 671 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); |
|
| 672 gtk_table_attach(GTK_TABLE(table), label, 1, 2, i, i + 1, |
|
| 673 GTK_FILL | GTK_EXPAND, 0, 0, 0); |
|
| 674 gtk_widget_show(label); |
|
| 675 } |
|
| 676 |
|
| 677 /* Setup the progress bar */ |
|
| 678 dialog->progress = gtk_progress_bar_new(); |
|
| 679 gtk_table_attach(GTK_TABLE(table), dialog->progress, 0, 2, 8, 9, |
|
| 680 GTK_FILL, GTK_FILL, 0, 0); |
|
| 681 gtk_widget_show(dialog->progress); |
|
| 682 |
|
| 683 return table; |
|
| 684 } |
|
| 685 |
|
| 686 GaimGtkXferDialog * |
|
| 687 gaim_gtkxfer_dialog_new(void) |
|
| 688 { |
|
| 689 GaimGtkXferDialog *dialog; |
|
| 690 GtkWidget *window; |
|
| 691 GtkWidget *vbox1, *vbox2; |
|
| 692 GtkWidget *bbox; |
|
| 693 GtkWidget *sw; |
|
| 694 GtkWidget *button; |
|
| 695 GtkWidget *expander; |
|
| 696 GtkWidget *table; |
|
| 697 GtkWidget *checkbox; |
|
| 698 |
|
| 699 dialog = g_new0(GaimGtkXferDialog, 1); |
|
| 700 dialog->keep_open = |
|
| 701 gaim_prefs_get_bool("/gaim/gtk/filetransfer/keep_open"); |
|
| 702 dialog->auto_clear = |
|
| 703 gaim_prefs_get_bool("/gaim/gtk/filetransfer/clear_finished"); |
|
| 704 |
|
| 705 /* Create the window. */ |
|
| 706 dialog->window = window = gtk_window_new(GTK_WINDOW_TOPLEVEL); |
|
| 707 gtk_window_set_role(GTK_WINDOW(window), "file transfer"); |
|
| 708 gtk_window_set_title(GTK_WINDOW(window), _("File Transfers")); |
|
| 709 gtk_container_set_border_width(GTK_CONTAINER(window), GAIM_HIG_BORDER); |
|
| 710 |
|
| 711 g_signal_connect(G_OBJECT(window), "delete_event", |
|
| 712 G_CALLBACK(delete_win_cb), dialog); |
|
| 713 |
|
| 714 /* Create the parent vbox for everything. */ |
|
| 715 vbox1 = gtk_vbox_new(FALSE, GAIM_HIG_BORDER); |
|
| 716 gtk_container_add(GTK_CONTAINER(window), vbox1); |
|
| 717 gtk_widget_show(vbox1); |
|
| 718 |
|
| 719 /* Create the main vbox for top half of the window. */ |
|
| 720 vbox2 = gtk_vbox_new(FALSE, GAIM_HIG_BOX_SPACE); |
|
| 721 gtk_box_pack_start(GTK_BOX(vbox1), vbox2, TRUE, TRUE, 0); |
|
| 722 gtk_widget_show(vbox2); |
|
| 723 |
|
| 724 /* Setup the listbox */ |
|
| 725 sw = setup_tree(dialog); |
|
| 726 gtk_box_pack_start(GTK_BOX(vbox2), sw, TRUE, TRUE, 0); |
|
| 727 gtk_widget_set_size_request(sw,-1, 140); |
|
| 728 |
|
| 729 /* "Close this window when all transfers finish" */ |
|
| 730 checkbox = gtk_check_button_new_with_mnemonic( |
|
| 731 _("Close this window when all transfers _finish")); |
|
| 732 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox), |
|
| 733 !dialog->keep_open); |
|
| 734 g_signal_connect(G_OBJECT(checkbox), "toggled", |
|
| 735 G_CALLBACK(toggle_keep_open_cb), dialog); |
|
| 736 gtk_box_pack_start(GTK_BOX(vbox2), checkbox, FALSE, FALSE, 0); |
|
| 737 gtk_widget_show(checkbox); |
|
| 738 |
|
| 739 /* "Clear finished transfers" */ |
|
| 740 checkbox = gtk_check_button_new_with_mnemonic( |
|
| 741 _("C_lear finished transfers")); |
|
| 742 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox), |
|
| 743 dialog->auto_clear); |
|
| 744 g_signal_connect(G_OBJECT(checkbox), "toggled", |
|
| 745 G_CALLBACK(toggle_clear_finished_cb), dialog); |
|
| 746 gtk_box_pack_start(GTK_BOX(vbox2), checkbox, FALSE, FALSE, 0); |
|
| 747 gtk_widget_show(checkbox); |
|
| 748 |
|
| 749 /* "Download Details" arrow */ |
|
| 750 expander = gtk_expander_new_with_mnemonic(_("File transfer _details")); |
|
| 751 dialog->expander = expander; |
|
| 752 gtk_box_pack_start(GTK_BOX(vbox2), expander, FALSE, FALSE, 0); |
|
| 753 gtk_widget_show(expander); |
|
| 754 |
|
| 755 gtk_widget_set_sensitive(expander, FALSE); |
|
| 756 |
|
| 757 /* The table of information. */ |
|
| 758 table = make_info_table(dialog); |
|
| 759 gtk_container_add(GTK_CONTAINER(expander), table); |
|
| 760 gtk_widget_show(table); |
|
| 761 |
|
| 762 /* Now the button box for the buttons */ |
|
| 763 bbox = gtk_hbutton_box_new(); |
|
| 764 gtk_box_set_spacing(GTK_BOX(bbox), GAIM_HIG_BOX_SPACE); |
|
| 765 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); |
|
| 766 gtk_box_pack_end(GTK_BOX(vbox1), bbox, FALSE, TRUE, 0); |
|
| 767 gtk_widget_show(bbox); |
|
| 768 |
|
| 769 /* Open button */ |
|
| 770 button = gtk_button_new_from_stock(GTK_STOCK_OPEN); |
|
| 771 gtk_widget_set_sensitive(button, FALSE); |
|
| 772 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); |
|
| 773 gtk_widget_show(button); |
|
| 774 dialog->open_button = button; |
|
| 775 |
|
| 776 g_signal_connect(G_OBJECT(button), "clicked", |
|
| 777 G_CALLBACK(open_button_cb), dialog); |
|
| 778 |
|
| 779 /* Pause button */ |
|
| 780 button = gtk_button_new_with_mnemonic(_("_Pause")); |
|
| 781 gtk_widget_set_sensitive(button, FALSE); |
|
| 782 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); |
|
| 783 gtk_widget_show(button); |
|
| 784 dialog->pause_button = button; |
|
| 785 |
|
| 786 g_signal_connect(G_OBJECT(button), "clicked", |
|
| 787 G_CALLBACK(pause_button_cb), dialog); |
|
| 788 |
|
| 789 /* Resume button */ |
|
| 790 button = gtk_button_new_with_mnemonic(_("_Resume")); |
|
| 791 gtk_widget_set_sensitive(button, FALSE); |
|
| 792 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); |
|
| 793 gtk_widget_show(button); |
|
| 794 dialog->resume_button = button; |
|
| 795 |
|
| 796 g_signal_connect(G_OBJECT(button), "clicked", |
|
| 797 G_CALLBACK(resume_button_cb), dialog); |
|
| 798 |
|
| 799 /* Remove button */ |
|
| 800 button = gtk_button_new_from_stock(GTK_STOCK_REMOVE); |
|
| 801 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); |
|
| 802 gtk_widget_hide(button); |
|
| 803 dialog->remove_button = button; |
|
| 804 |
|
| 805 g_signal_connect(G_OBJECT(button), "clicked", |
|
| 806 G_CALLBACK(remove_button_cb), dialog); |
|
| 807 |
|
| 808 /* Stop button */ |
|
| 809 button = gtk_button_new_from_stock(GTK_STOCK_STOP); |
|
| 810 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); |
|
| 811 gtk_widget_show(button); |
|
| 812 gtk_widget_set_sensitive(button, FALSE); |
|
| 813 dialog->stop_button = button; |
|
| 814 |
|
| 815 g_signal_connect(G_OBJECT(button), "clicked", |
|
| 816 G_CALLBACK(stop_button_cb), dialog); |
|
| 817 |
|
| 818 /* Close button */ |
|
| 819 button = gtk_button_new_from_stock(GTK_STOCK_CLOSE); |
|
| 820 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); |
|
| 821 gtk_widget_show(button); |
|
| 822 dialog->close_button = button; |
|
| 823 |
|
| 824 g_signal_connect(G_OBJECT(button), "clicked", |
|
| 825 G_CALLBACK(close_button_cb), dialog); |
|
| 826 |
|
| 827 return dialog; |
|
| 828 } |
|
| 829 |
|
| 830 void |
|
| 831 gaim_gtkxfer_dialog_destroy(GaimGtkXferDialog *dialog) |
|
| 832 { |
|
| 833 g_return_if_fail(dialog != NULL); |
|
| 834 |
|
| 835 gaim_notify_close_with_handle(dialog); |
|
| 836 |
|
| 837 gtk_widget_destroy(dialog->window); |
|
| 838 |
|
| 839 g_free(dialog); |
|
| 840 } |
|
| 841 |
|
| 842 void |
|
| 843 gaim_gtkxfer_dialog_show(GaimGtkXferDialog *dialog) |
|
| 844 { |
|
| 845 g_return_if_fail(dialog != NULL); |
|
| 846 |
|
| 847 gtk_widget_show(dialog->window); |
|
| 848 } |
|
| 849 |
|
| 850 void |
|
| 851 gaim_gtkxfer_dialog_hide(GaimGtkXferDialog *dialog) |
|
| 852 { |
|
| 853 g_return_if_fail(dialog != NULL); |
|
| 854 |
|
| 855 gaim_notify_close_with_handle(dialog); |
|
| 856 |
|
| 857 gtk_widget_hide(dialog->window); |
|
| 858 } |
|
| 859 |
|
| 860 void |
|
| 861 gaim_show_xfer_dialog() |
|
| 862 { |
|
| 863 GaimGtkXferDialog *dialog; |
|
| 864 |
|
| 865 dialog = gaim_get_gtkxfer_dialog(); |
|
| 866 |
|
| 867 if (dialog == NULL) { |
|
| 868 dialog = gaim_gtkxfer_dialog_new(); |
|
| 869 |
|
| 870 gaim_set_gtkxfer_dialog(dialog); |
|
| 871 } |
|
| 872 |
|
| 873 gaim_gtkxfer_dialog_show(dialog); |
|
| 874 } |
|
| 875 |
|
| 876 void |
|
| 877 gaim_gtkxfer_dialog_add_xfer(GaimGtkXferDialog *dialog, GaimXfer *xfer) |
|
| 878 { |
|
| 879 GaimGtkXferUiData *data; |
|
| 880 GaimXferType type; |
|
| 881 GdkPixbuf *pixbuf; |
|
| 882 char *size_str, *remaining_str; |
|
| 883 char *lfilename, *utf8; |
|
| 884 |
|
| 885 g_return_if_fail(dialog != NULL); |
|
| 886 g_return_if_fail(xfer != NULL); |
|
| 887 |
|
| 888 gaim_xfer_ref(xfer); |
|
| 889 |
|
| 890 data = GAIM_GTKXFER(xfer); |
|
| 891 data->in_list = TRUE; |
|
| 892 |
|
| 893 gaim_gtkxfer_dialog_show(dialog); |
|
| 894 |
|
| 895 data->start_time = time(NULL); |
|
| 896 data->last_updated_time = 0; |
|
| 897 data->end_time = -1; |
|
| 898 |
|
| 899 type = gaim_xfer_get_type(xfer); |
|
| 900 |
|
| 901 size_str = gaim_str_size_to_units(gaim_xfer_get_size(xfer)); |
|
| 902 remaining_str = gaim_str_size_to_units(gaim_xfer_get_bytes_remaining(xfer)); |
|
| 903 |
|
| 904 pixbuf = gtk_widget_render_icon(dialog->window, |
|
| 905 (type == GAIM_XFER_RECEIVE |
|
| 906 ? GAIM_STOCK_DOWNLOAD |
|
| 907 : GAIM_STOCK_UPLOAD), |
|
| 908 GTK_ICON_SIZE_MENU, NULL); |
|
| 909 |
|
| 910 gtk_list_store_append(dialog->model, &data->iter); |
|
| 911 lfilename = g_path_get_basename(gaim_xfer_get_local_filename(xfer)); |
|
| 912 utf8 = g_filename_to_utf8(lfilename, -1, NULL, NULL, NULL); |
|
| 913 g_free(lfilename); |
|
| 914 lfilename = utf8; |
|
| 915 gtk_list_store_set(dialog->model, &data->iter, |
|
| 916 COLUMN_STATUS, pixbuf, |
|
| 917 COLUMN_PROGRESS, 0.0, |
|
| 918 COLUMN_FILENAME, (type == GAIM_XFER_RECEIVE) |
|
| 919 ? gaim_xfer_get_filename(xfer) |
|
| 920 : lfilename, |
|
| 921 COLUMN_SIZE, size_str, |
|
| 922 COLUMN_REMAINING, _("Waiting for transfer to begin"), |
|
| 923 COLUMN_DATA, xfer, |
|
| 924 -1); |
|
| 925 g_free(lfilename); |
|
| 926 |
|
| 927 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(dialog->tree)); |
|
| 928 |
|
| 929 g_object_unref(pixbuf); |
|
| 930 |
|
| 931 g_free(size_str); |
|
| 932 g_free(remaining_str); |
|
| 933 |
|
| 934 dialog->num_transfers++; |
|
| 935 |
|
| 936 ensure_row_selected(dialog); |
|
| 937 } |
|
| 938 |
|
| 939 void |
|
| 940 gaim_gtkxfer_dialog_remove_xfer(GaimGtkXferDialog *dialog, |
|
| 941 GaimXfer *xfer) |
|
| 942 { |
|
| 943 GaimGtkXferUiData *data; |
|
| 944 |
|
| 945 g_return_if_fail(dialog != NULL); |
|
| 946 g_return_if_fail(xfer != NULL); |
|
| 947 |
|
| 948 data = GAIM_GTKXFER(xfer); |
|
| 949 |
|
| 950 if (data == NULL) |
|
| 951 return; |
|
| 952 |
|
| 953 if (!data->in_list) |
|
| 954 return; |
|
| 955 |
|
| 956 data->in_list = FALSE; |
|
| 957 |
|
| 958 gtk_list_store_remove(GTK_LIST_STORE(dialog->model), &data->iter); |
|
| 959 |
|
| 960 dialog->num_transfers--; |
|
| 961 |
|
| 962 if (dialog->num_transfers == 0 && !dialog->keep_open) |
|
| 963 gaim_gtkxfer_dialog_hide(dialog); |
|
| 964 else |
|
| 965 ensure_row_selected(dialog); |
|
| 966 |
|
| 967 gaim_xfer_unref(xfer); |
|
| 968 } |
|
| 969 |
|
| 970 void |
|
| 971 gaim_gtkxfer_dialog_cancel_xfer(GaimGtkXferDialog *dialog, |
|
| 972 GaimXfer *xfer) |
|
| 973 { |
|
| 974 GaimGtkXferUiData *data; |
|
| 975 GdkPixbuf *pixbuf; |
|
| 976 gchar *status; |
|
| 977 |
|
| 978 g_return_if_fail(dialog != NULL); |
|
| 979 g_return_if_fail(xfer != NULL); |
|
| 980 |
|
| 981 data = GAIM_GTKXFER(xfer); |
|
| 982 |
|
| 983 if (data == NULL) |
|
| 984 return; |
|
| 985 |
|
| 986 if (!data->in_list) |
|
| 987 return; |
|
| 988 |
|
| 989 if ((gaim_xfer_get_status(xfer) == GAIM_XFER_STATUS_CANCEL_LOCAL) && (dialog->auto_clear)) { |
|
| 990 gaim_gtkxfer_dialog_remove_xfer(dialog, xfer); |
|
| 991 return; |
|
| 992 } |
|
| 993 |
|
| 994 data = GAIM_GTKXFER(xfer); |
|
| 995 |
|
| 996 update_detailed_info(dialog, xfer); |
|
| 997 |
|
| 998 pixbuf = gtk_widget_render_icon(dialog->window, |
|
| 999 GAIM_STOCK_FILE_CANCELED, |
|
| 1000 GTK_ICON_SIZE_MENU, NULL); |
|
| 1001 |
|
| 1002 if (gaim_xfer_is_canceled(xfer)) |
|
| 1003 status = _("Canceled"); |
|
| 1004 else |
|
| 1005 status = _("Failed"); |
|
| 1006 |
|
| 1007 gtk_list_store_set(dialog->model, &data->iter, |
|
| 1008 COLUMN_STATUS, pixbuf, |
|
| 1009 COLUMN_REMAINING, status, |
|
| 1010 -1); |
|
| 1011 |
|
| 1012 g_object_unref(pixbuf); |
|
| 1013 |
|
| 1014 update_buttons(dialog, xfer); |
|
| 1015 } |
|
| 1016 |
|
| 1017 void |
|
| 1018 gaim_gtkxfer_dialog_update_xfer(GaimGtkXferDialog *dialog, |
|
| 1019 GaimXfer *xfer) |
|
| 1020 { |
|
| 1021 GaimGtkXferUiData *data; |
|
| 1022 char *size_str, *remaining_str; |
|
| 1023 GtkTreeSelection *selection; |
|
| 1024 time_t current_time; |
|
| 1025 |
|
| 1026 g_return_if_fail(dialog != NULL); |
|
| 1027 g_return_if_fail(xfer != NULL); |
|
| 1028 |
|
| 1029 if ((data = GAIM_GTKXFER(xfer)) == NULL) |
|
| 1030 return; |
|
| 1031 |
|
| 1032 if (data->in_list == FALSE) |
|
| 1033 return; |
|
| 1034 |
|
| 1035 current_time = time(NULL); |
|
| 1036 if (((current_time - data->last_updated_time) == 0) && |
|
| 1037 (!gaim_xfer_is_completed(xfer))) |
|
| 1038 { |
|
| 1039 /* Don't update the window more than once per second */ |
|
| 1040 return; |
|
| 1041 } |
|
| 1042 data->last_updated_time = current_time; |
|
| 1043 |
|
| 1044 size_str = gaim_str_size_to_units(gaim_xfer_get_size(xfer)); |
|
| 1045 remaining_str = gaim_str_size_to_units(gaim_xfer_get_bytes_remaining(xfer)); |
|
| 1046 |
|
| 1047 gtk_list_store_set(xfer_dialog->model, &data->iter, |
|
| 1048 COLUMN_PROGRESS, gaim_xfer_get_progress(xfer), |
|
| 1049 COLUMN_SIZE, size_str, |
|
| 1050 COLUMN_REMAINING, remaining_str, |
|
| 1051 -1); |
|
| 1052 |
|
| 1053 if (gaim_xfer_is_completed(xfer)) |
|
| 1054 { |
|
| 1055 GdkPixbuf *pixbuf; |
|
| 1056 |
|
| 1057 pixbuf = gtk_widget_render_icon(dialog->window, |
|
| 1058 GAIM_STOCK_FILE_DONE, |
|
| 1059 GTK_ICON_SIZE_MENU, NULL); |
|
| 1060 |
|
| 1061 gtk_list_store_set(GTK_LIST_STORE(xfer_dialog->model), &data->iter, |
|
| 1062 COLUMN_STATUS, pixbuf, |
|
| 1063 COLUMN_REMAINING, _("Finished"), |
|
| 1064 -1); |
|
| 1065 |
|
| 1066 g_object_unref(pixbuf); |
|
| 1067 } |
|
| 1068 |
|
| 1069 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(xfer_dialog->tree)); |
|
| 1070 |
|
| 1071 if (xfer == dialog->selected_xfer) |
|
| 1072 update_detailed_info(xfer_dialog, xfer); |
|
| 1073 |
|
| 1074 if (gaim_xfer_is_completed(xfer) && dialog->auto_clear) |
|
| 1075 gaim_gtkxfer_dialog_remove_xfer(dialog, xfer); |
|
| 1076 else |
|
| 1077 update_buttons(dialog, xfer); |
|
| 1078 } |
|
| 1079 |
|
| 1080 /************************************************************************** |
|
| 1081 * File Transfer UI Ops |
|
| 1082 **************************************************************************/ |
|
| 1083 static void |
|
| 1084 gaim_gtkxfer_new_xfer(GaimXfer *xfer) |
|
| 1085 { |
|
| 1086 GaimGtkXferUiData *data; |
|
| 1087 |
|
| 1088 /* This is where we're setting xfer->ui_data for the first time. */ |
|
| 1089 data = g_new0(GaimGtkXferUiData, 1); |
|
| 1090 xfer->ui_data = data; |
|
| 1091 } |
|
| 1092 |
|
| 1093 static void |
|
| 1094 gaim_gtkxfer_destroy(GaimXfer *xfer) |
|
| 1095 { |
|
| 1096 GaimGtkXferUiData *data; |
|
| 1097 |
|
| 1098 data = GAIM_GTKXFER(xfer); |
|
| 1099 if (data) { |
|
| 1100 if (data->name) |
|
| 1101 g_free(data->name); |
|
| 1102 g_free(data); |
|
| 1103 xfer->ui_data = NULL; |
|
| 1104 } |
|
| 1105 } |
|
| 1106 |
|
| 1107 static void |
|
| 1108 gaim_gtkxfer_add_xfer(GaimXfer *xfer) |
|
| 1109 { |
|
| 1110 if (xfer_dialog == NULL) |
|
| 1111 xfer_dialog = gaim_gtkxfer_dialog_new(); |
|
| 1112 |
|
| 1113 gaim_gtkxfer_dialog_add_xfer(xfer_dialog, xfer); |
|
| 1114 } |
|
| 1115 |
|
| 1116 static void |
|
| 1117 gaim_gtkxfer_update_progress(GaimXfer *xfer, double percent) |
|
| 1118 { |
|
| 1119 gaim_gtkxfer_dialog_update_xfer(xfer_dialog, xfer); |
|
| 1120 } |
|
| 1121 |
|
| 1122 static void |
|
| 1123 gaim_gtkxfer_cancel_local(GaimXfer *xfer) |
|
| 1124 { |
|
| 1125 if (xfer_dialog) |
|
| 1126 gaim_gtkxfer_dialog_cancel_xfer(xfer_dialog, xfer); |
|
| 1127 } |
|
| 1128 |
|
| 1129 static void |
|
| 1130 gaim_gtkxfer_cancel_remote(GaimXfer *xfer) |
|
| 1131 { |
|
| 1132 if (xfer_dialog) |
|
| 1133 gaim_gtkxfer_dialog_cancel_xfer(xfer_dialog, xfer); |
|
| 1134 } |
|
| 1135 |
|
| 1136 static GaimXferUiOps ops = |
|
| 1137 { |
|
| 1138 gaim_gtkxfer_new_xfer, |
|
| 1139 gaim_gtkxfer_destroy, |
|
| 1140 gaim_gtkxfer_add_xfer, |
|
| 1141 gaim_gtkxfer_update_progress, |
|
| 1142 gaim_gtkxfer_cancel_local, |
|
| 1143 gaim_gtkxfer_cancel_remote |
|
| 1144 }; |
|
| 1145 |
|
| 1146 /************************************************************************** |
|
| 1147 * GTK+ File Transfer API |
|
| 1148 **************************************************************************/ |
|
| 1149 void |
|
| 1150 gaim_gtk_xfers_init(void) |
|
| 1151 { |
|
| 1152 gaim_prefs_add_none("/gaim/gtk/filetransfer"); |
|
| 1153 gaim_prefs_add_bool("/gaim/gtk/filetransfer/clear_finished", TRUE); |
|
| 1154 gaim_prefs_add_bool("/gaim/gtk/filetransfer/keep_open", FALSE); |
|
| 1155 } |
|
| 1156 |
|
| 1157 void |
|
| 1158 gaim_gtk_xfers_uninit(void) |
|
| 1159 { |
|
| 1160 if (xfer_dialog != NULL) |
|
| 1161 gaim_gtkxfer_dialog_destroy(xfer_dialog); |
|
| 1162 } |
|
| 1163 |
|
| 1164 void |
|
| 1165 gaim_set_gtkxfer_dialog(GaimGtkXferDialog *dialog) |
|
| 1166 { |
|
| 1167 xfer_dialog = dialog; |
|
| 1168 } |
|
| 1169 |
|
| 1170 GaimGtkXferDialog * |
|
| 1171 gaim_get_gtkxfer_dialog(void) |
|
| 1172 { |
|
| 1173 return xfer_dialog; |
|
| 1174 } |
|
| 1175 |
|
| 1176 GaimXferUiOps * |
|
| 1177 gaim_gtk_xfers_get_ui_ops(void) |
|
| 1178 { |
|
| 1179 return &ops; |
|
| 1180 } |
|