2 * Copyright (C) 2010 Collabora Ltd.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301 USA
19 * Authors: Philip Withnall <philip.withnall@collabora.co.uk>
26 #include <glib/gi18n-lib.h>
29 #include <telepathy-glib/util.h>
31 #include <folks/folks.h>
33 #include <libempathy/empathy-individual-manager.h>
34 #include <libempathy/empathy-utils.h>
36 #include "empathy-individual-linker.h"
37 #include "empathy-individual-store.h"
38 #include "empathy-individual-view.h"
39 #include "empathy-individual-widget.h"
40 #include "empathy-persona-store.h"
41 #include "empathy-persona-view.h"
44 * SECTION:empathy-individual-linker
45 * @title:EmpathyIndividualLinker
46 * @short_description: A widget used to link together #FolksIndividual<!-- -->s
47 * @include: libempathy-gtk/empathy-individual-linker.h
49 * #EmpathyIndividualLinker is a widget which allows selection of several
50 * #FolksIndividual<!-- -->s to link together to form a single new individual.
51 * The widget provides a preview of the linked individual.
55 * EmpathyIndividualLinker:
56 * @parent: parent object
58 * Widget which extends #GtkBin to provide a list of #FolksIndividual<!-- -->s
62 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyIndividualLinker)
65 EmpathyIndividualStore *individual_store; /* owned */
66 EmpathyIndividualView *individual_view; /* child widget */
67 GtkWidget *preview_widget; /* child widget */
68 EmpathyPersonaStore *persona_store; /* owned */
69 GtkTreeViewColumn *toggle_column; /* child widget */
70 GtkCellRenderer *toggle_renderer; /* child widget */
71 GtkWidget *search_widget; /* child widget */
73 FolksIndividual *start_individual; /* owned, allow-none */
74 FolksIndividual *new_individual; /* owned, allow-none */
76 /* Stores the Individuals whose Personas have been added to the
78 /* unowned Individual (borrowed from EmpathyIndividualStore) -> bool */
79 GHashTable *changed_individuals;
80 } EmpathyIndividualLinkerPriv;
83 PROP_START_INDIVIDUAL = 1,
87 G_DEFINE_TYPE (EmpathyIndividualLinker, empathy_individual_linker,
91 contact_toggle_cell_data_func (GtkTreeViewColumn *tree_column,
92 GtkCellRenderer *cell,
93 GtkTreeModel *tree_model,
95 EmpathyIndividualLinker *self)
97 EmpathyIndividualLinkerPriv *priv;
98 FolksIndividual *individual;
99 gboolean is_group, individual_added;
101 priv = GET_PRIV (self);
103 gtk_tree_model_get (tree_model, iter,
104 EMPATHY_INDIVIDUAL_STORE_COL_IS_GROUP, &is_group,
105 EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, &individual,
108 individual_added = GPOINTER_TO_UINT (g_hash_table_lookup (
109 priv->changed_individuals, individual));
111 /* We don't want to show checkboxes next to the group rows.
112 * All checkboxes should be sensitive except the checkbox for the start
113 * individual, which should be permanently active and insensitive */
115 "visible", !is_group,
116 "sensitive", individual != priv->start_individual,
117 "activatable", individual != priv->start_individual,
118 "active", individual_added || individual == priv->start_individual,
121 tp_clear_object (&individual);
125 update_toggle_renderers (EmpathyIndividualLinker *self)
127 EmpathyIndividualLinkerPriv *priv = GET_PRIV (self);
129 /* Re-setting the cell data func to the same function causes a refresh of the
130 * entire column, ensuring that each toggle button is correctly active or
131 * inactive. This is necessary because one Individual might appear multiple
132 * times in the list (in different groups), so toggling one instance of the
133 * Individual should toggle all of them. */
134 gtk_tree_view_column_set_cell_data_func (priv->toggle_column,
135 priv->toggle_renderer,
136 (GtkTreeCellDataFunc) contact_toggle_cell_data_func, self, NULL);
140 link_individual (EmpathyIndividualLinker *self,
141 FolksIndividual *individual)
143 EmpathyIndividualLinkerPriv *priv = GET_PRIV (self);
144 GeeSet *old_personas, *new_personas;
145 GeeHashSet *final_personas;
146 gboolean personas_changed;
148 /* Add the individual to the link */
149 g_hash_table_insert (priv->changed_individuals, individual,
150 GUINT_TO_POINTER (TRUE));
152 /* Add personas which are in @individual to priv->new_individual, adding them
153 * to the set of personas. */
154 old_personas = folks_individual_get_personas (individual);
155 new_personas = folks_individual_get_personas (priv->new_individual);
156 final_personas = gee_hash_set_new (FOLKS_TYPE_PERSONA, g_object_ref,
157 g_object_unref, g_direct_hash, g_direct_equal);
158 gee_collection_add_all (GEE_COLLECTION (final_personas),
159 GEE_COLLECTION (old_personas));
160 personas_changed = gee_collection_add_all (GEE_COLLECTION (final_personas),
161 GEE_COLLECTION (new_personas));
163 /* avoid updating all values in the Individual if the set of personas doesn't
165 if (personas_changed)
167 folks_individual_set_personas (priv->new_individual,
168 GEE_SET (final_personas));
171 g_clear_object (&final_personas);
173 /* Update the toggle renderers, so that if this Individual is listed in
174 * another group in the EmpathyIndividualView, the toggle button for that
175 * group is updated. */
176 update_toggle_renderers (self);
178 g_object_notify (G_OBJECT (self), "has-changed");
182 unlink_individual (EmpathyIndividualLinker *self,
183 FolksIndividual *individual)
185 EmpathyIndividualLinkerPriv *priv = GET_PRIV (self);
186 GeeSet *removed_personas, *old_personas;
187 GeeHashSet *final_personas;
188 gboolean personas_changed;
190 /* Remove the individual from the link */
191 g_hash_table_remove (priv->changed_individuals, individual);
193 /* Remove personas which are in @individual from priv->new_individual. */
194 old_personas = folks_individual_get_personas (priv->new_individual);
195 removed_personas = folks_individual_get_personas (individual);
197 final_personas = gee_hash_set_new (FOLKS_TYPE_PERSONA, g_object_ref,
198 g_object_unref, g_direct_hash, g_direct_equal);
199 gee_collection_add_all (GEE_COLLECTION (final_personas),
200 GEE_COLLECTION (old_personas));
201 personas_changed = gee_collection_remove_all (GEE_COLLECTION (final_personas),
202 GEE_COLLECTION (removed_personas));
204 if (personas_changed)
206 folks_individual_set_personas (priv->new_individual,
207 GEE_SET (final_personas));
210 g_clear_object (&final_personas);
212 /* Update the toggle renderers, so that if this Individual is listed in
213 * another group in the EmpathyIndividualView, the toggle button for that
214 * group is updated. */
215 update_toggle_renderers (self);
217 g_object_notify (G_OBJECT (self), "has-changed");
221 toggle_individual_row (EmpathyIndividualLinker *self,
224 EmpathyIndividualLinkerPriv *priv = GET_PRIV (self);
225 FolksIndividual *individual;
227 GtkTreeModel *tree_model;
228 gboolean individual_added;
230 tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->individual_view));
232 gtk_tree_model_get_iter (tree_model, &iter, path);
233 gtk_tree_model_get (tree_model, &iter,
234 EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, &individual,
237 if (individual == NULL)
240 individual_added = GPOINTER_TO_UINT (g_hash_table_lookup (
241 priv->changed_individuals, individual));
243 /* Toggle the Individual's linked status */
244 if (individual_added)
245 unlink_individual (self, individual);
247 link_individual (self, individual);
249 g_object_unref (individual);
253 row_activated_cb (EmpathyIndividualView *view,
255 GtkTreeViewColumn *column,
256 EmpathyIndividualLinker *self)
258 toggle_individual_row (self, path);
262 row_toggled_cb (GtkCellRendererToggle *cell_renderer,
264 EmpathyIndividualLinker *self)
266 GtkTreePath *tree_path = gtk_tree_path_new_from_string (path);
267 toggle_individual_row (self, tree_path);
268 gtk_tree_path_free (tree_path);
272 individual_view_drag_motion_cb (GtkWidget *widget,
273 GdkDragContext *context,
278 EmpathyIndividualView *view = EMPATHY_INDIVIDUAL_VIEW (widget);
281 target = gtk_drag_dest_find_target (GTK_WIDGET (view), context, NULL);
283 if (target == gdk_atom_intern_static_string ("text/persona-id"))
287 /* FIXME: It doesn't make sense for us to highlight a specific row or
288 * position to drop a Persona in, so just highlight the entire widget.
289 * Since I can't find a way to do this, just highlight the first possible
290 * position in the tree. */
291 gdk_drag_status (context, gdk_drag_context_get_suggested_action (context),
294 path = gtk_tree_path_new_first ();
295 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (view), path,
296 GTK_TREE_VIEW_DROP_BEFORE);
297 gtk_tree_path_free (path);
302 /* Unknown or unhandled drag target */
303 gdk_drag_status (context, GDK_ACTION_DEFAULT, time_);
304 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (view), NULL, 0);
310 individual_view_drag_persona_received_cb (EmpathyIndividualView *view,
311 GdkDragAction action,
312 FolksPersona *persona,
313 FolksIndividual *individual,
314 EmpathyIndividualLinker *self)
316 EmpathyIndividualLinkerPriv *priv = GET_PRIV (self);
318 /* A Persona has been dragged onto the EmpathyIndividualView (from the
319 * EmpathyPersonaView), so we try to remove the Individual which contains
320 * the Persona from the link. */
321 if (individual != priv->start_individual)
323 unlink_individual (self, individual);
331 persona_view_drag_individual_received_cb (EmpathyPersonaView *view,
332 GdkDragAction action,
333 FolksIndividual *individual,
334 EmpathyIndividualLinker *self)
336 /* An Individual has been dragged onto the EmpathyPersonaView (from the
337 * EmpathyIndividualView), so we try to add the Individual to the link. */
338 link_individual (self, individual);
344 set_up (EmpathyIndividualLinker *self)
346 EmpathyIndividualLinkerPriv *priv;
347 EmpathyIndividualManager *individual_manager;
350 GtkWidget *label, *scrolled_window;
352 EmpathyPersonaView *persona_view;
354 GtkWidget *alignment;
356 priv = GET_PRIV (self);
358 top_vbox = gtk_vbox_new (FALSE, 6);
361 paned = GTK_PANED (gtk_hpaned_new ());
363 /* Left column heading */
364 alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
365 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 0, 6);
366 gtk_widget_show (alignment);
368 vbox = GTK_BOX (gtk_vbox_new (FALSE, 6));
369 label = gtk_label_new (NULL);
370 tmp = g_strdup_printf ("<b>%s</b>", _("Select contacts to link"));
371 gtk_label_set_markup (GTK_LABEL (label), tmp);
373 gtk_box_pack_start (vbox, label, FALSE, TRUE, 0);
374 gtk_widget_show (label);
376 /* Individual selector */
377 individual_manager = empathy_individual_manager_dup_singleton ();
378 priv->individual_store = empathy_individual_store_new (individual_manager);
379 g_object_unref (individual_manager);
381 empathy_individual_store_set_show_protocols (priv->individual_store, FALSE);
383 priv->individual_view = empathy_individual_view_new (priv->individual_store,
384 EMPATHY_INDIVIDUAL_VIEW_FEATURE_INDIVIDUAL_DRAG |
385 EMPATHY_INDIVIDUAL_VIEW_FEATURE_INDIVIDUAL_DROP |
386 EMPATHY_INDIVIDUAL_VIEW_FEATURE_PERSONA_DROP,
387 EMPATHY_INDIVIDUAL_FEATURE_NONE);
388 empathy_individual_view_set_show_offline (priv->individual_view, TRUE);
389 empathy_individual_view_set_show_untrusted (priv->individual_view, FALSE);
391 g_signal_connect (priv->individual_view, "row-activated",
392 (GCallback) row_activated_cb, self);
393 g_signal_connect (priv->individual_view, "drag-motion",
394 (GCallback) individual_view_drag_motion_cb, self);
395 g_signal_connect (priv->individual_view, "drag-persona-received",
396 (GCallback) individual_view_drag_persona_received_cb, self);
398 /* Add a checkbox column to the selector */
399 priv->toggle_renderer = gtk_cell_renderer_toggle_new ();
400 g_signal_connect (priv->toggle_renderer, "toggled",
401 (GCallback) row_toggled_cb, self);
403 priv->toggle_column = gtk_tree_view_column_new ();
404 gtk_tree_view_column_pack_start (priv->toggle_column, priv->toggle_renderer,
406 gtk_tree_view_column_set_cell_data_func (priv->toggle_column,
407 priv->toggle_renderer,
408 (GtkTreeCellDataFunc) contact_toggle_cell_data_func, self, NULL);
410 gtk_tree_view_insert_column (GTK_TREE_VIEW (priv->individual_view),
411 priv->toggle_column, 0);
413 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
414 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
415 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
416 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
418 gtk_container_add (GTK_CONTAINER (scrolled_window),
419 GTK_WIDGET (priv->individual_view));
420 gtk_widget_show (GTK_WIDGET (priv->individual_view));
422 gtk_box_pack_start (vbox, scrolled_window, TRUE, TRUE, 0);
423 gtk_widget_show (scrolled_window);
426 priv->search_widget = empathy_live_search_new (
427 GTK_WIDGET (priv->individual_view));
428 empathy_individual_view_set_live_search (priv->individual_view,
429 EMPATHY_LIVE_SEARCH (priv->search_widget));
431 gtk_box_pack_end (vbox, priv->search_widget, FALSE, TRUE, 0);
433 gtk_container_add (GTK_CONTAINER (alignment), GTK_WIDGET (vbox));
434 gtk_paned_pack1 (paned, alignment, TRUE, FALSE);
435 gtk_widget_show (GTK_WIDGET (vbox));
437 /* Right column heading */
438 alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
439 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 6, 0);
440 gtk_widget_show (alignment);
442 vbox = GTK_BOX (gtk_vbox_new (FALSE, 6));
443 label = gtk_label_new (NULL);
444 tmp = g_strdup_printf ("<b>%s</b>", _("New contact preview"));
445 gtk_label_set_markup (GTK_LABEL (label), tmp);
447 gtk_box_pack_start (vbox, label, FALSE, TRUE, 0);
448 gtk_widget_show (label);
450 /* New individual preview */
451 priv->preview_widget = empathy_individual_widget_new (priv->new_individual,
452 EMPATHY_INDIVIDUAL_WIDGET_SHOW_DETAILS);
453 gtk_box_pack_start (vbox, priv->preview_widget, FALSE, TRUE, 0);
454 gtk_widget_show (priv->preview_widget);
457 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
458 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
459 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
460 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
463 priv->persona_store = empathy_persona_store_new (priv->new_individual);
464 empathy_persona_store_set_show_protocols (priv->persona_store, TRUE);
465 persona_view = empathy_persona_view_new (priv->persona_store,
466 EMPATHY_PERSONA_VIEW_FEATURE_ALL);
467 empathy_persona_view_set_show_offline (persona_view, TRUE);
469 g_signal_connect (persona_view, "drag-individual-received",
470 (GCallback) persona_view_drag_individual_received_cb, self);
472 gtk_container_add (GTK_CONTAINER (scrolled_window),
473 GTK_WIDGET (persona_view));
474 gtk_widget_show (GTK_WIDGET (persona_view));
476 gtk_box_pack_start (vbox, scrolled_window, TRUE, TRUE, 0);
477 gtk_widget_show (scrolled_window);
479 gtk_container_add (GTK_CONTAINER (alignment), GTK_WIDGET (vbox));
480 gtk_paned_pack2 (paned, alignment, TRUE, FALSE);
481 gtk_widget_show (GTK_WIDGET (vbox));
483 gtk_widget_show (GTK_WIDGET (paned));
486 label = gtk_label_new (NULL);
487 tmp = g_strdup_printf ("<i>%s</i>",
488 _("Contacts selected in the list on the left will be linked together."));
489 gtk_label_set_markup (GTK_LABEL (label), tmp);
491 gtk_widget_show (label);
493 gtk_box_pack_start (GTK_BOX (top_vbox), GTK_WIDGET (paned), TRUE, TRUE, 0);
494 gtk_box_pack_start (GTK_BOX (top_vbox), label, FALSE, TRUE, 0);
496 /* Add the main vbox to the bin */
497 gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (top_vbox));
498 gtk_widget_show (GTK_WIDGET (top_vbox));
502 empathy_individual_linker_init (EmpathyIndividualLinker *self)
504 EmpathyIndividualLinkerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
505 EMPATHY_TYPE_INDIVIDUAL_LINKER, EmpathyIndividualLinkerPriv);
509 priv->changed_individuals = g_hash_table_new (NULL, NULL);
515 get_property (GObject *object,
520 EmpathyIndividualLinkerPriv *priv;
522 priv = GET_PRIV (object);
526 case PROP_START_INDIVIDUAL:
527 g_value_set_object (value, priv->start_individual);
529 case PROP_HAS_CHANGED:
530 g_value_set_boolean (value, empathy_individual_linker_get_has_changed (
531 EMPATHY_INDIVIDUAL_LINKER (object)));
534 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
540 set_property (GObject *object,
547 case PROP_START_INDIVIDUAL:
548 empathy_individual_linker_set_start_individual (
549 EMPATHY_INDIVIDUAL_LINKER (object), g_value_get_object (value));
552 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
558 dispose (GObject *object)
560 EmpathyIndividualLinkerPriv *priv = GET_PRIV (object);
562 tp_clear_object (&priv->individual_store);
563 tp_clear_object (&priv->persona_store);
564 tp_clear_object (&priv->start_individual);
565 tp_clear_object (&priv->new_individual);
567 G_OBJECT_CLASS (empathy_individual_linker_parent_class)->dispose (object);
571 finalize (GObject *object)
573 EmpathyIndividualLinkerPriv *priv = GET_PRIV (object);
575 g_hash_table_destroy (priv->changed_individuals);
577 G_OBJECT_CLASS (empathy_individual_linker_parent_class)->finalize (object);
581 size_allocate (GtkWidget *widget,
582 GtkAllocation *allocation)
584 GtkBin *bin = GTK_BIN (widget);
585 GtkAllocation child_allocation;
588 gtk_widget_set_allocation (widget, allocation);
590 child = gtk_bin_get_child (bin);
592 if (child && gtk_widget_get_visible (child))
594 child_allocation.x = allocation->x +
595 gtk_container_get_border_width (GTK_CONTAINER (widget));
596 child_allocation.y = allocation->y +
597 gtk_container_get_border_width (GTK_CONTAINER (widget));
598 child_allocation.width = MAX (allocation->width -
599 gtk_container_get_border_width (GTK_CONTAINER (widget)) * 2, 0);
600 child_allocation.height = MAX (allocation->height -
601 gtk_container_get_border_width (GTK_CONTAINER (widget)) * 2, 0);
603 gtk_widget_size_allocate (child, &child_allocation);
608 empathy_individual_linker_class_init (EmpathyIndividualLinkerClass *klass)
610 GObjectClass *object_class = G_OBJECT_CLASS (klass);
611 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
613 object_class->get_property = get_property;
614 object_class->set_property = set_property;
615 object_class->dispose = dispose;
616 object_class->finalize = finalize;
618 widget_class->size_allocate = size_allocate;
621 * EmpathyIndividualLinker:start-individual:
623 * The #FolksIndividual to link other individuals to. This individual is
624 * selected by default in the list of individuals, and cannot be unselected.
625 * This ensures that empathy_individual_linker_get_linked_personas() will
626 * always return at least one persona to link.
628 g_object_class_install_property (object_class, PROP_START_INDIVIDUAL,
629 g_param_spec_object ("start-individual",
631 "The #FolksIndividual to link other individuals to.",
632 FOLKS_TYPE_INDIVIDUAL,
633 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
636 * EmpathyIndividualLinker:has-changed:
638 * Whether #FolksIndividual<!-- -->s have been added to or removed from
639 * the linked individual currently displayed in the widget.
641 * This will be %FALSE after the widget is initialised, and set to %TRUE when
642 * an individual is checked in the individual view on the left of the widget.
643 * If the individual is later unchecked, this will be reset to %FALSE, etc.
645 g_object_class_install_property (object_class, PROP_HAS_CHANGED,
646 g_param_spec_boolean ("has-changed",
648 "Whether individuals have been added to or removed from the linked "
649 "individual currently displayed in the widget.",
651 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
653 g_type_class_add_private (object_class, sizeof (EmpathyIndividualLinkerPriv));
657 * empathy_individual_linker_new:
658 * @start_individual: (allow-none): the #FolksIndividual to link to, or %NULL
660 * Creates a new #EmpathyIndividualLinker.
662 * Return value: a new #EmpathyIndividualLinker
665 empathy_individual_linker_new (FolksIndividual *start_individual)
667 g_return_val_if_fail (start_individual == NULL ||
668 FOLKS_IS_INDIVIDUAL (start_individual), NULL);
670 return g_object_new (EMPATHY_TYPE_INDIVIDUAL_LINKER,
671 "start-individual", start_individual,
676 * empathy_individual_linker_get_start_individual:
677 * @self: an #EmpathyIndividualLinker
679 * Get the value of #EmpathyIndividualLinker:start-individual.
681 * Return value: (transfer none): the start individual for linking, or %NULL
684 empathy_individual_linker_get_start_individual (EmpathyIndividualLinker *self)
686 g_return_val_if_fail (EMPATHY_IS_INDIVIDUAL_LINKER (self), NULL);
688 return GET_PRIV (self)->start_individual;
692 * empathy_individual_linker_set_start_individual:
693 * @self: an #EmpathyIndividualLinker
694 * @individual: (allow-none): the start individual, or %NULL
696 * Set the value of #EmpathyIndividualLinker:start-individual to @individual.
699 empathy_individual_linker_set_start_individual (EmpathyIndividualLinker *self,
700 FolksIndividual *individual)
702 EmpathyIndividualLinkerPriv *priv;
704 g_return_if_fail (EMPATHY_IS_INDIVIDUAL_LINKER (self));
705 g_return_if_fail (individual == NULL || FOLKS_IS_INDIVIDUAL (individual));
707 priv = GET_PRIV (self);
709 tp_clear_object (&priv->start_individual);
710 tp_clear_object (&priv->new_individual);
711 g_hash_table_remove_all (priv->changed_individuals);
713 if (individual != NULL)
715 priv->start_individual = g_object_ref (individual);
716 priv->new_individual = folks_individual_new (
717 folks_individual_get_personas (individual));
718 empathy_individual_view_set_store (priv->individual_view,
719 priv->individual_store);
723 priv->start_individual = NULL;
724 priv->new_individual = NULL;
726 /* We only display Individuals in the individual view if we have a
727 * new_individual to link them into */
728 empathy_individual_view_set_store (priv->individual_view, NULL);
731 empathy_individual_widget_set_individual (
732 EMPATHY_INDIVIDUAL_WIDGET (priv->preview_widget), priv->new_individual);
733 empathy_persona_store_set_individual (priv->persona_store,
734 priv->new_individual);
736 g_object_freeze_notify (G_OBJECT (self));
737 g_object_notify (G_OBJECT (self), "start-individual");
738 g_object_notify (G_OBJECT (self), "has-changed");
739 g_object_thaw_notify (G_OBJECT (self));
743 * empathy_individual_linker_get_linked_personas:
744 * @self: an #EmpathyIndividualLinker
746 * Return a list of the #FolksPersona<!-- -->s which comprise the linked
747 * individual currently displayed in the widget.
749 * The return value is guaranteed to contain at least one element.
751 * Return value: (transfer none) (element-type Folks.Persona): a set of
752 * #FolksPersona<!-- -->s to link together
755 empathy_individual_linker_get_linked_personas (EmpathyIndividualLinker *self)
757 EmpathyIndividualLinkerPriv *priv;
760 g_return_val_if_fail (EMPATHY_IS_INDIVIDUAL_LINKER (self), NULL);
762 priv = GET_PRIV (self);
764 if (priv->new_individual == NULL)
767 personas = folks_individual_get_personas (priv->new_individual);
768 g_assert (personas != NULL);
773 * empathy_individual_linker_get_has_changed:
774 * @self: an #EmpathyIndividualLinker
776 * Return whether #FolksIndividual<!-- -->s have been added to or removed from
777 * the linked individual currently displayed in the widget.
779 * This will be %FALSE after the widget is initialised, and set to %TRUE when
780 * an individual is checked in the individual view on the left of the widget.
781 * If the individual is later unchecked, this will be reset to %FALSE, etc.
783 * Return value: %TRUE if the linked individual has been changed, %FALSE
787 empathy_individual_linker_get_has_changed (EmpathyIndividualLinker *self)
789 EmpathyIndividualLinkerPriv *priv;
791 g_return_val_if_fail (EMPATHY_IS_INDIVIDUAL_LINKER (self), FALSE);
793 priv = GET_PRIV (self);
795 return (g_hash_table_size (priv->changed_individuals) > 0) ? TRUE : FALSE;
799 empathy_individual_linker_set_search_text (EmpathyIndividualLinker *self,
800 const gchar *search_text)
802 g_return_if_fail (EMPATHY_IS_INDIVIDUAL_LINKER (self));
804 empathy_live_search_set_text (
805 EMPATHY_LIVE_SEARCH (GET_PRIV (self)->search_widget), search_text);