2 * Copyright (C) 2003, 2004 Xan Lopez
3 * Copyright (C) 2007 Marco Barisione <marco@barisione.org>
4 * Copyright (C) 2008-2009 Collabora Ltd.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301 USA
22 * Marco Barisione <marco@barisione.org>
23 * Jonny Lamb <jonny.lamb@collabora.co.uk>
24 * Xavier Claessens <xclaesse@gmail.com>
25 * Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
28 /* The original file transfer manager code was copied from Epiphany */
34 #include <glib/gi18n.h>
37 #define DEBUG_FLAG EMPATHY_DEBUG_FT
38 #include <libempathy/empathy-debug.h>
39 #include <libempathy/empathy-tp-file.h>
40 #include <libempathy/empathy-utils.h>
42 #include <libempathy-gtk/empathy-conf.h>
43 #include <libempathy-gtk/empathy-ui-utils.h>
44 #include <libempathy-gtk/empathy-geometry.h>
45 #include <libempathy-gtk/empathy-images.h>
47 #include "empathy-ft-manager.h"
60 GHashTable *ft_handler_to_row_ref;
65 GtkWidget *open_button;
66 GtkWidget *abort_button;
67 GtkWidget *clear_button;
69 guint save_geometry_id;
70 } EmpathyFTManagerPriv;
79 G_DEFINE_TYPE (EmpathyFTManager, empathy_ft_manager, G_TYPE_OBJECT);
81 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyFTManager)
83 static EmpathyFTManager *manager_singleton = NULL;
85 static void ft_handler_hashing_started_cb (EmpathyFTHandler *handler,
86 EmpathyFTManager *manager);
89 ft_manager_format_interval (guint interval)
91 gint hours, mins, secs;
93 hours = interval / 3600;
94 interval -= hours * 3600;
96 interval -= mins * 60;
100 /* Translators: time left, when it is more than one hour */
101 return g_strdup_printf (_("%u:%02u.%02u"), hours, mins, secs);
103 /* Translators: time left, when is is less than one hour */
104 return g_strdup_printf (_("%02u.%02u"), mins, secs);
108 ft_manager_update_buttons (EmpathyFTManager *manager)
110 GtkTreeSelection *selection;
113 EmpathyFTHandler *handler;
114 gboolean open_enabled = FALSE;
115 gboolean abort_enabled = FALSE;
116 gboolean clear_enabled = FALSE;
117 gboolean is_completed, is_cancelled;
118 GHashTableIter hash_iter;
119 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
121 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
123 if (gtk_tree_selection_get_selected (selection, &model, &iter))
125 gtk_tree_model_get (model, &iter, COL_FT_OBJECT, &handler, -1);
127 is_completed = empathy_ft_handler_is_completed (handler);
128 is_cancelled = empathy_ft_handler_is_cancelled (handler);
130 /* I can open the file if the transfer is completed and was incoming */
131 open_enabled = (is_completed && empathy_ft_handler_is_incoming (handler));
133 /* I can abort if the transfer is not already finished */
134 abort_enabled = (is_cancelled == FALSE && is_completed == FALSE);
136 g_object_unref (handler);
139 g_hash_table_iter_init (&hash_iter, priv->ft_handler_to_row_ref);
141 while (g_hash_table_iter_next (&hash_iter, (gpointer *) &handler, NULL))
143 if (empathy_ft_handler_is_completed (handler) ||
144 empathy_ft_handler_is_cancelled (handler))
145 clear_enabled = TRUE;
151 gtk_widget_set_sensitive (priv->open_button, open_enabled);
152 gtk_widget_set_sensitive (priv->abort_button, abort_enabled);
155 gtk_widget_set_sensitive (priv->clear_button, TRUE);
159 ft_manager_selection_changed (GtkTreeSelection *selection,
160 EmpathyFTManager *manager)
162 ft_manager_update_buttons (manager);
166 ft_manager_progress_cell_data_func (GtkTreeViewColumn *col,
167 GtkCellRenderer *renderer,
172 const gchar *text = NULL;
175 gtk_tree_model_get (model, iter, COL_PERCENT, &percent, -1);
180 text = C_("file transfer percent", "Unknown");
183 g_object_set (renderer, "text", text, "value", percent, NULL);
186 static GtkTreeRowReference *
187 ft_manager_get_row_from_handler (EmpathyFTManager *manager,
188 EmpathyFTHandler *handler)
190 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
192 return g_hash_table_lookup (priv->ft_handler_to_row_ref, handler);
196 ft_manager_remove_file_from_model (EmpathyFTManager *manager,
197 EmpathyFTHandler *handler)
199 GtkTreeRowReference *row_ref;
200 GtkTreeSelection *selection;
201 GtkTreePath *path = NULL;
203 gboolean update_selection;
204 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
206 row_ref = ft_manager_get_row_from_handler (manager, handler);
207 g_return_if_fail (row_ref);
209 DEBUG ("Removing file transfer from window: contact=%s, filename=%s",
210 empathy_contact_get_name (empathy_ft_handler_get_contact (handler)),
211 empathy_ft_handler_get_filename (handler));
213 /* Get the iter from the row_ref */
214 path = gtk_tree_row_reference_get_path (row_ref);
215 gtk_tree_model_get_iter (priv->model, &iter, path);
216 gtk_tree_path_free (path);
218 /* We have to update the selection only if we are removing the selected row */
219 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
220 update_selection = gtk_tree_selection_iter_is_selected (selection, &iter);
222 /* Remove tp_file's row. After that iter points to the next row */
223 if (!gtk_list_store_remove (GTK_LIST_STORE (priv->model), &iter))
227 /* There is no next row, set iter to the last row */
228 n_row = gtk_tree_model_iter_n_children (priv->model, NULL);
230 gtk_tree_model_iter_nth_child (priv->model, &iter, NULL, n_row - 1);
232 update_selection = FALSE;
235 if (update_selection)
236 gtk_tree_selection_select_iter (selection, &iter);
240 remove_finished_transfer_foreach (gpointer key,
244 EmpathyFTHandler *handler = key;
245 EmpathyFTManager *manager = user_data;
247 if (empathy_ft_handler_is_completed (handler) ||
248 empathy_ft_handler_is_cancelled (handler))
250 ft_manager_remove_file_from_model (manager, handler);
258 ft_manager_format_progress_bytes_and_percentage (guint64 current,
263 char *total_str, *current_str, *retval;
264 char *speed_str = NULL;
266 total_str = g_format_size_for_display (total);
267 current_str = g_format_size_for_display (current);
270 speed_str = g_format_size_for_display ((goffset) speed);
272 /* translators: first %s is the currently processed size, second %s is
273 * the total file size */
275 g_strdup_printf (_("%s of %s at %s/s"), current_str, total_str, speed_str) :
276 g_strdup_printf (_("%s of %s"), current_str, total_str);
279 g_free (current_str);
282 if (percentage != NULL)
285 *percentage = current * 100 / total;
294 ft_manager_format_contact_info (EmpathyFTHandler *handler)
297 const char *filename, *contact_name, *first_line_format;
300 incoming = empathy_ft_handler_is_incoming (handler);
301 contact_name = empathy_contact_get_name
302 (empathy_ft_handler_get_contact (handler));
303 filename = empathy_ft_handler_get_filename (handler);
306 /* translators: first %s is filename, second %s is the contact name */
307 first_line_format = _("Receiving \"%s\" from %s");
309 /* translators: first %s is filename, second %s is the contact name */
310 first_line_format = _("Sending \"%s\" to %s");
312 retval = g_strdup_printf (first_line_format, filename, contact_name);
318 ft_manager_format_error_message (EmpathyFTHandler *handler,
321 const char *contact_name, *filename;
322 EmpathyContact *contact;
323 char *first_line, *message;
327 incoming = empathy_ft_handler_is_incoming (handler);
329 contact = empathy_ft_handler_get_contact (handler);
331 contact_name = empathy_contact_get_name (contact);
333 filename = empathy_ft_handler_get_filename (handler);
336 /* filename/contact_name here are either both NULL or both valid */
337 if (filename && contact_name)
338 /* translators: first %s is filename, second %s
339 * is the contact name */
340 first_line = g_strdup_printf (_("Error receiving \"%s\" from %s"), filename,
343 first_line = g_strdup (_("Error receiving a file"));
345 /* translators: first %s is filename, second %s
346 * is the contact name */
347 if (filename && contact_name)
348 first_line = g_strdup_printf (_("Error sending \"%s\" to %s"), filename,
351 first_line = g_strdup (_("Error sending a file"));
353 message = g_strdup_printf ("%s\n%s", first_line, error->message);
361 ft_manager_update_handler_message (EmpathyFTManager *manager,
362 GtkTreeRowReference *row_ref,
367 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
369 /* Set new value in the store */
370 path = gtk_tree_row_reference_get_path (row_ref);
371 gtk_tree_model_get_iter (priv->model, &iter, path);
372 gtk_list_store_set (GTK_LIST_STORE (priv->model),
374 COL_MESSAGE, message ? message : "",
377 gtk_tree_path_free (path);
381 ft_manager_update_handler_progress (EmpathyFTManager *manager,
382 GtkTreeRowReference *row_ref,
387 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
389 /* Set new value in the store */
390 path = gtk_tree_row_reference_get_path (row_ref);
391 gtk_tree_model_get_iter (priv->model, &iter, path);
392 gtk_list_store_set (GTK_LIST_STORE (priv->model),
394 COL_PERCENT, percentage,
397 gtk_tree_path_free (path);
402 ft_manager_update_handler_time (EmpathyFTManager *manager,
403 GtkTreeRowReference *row_ref,
404 guint remaining_time)
408 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
411 remaining_str = ft_manager_format_interval (remaining_time);
413 /* Set new value in the store */
414 path = gtk_tree_row_reference_get_path (row_ref);
415 gtk_tree_model_get_iter (priv->model, &iter, path);
416 gtk_list_store_set (GTK_LIST_STORE (priv->model),
418 COL_REMAINING, remaining_str,
421 gtk_tree_path_free (path);
422 g_free (remaining_str);
426 ft_manager_clear_handler_time (EmpathyFTManager *manager,
427 GtkTreeRowReference *row_ref)
431 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
433 /* Set new value in the store */
434 path = gtk_tree_row_reference_get_path (row_ref);
435 gtk_tree_model_get_iter (priv->model, &iter, path);
436 gtk_list_store_set (GTK_LIST_STORE (priv->model),
441 gtk_tree_path_free (path);
445 ft_handler_transfer_error_cb (EmpathyFTHandler *handler,
447 EmpathyFTManager *manager)
450 GtkTreeRowReference *row_ref;
452 DEBUG ("Transfer error %s", error->message);
454 row_ref = ft_manager_get_row_from_handler (manager, handler);
455 g_return_if_fail (row_ref != NULL);
457 message = ft_manager_format_error_message (handler, error);
459 ft_manager_update_handler_message (manager, row_ref, message);
460 ft_manager_clear_handler_time (manager, row_ref);
461 ft_manager_update_buttons (manager);
467 do_real_transfer_done (EmpathyFTManager *manager,
468 EmpathyFTHandler *handler)
470 const char *contact_name;
471 const char *filename;
472 char *first_line, *second_line, *message;
475 GtkTreeRowReference *row_ref;
476 GtkRecentManager *recent_manager;
479 row_ref = ft_manager_get_row_from_handler (manager, handler);
480 g_return_if_fail (row_ref != NULL);
482 incoming = empathy_ft_handler_is_incoming (handler);
483 contact_name = empathy_contact_get_name
484 (empathy_ft_handler_get_contact (handler));
485 filename = empathy_ft_handler_get_filename (handler);
488 /* translators: first %s is filename, second %s
489 * is the contact name */
490 first_line = g_strdup_printf (_("\"%s\" received from %s"), filename,
493 /* translators: first %s is filename, second %s
494 * is the contact name */
495 first_line = g_strdup_printf (_("\"%s\" sent to %s"), filename,
498 second_line = g_strdup (_("File transfer completed"));
500 message = g_strdup_printf ("%s\n%s", first_line, second_line);
501 ft_manager_update_handler_message (manager, row_ref, message);
502 ft_manager_clear_handler_time (manager, row_ref);
505 ft_manager_update_buttons (manager);
509 g_free (second_line);
511 recent_manager = gtk_recent_manager_get_default ();
512 file = empathy_ft_handler_get_gfile (handler);
513 uri = g_file_get_uri (file);
515 gtk_recent_manager_add_item (recent_manager, uri);
521 ft_handler_transfer_done_cb (EmpathyFTHandler *handler,
522 EmpathyTpFile *tp_file,
523 EmpathyFTManager *manager)
525 if (empathy_ft_handler_is_incoming (handler) &&
526 empathy_ft_handler_get_use_hash (handler))
528 DEBUG ("Transfer done, waiting for hashing-started");
530 /* connect to the signal and return early */
531 g_signal_connect (handler, "hashing-started",
532 G_CALLBACK (ft_handler_hashing_started_cb), manager);
537 DEBUG ("Transfer done, no hashing");
539 do_real_transfer_done (manager, handler);
543 ft_handler_transfer_progress_cb (EmpathyFTHandler *handler,
544 guint64 current_bytes,
546 guint remaining_time,
548 EmpathyFTManager *manager)
550 char *first_line, *second_line, *message;
552 GtkTreeRowReference *row_ref;
554 DEBUG ("Transfer progress");
556 row_ref = ft_manager_get_row_from_handler (manager, handler);
557 g_return_if_fail (row_ref != NULL);
559 first_line = ft_manager_format_contact_info (handler);
560 second_line = ft_manager_format_progress_bytes_and_percentage
561 (current_bytes, total_bytes, speed, &percentage);
563 message = g_strdup_printf ("%s\n%s", first_line, second_line);
565 ft_manager_update_handler_message (manager, row_ref, message);
566 ft_manager_update_handler_progress (manager, row_ref, percentage);
568 if (remaining_time > 0)
569 ft_manager_update_handler_time (manager, row_ref, remaining_time);
573 g_free (second_line);
577 ft_handler_transfer_started_cb (EmpathyFTHandler *handler,
578 EmpathyTpFile *tp_file,
579 EmpathyFTManager *manager)
581 guint64 transferred_bytes, total_bytes;
583 DEBUG ("Transfer started");
585 g_signal_connect (handler, "transfer-progress",
586 G_CALLBACK (ft_handler_transfer_progress_cb), manager);
587 g_signal_connect (handler, "transfer-done",
588 G_CALLBACK (ft_handler_transfer_done_cb), manager);
590 transferred_bytes = empathy_ft_handler_get_transferred_bytes (handler);
591 total_bytes = empathy_ft_handler_get_total_bytes (handler);
593 ft_handler_transfer_progress_cb (handler, transferred_bytes, total_bytes,
598 ft_handler_hashing_done_cb (EmpathyFTHandler *handler,
599 EmpathyFTManager *manager)
601 GtkTreeRowReference *row_ref;
602 char *first_line, *second_line, *message;
604 DEBUG ("Hashing done");
606 /* update the message */
607 if (empathy_ft_handler_is_incoming (handler))
609 do_real_transfer_done (manager, handler);
613 row_ref = ft_manager_get_row_from_handler (manager, handler);
614 g_return_if_fail (row_ref != NULL);
616 first_line = ft_manager_format_contact_info (handler);
617 second_line = g_strdup (_("Waiting for the other participant's response"));
618 message = g_strdup_printf ("%s\n%s", first_line, second_line);
620 ft_manager_update_handler_message (manager, row_ref, message);
624 g_free (second_line);
626 g_signal_connect (handler, "transfer-started",
627 G_CALLBACK (ft_handler_transfer_started_cb), manager);
631 ft_handler_hashing_progress_cb (EmpathyFTHandler *handler,
632 guint64 current_bytes,
634 EmpathyFTManager *manager)
636 char *first_line, *second_line, *message;
637 GtkTreeRowReference *row_ref;
639 row_ref = ft_manager_get_row_from_handler (manager, handler);
640 g_return_if_fail (row_ref != NULL);
642 if (empathy_ft_handler_is_incoming (handler))
643 first_line = g_strdup_printf (_("Checking integrity of \"%s\""),
644 empathy_ft_handler_get_filename (handler));
646 first_line = g_strdup_printf (_("Hashing \"%s\""),
647 empathy_ft_handler_get_filename (handler));
649 second_line = ft_manager_format_progress_bytes_and_percentage
650 (current_bytes, total_bytes, -1, NULL);
652 message = g_strdup_printf ("%s\n%s", first_line, second_line);
654 ft_manager_update_handler_message (manager, row_ref, message);
658 g_free (second_line);
662 ft_handler_hashing_started_cb (EmpathyFTHandler *handler,
663 EmpathyFTManager *manager)
665 char *message, *first_line, *second_line;
666 GtkTreeRowReference *row_ref;
668 DEBUG ("Hashing started");
670 g_signal_connect (handler, "hashing-progress",
671 G_CALLBACK (ft_handler_hashing_progress_cb), manager);
672 g_signal_connect (handler, "hashing-done",
673 G_CALLBACK (ft_handler_hashing_done_cb), manager);
675 row_ref = ft_manager_get_row_from_handler (manager, handler);
676 g_return_if_fail (row_ref != NULL);
678 first_line = ft_manager_format_contact_info (handler);
680 if (empathy_ft_handler_is_incoming (handler))
681 second_line = g_strdup_printf (_("Checking integrity of \"%s\""),
682 empathy_ft_handler_get_filename (handler));
684 second_line = g_strdup_printf (_("Hashing \"%s\""),
685 empathy_ft_handler_get_filename (handler));
687 message = g_strdup_printf ("%s\n%s", first_line, second_line);
689 ft_manager_update_handler_message (manager, row_ref, message);
692 g_free (second_line);
697 ft_manager_start_transfer (EmpathyFTManager *manager,
698 EmpathyFTHandler *handler)
700 EmpathyFTManagerPriv *priv;
701 gboolean is_outgoing;
703 priv = GET_PRIV (manager);
705 is_outgoing = !empathy_ft_handler_is_incoming (handler);
707 DEBUG ("Start transfer, is outgoing %s",
708 is_outgoing ? "True" : "False");
710 /* now connect the signals */
711 g_signal_connect (handler, "transfer-error",
712 G_CALLBACK (ft_handler_transfer_error_cb), manager);
714 if (is_outgoing && empathy_ft_handler_get_use_hash (handler)) {
715 g_signal_connect (handler, "hashing-started",
716 G_CALLBACK (ft_handler_hashing_started_cb), manager);
718 /* either incoming or outgoing without hash */
719 g_signal_connect (handler, "transfer-started",
720 G_CALLBACK (ft_handler_transfer_started_cb), manager);
723 empathy_ft_handler_start_transfer (handler);
727 ft_manager_add_handler_to_list (EmpathyFTManager *manager,
728 EmpathyFTHandler *handler,
731 GtkTreeRowReference *row_ref;
733 GtkTreeSelection *selection;
736 const char *content_type, *second_line;
737 char *first_line, *message;
738 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
742 /* get the icon name from the mime-type of the file. */
743 content_type = empathy_ft_handler_get_content_type (handler);
745 if (content_type != NULL)
746 icon = g_content_type_get_icon (content_type);
748 /* append the handler in the store */
749 gtk_list_store_insert_with_values (GTK_LIST_STORE (priv->model),
750 &iter, G_MAXINT, COL_FT_OBJECT, handler,
754 g_object_unref (icon);
756 /* insert the new row_ref in the hash table */
757 path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->model), &iter);
758 row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (priv->model), path);
759 gtk_tree_path_free (path);
760 g_hash_table_insert (priv->ft_handler_to_row_ref, g_object_ref (handler),
763 /* select the new row */
764 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
765 gtk_tree_selection_select_iter (selection, &iter);
769 message = ft_manager_format_error_message (handler, error);
770 ft_manager_update_handler_message (manager, row_ref, message);
776 /* update the row with the initial values.
777 * the only case where we postpone this is in case we're managing
778 * an outgoing+hashing transfer, as the hashing started signal will
779 * take care of updating the information.
781 if (empathy_ft_handler_is_incoming (handler) ||
782 !empathy_ft_handler_get_use_hash (handler)) {
783 first_line = ft_manager_format_contact_info (handler);
784 second_line = _("Waiting for the other participant's response");
785 message = g_strdup_printf ("%s\n%s", first_line, second_line);
787 ft_manager_update_handler_message (manager, row_ref, message);
793 /* hook up the signals and start the transfer */
794 ft_manager_start_transfer (manager, handler);
798 ft_manager_clear (EmpathyFTManager *manager)
800 EmpathyFTManagerPriv *priv;
802 DEBUG ("Clearing file transfer list");
804 priv = GET_PRIV (manager);
806 /* Remove completed and cancelled transfers */
807 g_hash_table_foreach_remove (priv->ft_handler_to_row_ref,
808 remove_finished_transfer_foreach, manager);
810 /* set the clear button back to insensitive */
811 gtk_widget_set_sensitive (priv->clear_button, FALSE);
815 ft_manager_open (EmpathyFTManager *manager)
817 GtkTreeSelection *selection;
820 EmpathyFTHandler *handler;
823 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
825 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
827 if (!gtk_tree_selection_get_selected (selection, &model, &iter))
830 gtk_tree_model_get (model, &iter, COL_FT_OBJECT, &handler, -1);
832 file = empathy_ft_handler_get_gfile (handler);
833 uri = g_file_get_uri (file);
835 DEBUG ("Opening URI: %s", uri);
836 empathy_url_show (GTK_WIDGET (priv->window), uri);
838 g_object_unref (handler);
843 ft_manager_stop (EmpathyFTManager *manager)
845 GtkTreeSelection *selection;
848 EmpathyFTHandler *handler;
849 EmpathyFTManagerPriv *priv;
851 priv = GET_PRIV (manager);
853 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
855 if (!gtk_tree_selection_get_selected (selection, &model, &iter))
858 gtk_tree_model_get (model, &iter, COL_FT_OBJECT, &handler, -1);
859 g_return_if_fail (handler != NULL);
861 DEBUG ("Stopping file transfer: contact=%s, filename=%s",
862 empathy_contact_get_name (empathy_ft_handler_get_contact (handler)),
863 empathy_ft_handler_get_filename (handler));
865 empathy_ft_handler_cancel_transfer (handler);
867 g_object_unref (handler);
871 ft_manager_save_geometry_timeout_cb (EmpathyFTManager *manager)
873 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
876 gtk_window_get_size (GTK_WINDOW (priv->window), &w, &h);
877 gtk_window_get_position (GTK_WINDOW (priv->window), &x, &y);
879 empathy_geometry_save ("ft-manager", x, y, w, h);
881 priv->save_geometry_id = 0;
887 ft_manager_configure_event_cb (GtkWidget *widget,
888 GdkEventConfigure *event,
889 EmpathyFTManager *manager)
891 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
893 if (priv->save_geometry_id != 0)
894 g_source_remove (priv->save_geometry_id);
896 priv->save_geometry_id = g_timeout_add (500,
897 (GSourceFunc) ft_manager_save_geometry_timeout_cb, manager);
903 ft_manager_response_cb (GtkWidget *widget,
905 EmpathyFTManager *manager)
910 ft_manager_clear (manager);
913 ft_manager_open (manager);
916 ft_manager_stop (manager);
922 ft_manager_delete_event_cb (GtkWidget *widget,
924 EmpathyFTManager *manager)
926 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
928 DEBUG ("%p", manager);
930 /* remove all the completed/cancelled/errored transfers */
931 ft_manager_clear (manager);
933 if (g_hash_table_size (priv->ft_handler_to_row_ref) > 0)
935 /* There is still FTs on flight, just hide the window */
936 DEBUG ("Hiding window");
937 gtk_widget_hide (widget);
945 ft_manager_destroy_cb (GtkWidget *widget,
946 EmpathyFTManager *manager)
948 DEBUG ("%p", manager);
950 g_object_unref (manager);
954 ft_manager_build_ui (EmpathyFTManager *manager)
959 GtkListStore *liststore;
960 GtkTreeViewColumn *column;
961 GtkCellRenderer *renderer;
962 GtkTreeSelection *selection;
964 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
966 filename = empathy_file_lookup ("empathy-ft-manager.ui", "src");
967 gui = empathy_builder_get_file (filename,
968 "ft_manager_dialog", &priv->window,
969 "ft_list", &priv->treeview,
970 "clear_button", &priv->clear_button,
971 "open_button", &priv->open_button,
972 "abort_button", &priv->abort_button,
976 empathy_builder_connect (gui, manager,
977 "ft_manager_dialog", "destroy", ft_manager_destroy_cb,
978 "ft_manager_dialog", "response", ft_manager_response_cb,
979 "ft_manager_dialog", "delete-event", ft_manager_delete_event_cb,
980 "ft_manager_dialog", "configure-event", ft_manager_configure_event_cb,
983 empathy_builder_unref_and_keep_widget (gui, priv->window);
985 /* Window geometry. */
986 empathy_geometry_load ("ft-manager", &x, &y, &w, &h);
988 if (x >= 0 && y >= 0)
990 /* Let the window manager position it if we don't have
991 * good x, y coordinates. */
992 gtk_window_move (GTK_WINDOW (priv->window), x, y);
997 /* Use the defaults from the ui file if we don't have
998 * good w, h geometry. */
999 gtk_window_resize (GTK_WINDOW (priv->window), w, h);
1002 /* Setup the tree view */
1003 view = GTK_TREE_VIEW (priv->treeview);
1004 selection = gtk_tree_view_get_selection (view);
1005 gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
1006 g_signal_connect (selection, "changed",
1007 G_CALLBACK (ft_manager_selection_changed), manager);
1008 gtk_tree_view_set_headers_visible (view, TRUE);
1009 gtk_tree_view_set_enable_search (view, FALSE);
1011 /* Setup the model */
1012 liststore = gtk_list_store_new (5,
1013 G_TYPE_INT, /* percent */
1014 G_TYPE_ICON, /* icon */
1015 G_TYPE_STRING, /* message */
1016 G_TYPE_STRING, /* remaining */
1017 G_TYPE_OBJECT); /* ft_handler */
1018 gtk_tree_view_set_model (view, GTK_TREE_MODEL (liststore));
1019 priv->model = GTK_TREE_MODEL (liststore);
1020 g_object_unref (liststore);
1022 /* Progress column */
1023 column = gtk_tree_view_column_new ();
1024 gtk_tree_view_column_set_title (column, _("%"));
1025 gtk_tree_view_column_set_sort_column_id (column, COL_PERCENT);
1026 gtk_tree_view_insert_column (view, column, -1);
1028 renderer = gtk_cell_renderer_progress_new ();
1029 g_object_set (renderer, "xalign", 0.5, NULL);
1030 gtk_tree_view_column_pack_start (column, renderer, FALSE);
1031 gtk_tree_view_column_set_cell_data_func (column, renderer,
1032 ft_manager_progress_cell_data_func, NULL, NULL);
1034 /* Icon and filename column*/
1035 column = gtk_tree_view_column_new ();
1036 gtk_tree_view_column_set_title (column, _("File"));
1037 gtk_tree_view_column_set_expand (column, TRUE);
1038 gtk_tree_view_column_set_resizable (column, TRUE);
1039 gtk_tree_view_column_set_sort_column_id (column, COL_MESSAGE);
1040 gtk_tree_view_column_set_spacing (column, 3);
1041 gtk_tree_view_insert_column (view, column, -1);
1043 renderer = gtk_cell_renderer_pixbuf_new ();
1044 g_object_set (renderer, "xpad", 3,
1045 "stock-size", GTK_ICON_SIZE_DND, NULL);
1046 gtk_tree_view_column_pack_start (column, renderer, FALSE);
1047 gtk_tree_view_column_set_attributes (column, renderer,
1048 "gicon", COL_ICON, NULL);
1050 renderer = gtk_cell_renderer_text_new ();
1051 g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
1052 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1053 gtk_tree_view_column_set_attributes (column, renderer,
1054 "text", COL_MESSAGE, NULL);
1056 /* Remaining time column */
1057 column = gtk_tree_view_column_new ();
1058 gtk_tree_view_column_set_title (column, _("Remaining"));
1059 gtk_tree_view_column_set_sort_column_id (column, COL_REMAINING);
1060 gtk_tree_view_insert_column (view, column, -1);
1062 renderer = gtk_cell_renderer_text_new ();
1063 g_object_set (renderer, "xalign", 0.5, NULL);
1064 gtk_tree_view_column_pack_start (column, renderer, FALSE);
1065 gtk_tree_view_column_set_attributes (column, renderer,
1066 "text", COL_REMAINING, NULL);
1068 /* clear button should be sensitive only if there are completed/cancelled
1069 * handlers in the store.
1071 gtk_widget_set_sensitive (priv->clear_button, FALSE);
1074 /* GObject method overrides */
1077 empathy_ft_manager_finalize (GObject *object)
1079 EmpathyFTManagerPriv *priv = GET_PRIV (object);
1081 DEBUG ("FT Manager %p", object);
1083 g_hash_table_destroy (priv->ft_handler_to_row_ref);
1085 if (priv->save_geometry_id != 0)
1086 g_source_remove (priv->save_geometry_id);
1088 G_OBJECT_CLASS (empathy_ft_manager_parent_class)->finalize (object);
1092 empathy_ft_manager_init (EmpathyFTManager *manager)
1094 EmpathyFTManagerPriv *priv;
1096 priv = G_TYPE_INSTANCE_GET_PRIVATE ((manager), EMPATHY_TYPE_FT_MANAGER,
1097 EmpathyFTManagerPriv);
1099 manager->priv = priv;
1101 priv->ft_handler_to_row_ref = g_hash_table_new_full (g_direct_hash,
1102 g_direct_equal, (GDestroyNotify) g_object_unref,
1103 (GDestroyNotify) gtk_tree_row_reference_free);
1105 ft_manager_build_ui (manager);
1109 empathy_ft_manager_constructor (GType type,
1111 GObjectConstructParam *props)
1115 if (manager_singleton)
1117 retval = G_OBJECT (manager_singleton);
1121 retval = G_OBJECT_CLASS (empathy_ft_manager_parent_class)->constructor
1122 (type, n_props, props);
1124 manager_singleton = EMPATHY_FT_MANAGER (retval);
1125 g_object_add_weak_pointer (retval, (gpointer) &manager_singleton);
1132 empathy_ft_manager_class_init (EmpathyFTManagerClass *klass)
1134 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1136 object_class->finalize = empathy_ft_manager_finalize;
1137 object_class->constructor = empathy_ft_manager_constructor;
1139 g_type_class_add_private (object_class, sizeof (EmpathyFTManagerPriv));
1142 /* public methods */
1145 empathy_ft_manager_add_handler (EmpathyFTHandler *handler)
1147 EmpathyFTManager *manager;
1148 EmpathyFTManagerPriv *priv;
1150 DEBUG ("Adding handler");
1152 g_return_if_fail (EMPATHY_IS_FT_HANDLER (handler));
1154 manager = g_object_new (EMPATHY_TYPE_FT_MANAGER, NULL);
1155 priv = GET_PRIV (manager);
1157 ft_manager_add_handler_to_list (manager, handler, NULL);
1158 gtk_window_present (GTK_WINDOW (priv->window));
1162 empathy_ft_manager_display_error (EmpathyFTHandler *handler,
1163 const GError *error)
1165 EmpathyFTManager *manager;
1166 EmpathyFTManagerPriv *priv;
1168 g_return_if_fail (EMPATHY_IS_FT_HANDLER (handler));
1169 g_return_if_fail (error != NULL);
1171 manager = g_object_new (EMPATHY_TYPE_FT_MANAGER, NULL);
1172 priv = GET_PRIV (manager);
1174 ft_manager_add_handler_to_list (manager, handler, error);
1175 gtk_window_present (GTK_WINDOW (priv->window));
1179 empathy_ft_manager_show (void)
1181 EmpathyFTManager *manager;
1182 EmpathyFTManagerPriv *priv;
1184 manager = g_object_new (EMPATHY_TYPE_FT_MANAGER, NULL);
1185 priv = GET_PRIV (manager);
1187 gtk_window_present (GTK_WINDOW (priv->window));