LogWindow: better logic for the buttons sensitivity
[empathy-mirror.git] / src / empathy-ft-manager.c
blobe23b0b45a31c69840b69faffde2a84d5cec57e80
1 /*
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
21 * Authors: Xan Lopez
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 */
30 #include "config.h"
32 #include <string.h>
34 #include <glib/gi18n.h>
35 #include <gtk/gtk.h>
36 #include <gdk/gdkkeysyms.h>
38 #define DEBUG_FLAG EMPATHY_DEBUG_FT
39 #include <libempathy/empathy-debug.h>
40 #include <libempathy/empathy-tp-file.h>
41 #include <libempathy/empathy-utils.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"
49 enum
51 COL_PERCENT,
52 COL_ICON,
53 COL_MESSAGE,
54 COL_REMAINING,
55 COL_FT_OBJECT
58 typedef struct {
59 GtkTreeModel *model;
60 GHashTable *ft_handler_to_row_ref;
62 /* Widgets */
63 GtkWidget *window;
64 GtkWidget *treeview;
65 GtkWidget *open_button;
66 GtkWidget *abort_button;
67 GtkWidget *clear_button;
68 } EmpathyFTManagerPriv;
70 enum
72 RESPONSE_OPEN = 1,
73 RESPONSE_STOP = 2,
74 RESPONSE_CLEAR = 3,
75 RESPONSE_CLOSE = 4
78 G_DEFINE_TYPE (EmpathyFTManager, empathy_ft_manager, G_TYPE_OBJECT);
80 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyFTManager)
82 static EmpathyFTManager *manager_singleton = NULL;
84 static void ft_handler_hashing_started_cb (EmpathyFTHandler *handler,
85 EmpathyFTManager *manager);
87 static gchar *
88 ft_manager_format_interval (guint interval)
90 gint hours, mins, secs;
92 hours = interval / 3600;
93 interval -= hours * 3600;
94 mins = interval / 60;
95 interval -= mins * 60;
96 secs = interval;
98 if (hours > 0)
99 /* Translators: time left, when it is more than one hour */
100 return g_strdup_printf (_("%u:%02u.%02u"), hours, mins, secs);
101 else
102 /* Translators: time left, when is is less than one hour */
103 return g_strdup_printf (_("%02u.%02u"), mins, secs);
106 static void
107 ft_manager_update_buttons (EmpathyFTManager *manager)
109 GtkTreeSelection *selection;
110 GtkTreeModel *model;
111 GtkTreeIter iter;
112 EmpathyFTHandler *handler;
113 gboolean open_enabled = FALSE;
114 gboolean abort_enabled = FALSE;
115 gboolean clear_enabled = FALSE;
116 gboolean is_completed, is_cancelled;
117 GHashTableIter hash_iter;
118 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
120 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
122 if (gtk_tree_selection_get_selected (selection, &model, &iter))
124 gtk_tree_model_get (model, &iter, COL_FT_OBJECT, &handler, -1);
126 is_completed = empathy_ft_handler_is_completed (handler);
127 is_cancelled = empathy_ft_handler_is_cancelled (handler);
129 /* I can open the file if the transfer is completed and was incoming */
130 open_enabled = (is_completed && empathy_ft_handler_is_incoming (handler));
132 /* I can abort if the transfer is not already finished */
133 abort_enabled = (is_cancelled == FALSE && is_completed == FALSE);
135 g_object_unref (handler);
138 g_hash_table_iter_init (&hash_iter, priv->ft_handler_to_row_ref);
140 while (g_hash_table_iter_next (&hash_iter, (gpointer *) &handler, NULL))
142 if (empathy_ft_handler_is_completed (handler) ||
143 empathy_ft_handler_is_cancelled (handler))
144 clear_enabled = TRUE;
146 if (clear_enabled)
147 break;
150 gtk_widget_set_sensitive (priv->open_button, open_enabled);
151 gtk_widget_set_sensitive (priv->abort_button, abort_enabled);
153 if (clear_enabled)
154 gtk_widget_set_sensitive (priv->clear_button, TRUE);
157 static void
158 ft_manager_selection_changed (GtkTreeSelection *selection,
159 EmpathyFTManager *manager)
161 ft_manager_update_buttons (manager);
164 static void
165 ft_manager_progress_cell_data_func (GtkTreeViewColumn *col,
166 GtkCellRenderer *renderer,
167 GtkTreeModel *model,
168 GtkTreeIter *iter,
169 gpointer user_data)
171 const gchar *text = NULL;
172 gint percent;
174 gtk_tree_model_get (model, iter, COL_PERCENT, &percent, -1);
176 if (percent < 0)
178 percent = 0;
179 text = C_("file transfer percent", "Unknown");
182 g_object_set (renderer, "text", text, "value", percent, NULL);
185 static GtkTreeRowReference *
186 ft_manager_get_row_from_handler (EmpathyFTManager *manager,
187 EmpathyFTHandler *handler)
189 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
191 return g_hash_table_lookup (priv->ft_handler_to_row_ref, handler);
194 static void
195 ft_manager_remove_file_from_model (EmpathyFTManager *manager,
196 EmpathyFTHandler *handler)
198 GtkTreeRowReference *row_ref;
199 GtkTreeSelection *selection;
200 GtkTreePath *path = NULL;
201 GtkTreeIter iter;
202 gboolean update_selection;
203 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
205 row_ref = ft_manager_get_row_from_handler (manager, handler);
206 g_return_if_fail (row_ref);
208 DEBUG ("Removing file transfer from window: contact=%s, filename=%s",
209 empathy_contact_get_alias (empathy_ft_handler_get_contact (handler)),
210 empathy_ft_handler_get_filename (handler));
212 /* Get the iter from the row_ref */
213 path = gtk_tree_row_reference_get_path (row_ref);
214 gtk_tree_model_get_iter (priv->model, &iter, path);
215 gtk_tree_path_free (path);
217 /* We have to update the selection only if we are removing the selected row */
218 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
219 update_selection = gtk_tree_selection_iter_is_selected (selection, &iter);
221 /* Remove tp_file's row. After that iter points to the next row */
222 if (!gtk_list_store_remove (GTK_LIST_STORE (priv->model), &iter))
224 gint n_row;
226 /* There is no next row, set iter to the last row */
227 n_row = gtk_tree_model_iter_n_children (priv->model, NULL);
228 if (n_row > 0)
229 gtk_tree_model_iter_nth_child (priv->model, &iter, NULL, n_row - 1);
230 else
231 update_selection = FALSE;
234 if (update_selection)
235 gtk_tree_selection_select_iter (selection, &iter);
238 static gboolean
239 remove_finished_transfer_foreach (gpointer key,
240 gpointer value,
241 gpointer user_data)
243 EmpathyFTHandler *handler = key;
244 EmpathyFTManager *manager = user_data;
246 if (empathy_ft_handler_is_completed (handler) ||
247 empathy_ft_handler_is_cancelled (handler))
249 ft_manager_remove_file_from_model (manager, handler);
250 return TRUE;
253 return FALSE;
256 static gchar *
257 ft_manager_format_progress_bytes_and_percentage (guint64 current,
258 guint64 total,
259 gdouble speed,
260 int *percentage)
262 char *total_str, *current_str, *retval;
263 char *speed_str = NULL;
265 total_str = g_format_size_for_display (total);
266 current_str = g_format_size_for_display (current);
268 if (speed > 0)
269 speed_str = g_format_size_for_display ((goffset) speed);
271 /* translators: first %s is the currently processed size, second %s is
272 * the total file size */
273 retval = speed_str ?
274 g_strdup_printf (_("%s of %s at %s/s"), current_str, total_str, speed_str) :
275 g_strdup_printf (_("%s of %s"), current_str, total_str);
277 g_free (total_str);
278 g_free (current_str);
279 g_free (speed_str);
281 if (percentage != NULL)
283 if (total != 0)
284 *percentage = current * 100 / total;
285 else
286 *percentage = -1;
289 return retval;
292 static gchar *
293 ft_manager_format_contact_info (EmpathyFTHandler *handler)
295 gboolean incoming;
296 const char *filename, *contact_name, *first_line_format;
297 char *retval;
299 incoming = empathy_ft_handler_is_incoming (handler);
300 contact_name = empathy_contact_get_alias
301 (empathy_ft_handler_get_contact (handler));
302 filename = empathy_ft_handler_get_filename (handler);
304 if (incoming)
305 /* translators: first %s is filename, second %s is the contact name */
306 first_line_format = _("Receiving \"%s\" from %s");
307 else
308 /* translators: first %s is filename, second %s is the contact name */
309 first_line_format = _("Sending \"%s\" to %s");
311 retval = g_strdup_printf (first_line_format, filename, contact_name);
313 return retval;
316 static gchar *
317 ft_manager_format_error_message (EmpathyFTHandler *handler,
318 const GError *error)
320 const char *contact_name, *filename;
321 EmpathyContact *contact;
322 char *first_line, *message;
323 gboolean incoming;
325 contact_name = NULL;
326 incoming = empathy_ft_handler_is_incoming (handler);
328 contact = empathy_ft_handler_get_contact (handler);
329 if (contact)
330 contact_name = empathy_contact_get_alias (contact);
332 filename = empathy_ft_handler_get_filename (handler);
334 if (incoming)
335 /* filename/contact_name here are either both NULL or both valid */
336 if (filename && contact_name)
337 /* translators: first %s is filename, second %s
338 * is the contact name */
339 first_line = g_strdup_printf (_("Error receiving \"%s\" from %s"), filename,
340 contact_name);
341 else
342 first_line = g_strdup (_("Error receiving a file"));
343 else
344 /* translators: first %s is filename, second %s
345 * is the contact name */
346 if (filename && contact_name)
347 first_line = g_strdup_printf (_("Error sending \"%s\" to %s"), filename,
348 contact_name);
349 else
350 first_line = g_strdup (_("Error sending a file"));
352 message = g_strdup_printf ("%s\n%s", first_line, error->message);
354 g_free (first_line);
356 return message;
359 static void
360 ft_manager_update_handler_message (EmpathyFTManager *manager,
361 GtkTreeRowReference *row_ref,
362 const char *message)
364 GtkTreePath *path;
365 GtkTreeIter iter;
366 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
368 /* Set new value in the store */
369 path = gtk_tree_row_reference_get_path (row_ref);
370 gtk_tree_model_get_iter (priv->model, &iter, path);
371 gtk_list_store_set (GTK_LIST_STORE (priv->model),
372 &iter,
373 COL_MESSAGE, message ? message : "",
374 -1);
376 gtk_tree_path_free (path);
379 static void
380 ft_manager_update_handler_progress (EmpathyFTManager *manager,
381 GtkTreeRowReference *row_ref,
382 int percentage)
384 GtkTreePath *path;
385 GtkTreeIter iter;
386 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
388 /* Set new value in the store */
389 path = gtk_tree_row_reference_get_path (row_ref);
390 gtk_tree_model_get_iter (priv->model, &iter, path);
391 gtk_list_store_set (GTK_LIST_STORE (priv->model),
392 &iter,
393 COL_PERCENT, percentage,
394 -1);
396 gtk_tree_path_free (path);
400 static void
401 ft_manager_update_handler_time (EmpathyFTManager *manager,
402 GtkTreeRowReference *row_ref,
403 guint remaining_time)
405 GtkTreePath *path;
406 GtkTreeIter iter;
407 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
408 char *remaining_str;
410 remaining_str = ft_manager_format_interval (remaining_time);
412 /* Set new value in the store */
413 path = gtk_tree_row_reference_get_path (row_ref);
414 gtk_tree_model_get_iter (priv->model, &iter, path);
415 gtk_list_store_set (GTK_LIST_STORE (priv->model),
416 &iter,
417 COL_REMAINING, remaining_str,
418 -1);
420 gtk_tree_path_free (path);
421 g_free (remaining_str);
424 static void
425 ft_manager_clear_handler_time (EmpathyFTManager *manager,
426 GtkTreeRowReference *row_ref)
428 GtkTreePath *path;
429 GtkTreeIter iter;
430 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
432 /* Set new value in the store */
433 path = gtk_tree_row_reference_get_path (row_ref);
434 gtk_tree_model_get_iter (priv->model, &iter, path);
435 gtk_list_store_set (GTK_LIST_STORE (priv->model),
436 &iter,
437 COL_REMAINING, NULL,
438 -1);
440 gtk_tree_path_free (path);
443 static void
444 ft_handler_transfer_error_cb (EmpathyFTHandler *handler,
445 GError *error,
446 EmpathyFTManager *manager)
448 char *message;
449 GtkTreeRowReference *row_ref;
451 DEBUG ("Transfer error %s", error->message);
453 row_ref = ft_manager_get_row_from_handler (manager, handler);
454 g_return_if_fail (row_ref != NULL);
456 message = ft_manager_format_error_message (handler, error);
458 ft_manager_update_handler_message (manager, row_ref, message);
459 ft_manager_clear_handler_time (manager, row_ref);
460 ft_manager_update_buttons (manager);
462 g_free (message);
465 static void
466 do_real_transfer_done (EmpathyFTManager *manager,
467 EmpathyFTHandler *handler)
469 const char *contact_name;
470 const char *filename;
471 char *first_line, *second_line, *message;
472 char *uri;
473 gboolean incoming;
474 GtkTreeRowReference *row_ref;
475 GtkRecentManager *recent_manager;
476 GFile *file;
478 row_ref = ft_manager_get_row_from_handler (manager, handler);
479 g_return_if_fail (row_ref != NULL);
481 incoming = empathy_ft_handler_is_incoming (handler);
482 contact_name = empathy_contact_get_alias
483 (empathy_ft_handler_get_contact (handler));
484 filename = empathy_ft_handler_get_filename (handler);
486 if (incoming)
487 /* translators: first %s is filename, second %s
488 * is the contact name */
489 first_line = g_strdup_printf (_("\"%s\" received from %s"), filename,
490 contact_name);
491 else
492 /* translators: first %s is filename, second %s
493 * is the contact name */
494 first_line = g_strdup_printf (_("\"%s\" sent to %s"), filename,
495 contact_name);
497 second_line = g_strdup (_("File transfer completed"));
499 message = g_strdup_printf ("%s\n%s", first_line, second_line);
500 ft_manager_update_handler_message (manager, row_ref, message);
501 ft_manager_clear_handler_time (manager, row_ref);
503 /* update buttons */
504 ft_manager_update_buttons (manager);
506 g_free (message);
507 g_free (first_line);
508 g_free (second_line);
510 recent_manager = gtk_recent_manager_get_default ();
511 file = empathy_ft_handler_get_gfile (handler);
512 uri = g_file_get_uri (file);
514 gtk_recent_manager_add_item (recent_manager, uri);
516 g_free (uri);
519 static void
520 ft_handler_transfer_done_cb (EmpathyFTHandler *handler,
521 EmpathyTpFile *tp_file,
522 EmpathyFTManager *manager)
524 if (empathy_ft_handler_is_incoming (handler) &&
525 empathy_ft_handler_get_use_hash (handler))
527 DEBUG ("Transfer done, waiting for hashing-started");
529 /* connect to the signal and return early */
530 g_signal_connect (handler, "hashing-started",
531 G_CALLBACK (ft_handler_hashing_started_cb), manager);
533 return;
536 DEBUG ("Transfer done, no hashing");
538 do_real_transfer_done (manager, handler);
541 static void
542 ft_handler_transfer_progress_cb (EmpathyFTHandler *handler,
543 guint64 current_bytes,
544 guint64 total_bytes,
545 guint remaining_time,
546 gdouble speed,
547 EmpathyFTManager *manager)
549 char *first_line, *second_line, *message;
550 int percentage;
551 GtkTreeRowReference *row_ref;
553 DEBUG ("Transfer progress");
555 row_ref = ft_manager_get_row_from_handler (manager, handler);
556 g_return_if_fail (row_ref != NULL);
558 first_line = ft_manager_format_contact_info (handler);
559 second_line = ft_manager_format_progress_bytes_and_percentage
560 (current_bytes, total_bytes, speed, &percentage);
562 message = g_strdup_printf ("%s\n%s", first_line, second_line);
564 ft_manager_update_handler_message (manager, row_ref, message);
565 ft_manager_update_handler_progress (manager, row_ref, percentage);
567 if (remaining_time > 0)
568 ft_manager_update_handler_time (manager, row_ref, remaining_time);
570 g_free (message);
571 g_free (first_line);
572 g_free (second_line);
575 static void
576 ft_handler_transfer_started_cb (EmpathyFTHandler *handler,
577 EmpathyTpFile *tp_file,
578 EmpathyFTManager *manager)
580 guint64 transferred_bytes, total_bytes;
582 DEBUG ("Transfer started");
584 g_signal_connect (handler, "transfer-progress",
585 G_CALLBACK (ft_handler_transfer_progress_cb), manager);
586 g_signal_connect (handler, "transfer-done",
587 G_CALLBACK (ft_handler_transfer_done_cb), manager);
589 transferred_bytes = empathy_ft_handler_get_transferred_bytes (handler);
590 total_bytes = empathy_ft_handler_get_total_bytes (handler);
592 ft_handler_transfer_progress_cb (handler, transferred_bytes, total_bytes,
593 0, -1, manager);
596 static void
597 ft_handler_hashing_done_cb (EmpathyFTHandler *handler,
598 EmpathyFTManager *manager)
600 GtkTreeRowReference *row_ref;
601 char *first_line, *second_line, *message;
603 DEBUG ("Hashing done");
605 /* update the message */
606 if (empathy_ft_handler_is_incoming (handler))
608 do_real_transfer_done (manager, handler);
609 return;
612 row_ref = ft_manager_get_row_from_handler (manager, handler);
613 g_return_if_fail (row_ref != NULL);
615 first_line = ft_manager_format_contact_info (handler);
616 second_line = g_strdup (_("Waiting for the other participant's response"));
617 message = g_strdup_printf ("%s\n%s", first_line, second_line);
619 ft_manager_update_handler_message (manager, row_ref, message);
621 g_free (message);
622 g_free (first_line);
623 g_free (second_line);
625 g_signal_connect (handler, "transfer-started",
626 G_CALLBACK (ft_handler_transfer_started_cb), manager);
629 static void
630 ft_handler_hashing_progress_cb (EmpathyFTHandler *handler,
631 guint64 current_bytes,
632 guint64 total_bytes,
633 EmpathyFTManager *manager)
635 char *first_line, *second_line, *message;
636 GtkTreeRowReference *row_ref;
638 row_ref = ft_manager_get_row_from_handler (manager, handler);
639 g_return_if_fail (row_ref != NULL);
641 if (empathy_ft_handler_is_incoming (handler))
642 first_line = g_strdup_printf (_("Checking integrity of \"%s\""),
643 empathy_ft_handler_get_filename (handler));
644 else
645 first_line = g_strdup_printf (_("Hashing \"%s\""),
646 empathy_ft_handler_get_filename (handler));
648 second_line = ft_manager_format_progress_bytes_and_percentage
649 (current_bytes, total_bytes, -1, NULL);
651 message = g_strdup_printf ("%s\n%s", first_line, second_line);
653 ft_manager_update_handler_message (manager, row_ref, message);
655 g_free (message);
656 g_free (first_line);
657 g_free (second_line);
660 static void
661 ft_handler_hashing_started_cb (EmpathyFTHandler *handler,
662 EmpathyFTManager *manager)
664 char *message, *first_line, *second_line;
665 GtkTreeRowReference *row_ref;
667 DEBUG ("Hashing started");
669 g_signal_connect (handler, "hashing-progress",
670 G_CALLBACK (ft_handler_hashing_progress_cb), manager);
671 g_signal_connect (handler, "hashing-done",
672 G_CALLBACK (ft_handler_hashing_done_cb), manager);
674 row_ref = ft_manager_get_row_from_handler (manager, handler);
675 g_return_if_fail (row_ref != NULL);
677 first_line = ft_manager_format_contact_info (handler);
679 if (empathy_ft_handler_is_incoming (handler))
680 second_line = g_strdup_printf (_("Checking integrity of \"%s\""),
681 empathy_ft_handler_get_filename (handler));
682 else
683 second_line = g_strdup_printf (_("Hashing \"%s\""),
684 empathy_ft_handler_get_filename (handler));
686 message = g_strdup_printf ("%s\n%s", first_line, second_line);
688 ft_manager_update_handler_message (manager, row_ref, message);
690 g_free (first_line);
691 g_free (second_line);
692 g_free (message);
695 static void
696 ft_manager_start_transfer (EmpathyFTManager *manager,
697 EmpathyFTHandler *handler)
699 gboolean is_outgoing;
701 is_outgoing = !empathy_ft_handler_is_incoming (handler);
703 DEBUG ("Start transfer, is outgoing %s",
704 is_outgoing ? "True" : "False");
706 /* now connect the signals */
707 g_signal_connect (handler, "transfer-error",
708 G_CALLBACK (ft_handler_transfer_error_cb), manager);
710 if (is_outgoing && empathy_ft_handler_get_use_hash (handler)) {
711 g_signal_connect (handler, "hashing-started",
712 G_CALLBACK (ft_handler_hashing_started_cb), manager);
713 } else {
714 /* either incoming or outgoing without hash */
715 g_signal_connect (handler, "transfer-started",
716 G_CALLBACK (ft_handler_transfer_started_cb), manager);
719 empathy_ft_handler_start_transfer (handler);
722 static void
723 ft_manager_add_handler_to_list (EmpathyFTManager *manager,
724 EmpathyFTHandler *handler,
725 const GError *error)
727 GtkTreeRowReference *row_ref;
728 GtkTreeIter iter;
729 GtkTreeSelection *selection;
730 GtkTreePath *path;
731 GIcon *icon;
732 const char *content_type, *second_line;
733 char *first_line, *message;
734 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
736 icon = NULL;
738 /* get the icon name from the mime-type of the file. */
739 content_type = empathy_ft_handler_get_content_type (handler);
741 if (content_type != NULL)
742 icon = g_content_type_get_icon (content_type);
744 /* append the handler in the store */
745 gtk_list_store_insert_with_values (GTK_LIST_STORE (priv->model),
746 &iter, G_MAXINT, COL_FT_OBJECT, handler,
747 COL_ICON, icon, -1);
749 if (icon != NULL)
750 g_object_unref (icon);
752 /* insert the new row_ref in the hash table */
753 path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->model), &iter);
754 row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (priv->model), path);
755 gtk_tree_path_free (path);
756 g_hash_table_insert (priv->ft_handler_to_row_ref, g_object_ref (handler),
757 row_ref);
759 /* select the new row */
760 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
761 gtk_tree_selection_select_iter (selection, &iter);
763 if (error != NULL)
765 message = ft_manager_format_error_message (handler, error);
766 ft_manager_update_handler_message (manager, row_ref, message);
768 g_free (message);
769 return;
772 /* update the row with the initial values.
773 * the only case where we postpone this is in case we're managing
774 * an outgoing+hashing transfer, as the hashing started signal will
775 * take care of updating the information.
777 if (empathy_ft_handler_is_incoming (handler) ||
778 !empathy_ft_handler_get_use_hash (handler)) {
779 first_line = ft_manager_format_contact_info (handler);
780 second_line = _("Waiting for the other participant's response");
781 message = g_strdup_printf ("%s\n%s", first_line, second_line);
783 ft_manager_update_handler_message (manager, row_ref, message);
785 g_free (first_line);
786 g_free (message);
789 /* hook up the signals and start the transfer */
790 ft_manager_start_transfer (manager, handler);
793 static void
794 ft_manager_clear (EmpathyFTManager *manager)
796 EmpathyFTManagerPriv *priv;
798 DEBUG ("Clearing file transfer list");
800 priv = GET_PRIV (manager);
802 /* Remove completed and cancelled transfers */
803 g_hash_table_foreach_remove (priv->ft_handler_to_row_ref,
804 remove_finished_transfer_foreach, manager);
806 /* set the clear button back to insensitive */
807 gtk_widget_set_sensitive (priv->clear_button, FALSE);
810 static void
811 ft_manager_open (EmpathyFTManager *manager)
813 GtkTreeSelection *selection;
814 GtkTreeIter iter;
815 GtkTreeModel *model;
816 EmpathyFTHandler *handler;
817 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
819 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
821 if (!gtk_tree_selection_get_selected (selection, &model, &iter))
822 return;
824 gtk_tree_model_get (model, &iter, COL_FT_OBJECT, &handler, -1);
826 if (empathy_ft_handler_is_completed (handler)){
827 char *uri;
828 GFile *file;
830 file = empathy_ft_handler_get_gfile (handler);
831 uri = g_file_get_uri (file);
833 DEBUG ("Opening URI: %s", uri);
834 empathy_url_show (GTK_WIDGET (priv->window), uri);
835 g_free (uri);
838 g_object_unref (handler);
841 static void
842 ft_manager_stop (EmpathyFTManager *manager)
844 GtkTreeSelection *selection;
845 GtkTreeIter iter;
846 GtkTreeModel *model;
847 EmpathyFTHandler *handler;
848 EmpathyFTManagerPriv *priv;
850 priv = GET_PRIV (manager);
852 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
854 if (!gtk_tree_selection_get_selected (selection, &model, &iter))
855 return;
857 gtk_tree_model_get (model, &iter, COL_FT_OBJECT, &handler, -1);
858 g_return_if_fail (handler != NULL);
860 DEBUG ("Stopping file transfer: contact=%s, filename=%s",
861 empathy_contact_get_alias (empathy_ft_handler_get_contact (handler)),
862 empathy_ft_handler_get_filename (handler));
864 empathy_ft_handler_cancel_transfer (handler);
866 g_object_unref (handler);
869 static gboolean
870 close_window (EmpathyFTManager *manager)
872 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
874 DEBUG ("%p", manager);
876 /* remove all the completed/cancelled/errored transfers */
877 ft_manager_clear (manager);
879 if (g_hash_table_size (priv->ft_handler_to_row_ref) > 0)
881 /* There is still FTs on flight, just hide the window */
882 DEBUG ("Hiding window");
883 gtk_widget_hide (priv->window);
884 return TRUE;
887 return FALSE;
890 static void
891 ft_manager_response_cb (GtkWidget *widget,
892 gint response,
893 EmpathyFTManager *manager)
895 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
897 switch (response)
899 case RESPONSE_CLEAR:
900 ft_manager_clear (manager);
901 break;
902 case RESPONSE_OPEN:
903 ft_manager_open (manager);
904 break;
905 case RESPONSE_STOP:
906 ft_manager_stop (manager);
907 break;
908 case RESPONSE_CLOSE:
909 if (!close_window (manager))
910 gtk_widget_destroy (priv->window);
911 break;
912 case GTK_RESPONSE_NONE:
913 case GTK_RESPONSE_DELETE_EVENT:
914 /* Do nothing */
915 break;
916 default:
917 g_assert_not_reached ();
921 static gboolean
922 ft_manager_delete_event_cb (GtkWidget *widget,
923 GdkEvent *event,
924 EmpathyFTManager *manager)
926 return close_window (manager);
929 static void
930 ft_manager_destroy_cb (GtkWidget *widget,
931 EmpathyFTManager *manager)
933 DEBUG ("%p", manager);
935 g_object_unref (manager);
938 static gboolean
939 ft_view_button_press_event_cb (GtkWidget *widget,
940 GdkEventKey *event,
941 EmpathyFTManager *manager)
944 if (event->type != GDK_2BUTTON_PRESS)
945 return FALSE;
947 ft_manager_open (manager);
949 return FALSE;
952 static gboolean
953 ft_manager_key_press_event_cb (GtkWidget *widget,
954 GdkEventKey *event,
955 gpointer user_data)
957 if ((event->state & GDK_CONTROL_MASK && event->keyval == GDK_KEY_w)
958 || event->keyval == GDK_KEY_Escape)
960 gtk_widget_destroy (widget);
961 return TRUE;
964 return FALSE;
967 static void
968 ft_manager_build_ui (EmpathyFTManager *manager)
970 GtkBuilder *gui;
971 GtkTreeView *view;
972 GtkListStore *liststore;
973 GtkTreeViewColumn *column;
974 GtkCellRenderer *renderer;
975 GtkTreeSelection *selection;
976 gchar *filename;
977 EmpathyFTManagerPriv *priv = GET_PRIV (manager);
979 filename = empathy_file_lookup ("empathy-ft-manager.ui", "src");
980 gui = empathy_builder_get_file (filename,
981 "ft_manager_dialog", &priv->window,
982 "ft_list", &priv->treeview,
983 "clear_button", &priv->clear_button,
984 "open_button", &priv->open_button,
985 "abort_button", &priv->abort_button,
986 NULL);
987 g_free (filename);
989 empathy_builder_connect (gui, manager,
990 "ft_manager_dialog", "destroy", ft_manager_destroy_cb,
991 "ft_manager_dialog", "response", ft_manager_response_cb,
992 "ft_manager_dialog", "delete-event", ft_manager_delete_event_cb,
993 "ft_manager_dialog", "key-press-event", ft_manager_key_press_event_cb,
994 NULL);
996 empathy_builder_unref_and_keep_widget (gui, priv->window);
998 /* Window geometry. */
999 empathy_geometry_bind (GTK_WINDOW (priv->window), "ft-manager");
1001 /* Setup the tree view */
1002 view = GTK_TREE_VIEW (priv->treeview);
1003 selection = gtk_tree_view_get_selection (view);
1004 gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
1005 g_signal_connect (selection, "changed",
1006 G_CALLBACK (ft_manager_selection_changed), manager);
1007 g_signal_connect (view, "button-press-event",
1008 G_CALLBACK (ft_view_button_press_event_cb),
1009 manager);
1010 gtk_tree_view_set_headers_visible (view, TRUE);
1011 gtk_tree_view_set_enable_search (view, FALSE);
1013 /* Setup the model */
1014 liststore = gtk_list_store_new (5,
1015 G_TYPE_INT, /* percent */
1016 G_TYPE_ICON, /* icon */
1017 G_TYPE_STRING, /* message */
1018 G_TYPE_STRING, /* remaining */
1019 G_TYPE_OBJECT); /* ft_handler */
1020 gtk_tree_view_set_model (view, GTK_TREE_MODEL (liststore));
1021 priv->model = GTK_TREE_MODEL (liststore);
1022 g_object_unref (liststore);
1024 /* Progress column */
1025 column = gtk_tree_view_column_new ();
1026 gtk_tree_view_column_set_title (column, _("%"));
1027 gtk_tree_view_column_set_sort_column_id (column, COL_PERCENT);
1028 gtk_tree_view_insert_column (view, column, -1);
1030 renderer = gtk_cell_renderer_progress_new ();
1031 g_object_set (renderer, "xalign", 0.5, NULL);
1032 gtk_tree_view_column_pack_start (column, renderer, FALSE);
1033 gtk_tree_view_column_set_cell_data_func (column, renderer,
1034 ft_manager_progress_cell_data_func, NULL, NULL);
1036 /* Icon and filename column*/
1037 column = gtk_tree_view_column_new ();
1038 gtk_tree_view_column_set_title (column, _("File"));
1039 gtk_tree_view_column_set_expand (column, TRUE);
1040 gtk_tree_view_column_set_resizable (column, TRUE);
1041 gtk_tree_view_column_set_sort_column_id (column, COL_MESSAGE);
1042 gtk_tree_view_column_set_spacing (column, 3);
1043 gtk_tree_view_insert_column (view, column, -1);
1045 renderer = gtk_cell_renderer_pixbuf_new ();
1046 g_object_set (renderer, "xpad", 3,
1047 "stock-size", GTK_ICON_SIZE_DND, NULL);
1048 gtk_tree_view_column_pack_start (column, renderer, FALSE);
1049 gtk_tree_view_column_set_attributes (column, renderer,
1050 "gicon", COL_ICON, NULL);
1052 renderer = gtk_cell_renderer_text_new ();
1053 g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
1054 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1055 gtk_tree_view_column_set_attributes (column, renderer,
1056 "text", COL_MESSAGE, NULL);
1058 /* Remaining time column */
1059 column = gtk_tree_view_column_new ();
1060 gtk_tree_view_column_set_title (column, _("Remaining"));
1061 gtk_tree_view_column_set_sort_column_id (column, COL_REMAINING);
1062 gtk_tree_view_insert_column (view, column, -1);
1064 renderer = gtk_cell_renderer_text_new ();
1065 g_object_set (renderer, "xalign", 0.5, NULL);
1066 gtk_tree_view_column_pack_start (column, renderer, FALSE);
1067 gtk_tree_view_column_set_attributes (column, renderer,
1068 "text", COL_REMAINING, NULL);
1070 /* clear button should be sensitive only if there are completed/cancelled
1071 * handlers in the store.
1073 gtk_widget_set_sensitive (priv->clear_button, FALSE);
1076 /* GObject method overrides */
1078 static void
1079 empathy_ft_manager_finalize (GObject *object)
1081 EmpathyFTManagerPriv *priv = GET_PRIV (object);
1083 DEBUG ("FT Manager %p", object);
1085 g_hash_table_destroy (priv->ft_handler_to_row_ref);
1087 G_OBJECT_CLASS (empathy_ft_manager_parent_class)->finalize (object);
1090 static void
1091 empathy_ft_manager_init (EmpathyFTManager *manager)
1093 EmpathyFTManagerPriv *priv;
1095 priv = G_TYPE_INSTANCE_GET_PRIVATE ((manager), EMPATHY_TYPE_FT_MANAGER,
1096 EmpathyFTManagerPriv);
1098 manager->priv = priv;
1100 priv->ft_handler_to_row_ref = g_hash_table_new_full (g_direct_hash,
1101 g_direct_equal, (GDestroyNotify) g_object_unref,
1102 (GDestroyNotify) gtk_tree_row_reference_free);
1104 ft_manager_build_ui (manager);
1107 static GObject *
1108 empathy_ft_manager_constructor (GType type,
1109 guint n_props,
1110 GObjectConstructParam *props)
1112 GObject *retval;
1114 if (manager_singleton)
1116 retval = G_OBJECT (manager_singleton);
1118 else
1120 retval = G_OBJECT_CLASS (empathy_ft_manager_parent_class)->constructor
1121 (type, n_props, props);
1123 manager_singleton = EMPATHY_FT_MANAGER (retval);
1124 g_object_add_weak_pointer (retval, (gpointer) &manager_singleton);
1127 return retval;
1130 static void
1131 empathy_ft_manager_class_init (EmpathyFTManagerClass *klass)
1133 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1135 object_class->finalize = empathy_ft_manager_finalize;
1136 object_class->constructor = empathy_ft_manager_constructor;
1138 g_type_class_add_private (object_class, sizeof (EmpathyFTManagerPriv));
1141 /* public methods */
1143 void
1144 empathy_ft_manager_add_handler (EmpathyFTHandler *handler)
1146 EmpathyFTManager *manager;
1147 EmpathyFTManagerPriv *priv;
1149 DEBUG ("Adding handler");
1151 g_return_if_fail (EMPATHY_IS_FT_HANDLER (handler));
1153 manager = g_object_new (EMPATHY_TYPE_FT_MANAGER, NULL);
1154 priv = GET_PRIV (manager);
1156 ft_manager_add_handler_to_list (manager, handler, NULL);
1157 gtk_window_present (GTK_WINDOW (priv->window));
1160 void
1161 empathy_ft_manager_display_error (EmpathyFTHandler *handler,
1162 const GError *error)
1164 EmpathyFTManager *manager;
1165 EmpathyFTManagerPriv *priv;
1167 g_return_if_fail (EMPATHY_IS_FT_HANDLER (handler));
1168 g_return_if_fail (error != NULL);
1170 manager = g_object_new (EMPATHY_TYPE_FT_MANAGER, NULL);
1171 priv = GET_PRIV (manager);
1173 ft_manager_add_handler_to_list (manager, handler, error);
1174 gtk_window_present (GTK_WINDOW (priv->window));
1177 void
1178 empathy_ft_manager_show (void)
1180 EmpathyFTManager *manager;
1181 EmpathyFTManagerPriv *priv;
1183 manager = g_object_new (EMPATHY_TYPE_FT_MANAGER, NULL);
1184 priv = GET_PRIV (manager);
1186 gtk_window_present (GTK_WINDOW (priv->window));