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-store-manager.h"
39 #include "empathy-individual-view.h"
40 #include "empathy-individual-widget.h"
41 #include "empathy-persona-store.h"
42 #include "empathy-persona-view.h"
45 * SECTION:empathy-individual-linker
46 * @title:EmpathyIndividualLinker
47 * @short_description: A widget used to link together #FolksIndividual<!-- -->s
48 * @include: libempathy-gtk/empathy-individual-linker.h
50 * #EmpathyIndividualLinker is a widget which allows selection of several
51 * #FolksIndividual<!-- -->s to link together to form a single new individual.
52 * The widget provides a preview of the linked individual.
56 * EmpathyIndividualLinker:
57 * @parent: parent object
59 * Widget which extends #GtkBin to provide a list of #FolksIndividual<!-- -->s
63 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyIndividualLinker)
66 EmpathyIndividualStore *individual_store; /* owned */
67 EmpathyIndividualView *individual_view; /* child widget */
68 GtkWidget *preview_widget; /* child widget */
69 EmpathyPersonaStore *persona_store; /* owned */
70 GtkTreeViewColumn *toggle_column; /* child widget */
71 GtkCellRenderer *toggle_renderer; /* child widget */
72 GtkWidget *search_widget; /* child widget */
74 FolksIndividual *start_individual; /* owned, allow-none */
75 FolksIndividual *new_individual; /* owned, allow-none */
77 /* Stores the Individuals whose Personas have been added to the
79 /* unowned Individual (borrowed from EmpathyIndividualStore) -> bool */
80 GHashTable *changed_individuals;
81 } EmpathyIndividualLinkerPriv;
84 PROP_START_INDIVIDUAL = 1,
88 G_DEFINE_TYPE (EmpathyIndividualLinker, empathy_individual_linker,
92 contact_toggle_cell_data_func (GtkTreeViewColumn *tree_column,
93 GtkCellRenderer *cell,
94 GtkTreeModel *tree_model,
96 EmpathyIndividualLinker *self)
98 EmpathyIndividualLinkerPriv *priv;
99 FolksIndividual *individual;
100 gboolean is_group, individual_added;
102 priv = GET_PRIV (self);
104 gtk_tree_model_get (tree_model, iter,
105 EMPATHY_INDIVIDUAL_STORE_COL_IS_GROUP, &is_group,
106 EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, &individual,
109 individual_added = GPOINTER_TO_UINT (g_hash_table_lookup (
110 priv->changed_individuals, individual));
112 /* We don't want to show checkboxes next to the group rows.
113 * All checkboxes should be sensitive except the checkbox for the start
114 * individual, which should be permanently active and insensitive */
116 "visible", !is_group,
117 "sensitive", individual != priv->start_individual,
118 "activatable", individual != priv->start_individual,
119 "active", individual_added || individual == priv->start_individual,
122 tp_clear_object (&individual);
126 update_toggle_renderers (EmpathyIndividualLinker *self)
128 EmpathyIndividualLinkerPriv *priv = GET_PRIV (self);
130 /* Re-setting the cell data func to the same function causes a refresh of the
131 * entire column, ensuring that each toggle button is correctly active or
132 * inactive. This is necessary because one Individual might appear multiple
133 * times in the list (in different groups), so toggling one instance of the
134 * Individual should toggle all of them. */
135 gtk_tree_view_column_set_cell_data_func (priv->toggle_column,
136 priv->toggle_renderer,
137 (GtkTreeCellDataFunc) contact_toggle_cell_data_func, self, NULL);
141 link_individual (EmpathyIndividualLinker *self,
142 FolksIndividual *individual)
144 EmpathyIndividualLinkerPriv *priv = GET_PRIV (self);
145 GeeSet *old_personas, *new_personas;
146 GeeHashSet *final_personas;
147 gboolean personas_changed;
149 /* Add the individual to the link */
150 g_hash_table_insert (priv->changed_individuals, individual,
151 GUINT_TO_POINTER (TRUE));
153 /* Add personas which are in @individual to priv->new_individual, adding them
154 * to the set of personas. */
155 old_personas = folks_individual_get_personas (individual);
156 new_personas = folks_individual_get_personas (priv->new_individual);
157 final_personas = gee_hash_set_new (FOLKS_TYPE_PERSONA, g_object_ref,
158 g_object_unref, g_direct_hash, g_direct_equal);
159 gee_collection_add_all (GEE_COLLECTION (final_personas),
160 GEE_COLLECTION (old_personas));
161 personas_changed = gee_collection_add_all (GEE_COLLECTION (final_personas),
162 GEE_COLLECTION (new_personas));
164 /* avoid updating all values in the Individual if the set of personas doesn't
166 if (personas_changed)
168 folks_individual_set_personas (priv->new_individual,
169 GEE_SET (final_personas));
172 g_clear_object (&final_personas);
174 /* Update the toggle renderers, so that if this Individual is listed in
175 * another group in the EmpathyIndividualView, the toggle button for that
176 * group is updated. */
177 update_toggle_renderers (self);
179 g_object_notify (G_OBJECT (self), "has-changed");
183 unlink_individual (EmpathyIndividualLinker *self,
184 FolksIndividual *individual)
186 EmpathyIndividualLinkerPriv *priv = GET_PRIV (self);
187 GeeSet *removed_personas, *old_personas;
188 GeeHashSet *final_personas;
189 gboolean personas_changed;
191 /* Remove the individual from the link */
192 g_hash_table_remove (priv->changed_individuals, individual);
194 /* Remove personas which are in @individual from priv->new_individual. */
195 old_personas = folks_individual_get_personas (priv->new_individual);
196 removed_personas = folks_individual_get_personas (individual);
198 final_personas = gee_hash_set_new (FOLKS_TYPE_PERSONA, g_object_ref,
199 g_object_unref, g_direct_hash, g_direct_equal);
200 gee_collection_add_all (GEE_COLLECTION (final_personas),
201 GEE_COLLECTION (old_personas));
202 personas_changed = gee_collection_remove_all (GEE_COLLECTION (final_personas),
203 GEE_COLLECTION (removed_personas));
205 if (personas_changed)
207 folks_individual_set_personas (priv->new_individual,
208 GEE_SET (final_personas));
211 g_clear_object (&final_personas);
213 /* Update the toggle renderers, so that if this Individual is listed in
214 * another group in the EmpathyIndividualView, the toggle button for that
215 * group is updated. */
216 update_toggle_renderers (self);
218 g_object_notify (G_OBJECT (self), "has-changed");
222 toggle_individual_row (EmpathyIndividualLinker *self,
225 EmpathyIndividualLinkerPriv *priv = GET_PRIV (self);
226 FolksIndividual *individual;
228 GtkTreeModel *tree_model;
229 gboolean individual_added;
231 tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->individual_view));
233 gtk_tree_model_get_iter (tree_model, &iter, path);
234 gtk_tree_model_get (tree_model, &iter,
235 EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, &individual,
238 if (individual == NULL)
241 individual_added = GPOINTER_TO_UINT (g_hash_table_lookup (
242 priv->changed_individuals, individual));
244 /* Toggle the Individual's linked status */
245 if (individual_added)
246 unlink_individual (self, individual);
248 link_individual (self, individual);
250 g_object_unref (individual);
254 row_activated_cb (EmpathyIndividualView *view,
256 GtkTreeViewColumn *column,
257 EmpathyIndividualLinker *self)
259 toggle_individual_row (self, path);
263 row_toggled_cb (GtkCellRendererToggle *cell_renderer,
265 EmpathyIndividualLinker *self)
267 GtkTreePath *tree_path = gtk_tree_path_new_from_string (path);
268 toggle_individual_row (self, tree_path);
269 gtk_tree_path_free (tree_path);
273 individual_view_drag_motion_cb (GtkWidget *widget,
274 GdkDragContext *context,
279 EmpathyIndividualView *view = EMPATHY_INDIVIDUAL_VIEW (widget);
282 target = gtk_drag_dest_find_target (GTK_WIDGET (view), context, NULL);
284 if (target == gdk_atom_intern_static_string ("text/x-persona-id"))
288 /* FIXME: It doesn't make sense for us to highlight a specific row or
289 * position to drop a Persona in, so just highlight the entire widget.
290 * Since I can't find a way to do this, just highlight the first possible
291 * position in the tree. */
292 gdk_drag_status (context, gdk_drag_context_get_suggested_action (context),
295 path = gtk_tree_path_new_first ();
296 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (view), path,
297 GTK_TREE_VIEW_DROP_BEFORE);
298 gtk_tree_path_free (path);
303 /* Unknown or unhandled drag target */
304 gdk_drag_status (context, GDK_ACTION_DEFAULT, time_);
305 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (view), NULL, 0);
311 individual_view_drag_persona_received_cb (EmpathyIndividualView *view,
312 GdkDragAction action,
313 FolksPersona *persona,
314 FolksIndividual *individual,
315 EmpathyIndividualLinker *self)
317 EmpathyIndividualLinkerPriv *priv = GET_PRIV (self);
319 /* A Persona has been dragged onto the EmpathyIndividualView (from the
320 * EmpathyPersonaView), so we try to remove the Individual which contains
321 * the Persona from the link. */
322 if (individual != priv->start_individual)
324 unlink_individual (self, individual);
332 persona_view_drag_individual_received_cb (EmpathyPersonaView *view,
333 GdkDragAction action,
334 FolksIndividual *individual,
335 EmpathyIndividualLinker *self)
337 /* An Individual has been dragged onto the EmpathyPersonaView (from the
338 * EmpathyIndividualView), so we try to add the Individual to the link. */
339 link_individual (self, individual);
345 set_up (EmpathyIndividualLinker *self)
347 EmpathyIndividualLinkerPriv *priv;
348 EmpathyIndividualManager *individual_manager;
351 GtkWidget *label, *scrolled_window;
353 EmpathyPersonaView *persona_view;
355 GtkWidget *alignment;
357 priv = GET_PRIV (self);
359 top_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
363 paned = GTK_PANED (gtk_paned_new (GTK_ORIENTATION_HORIZONTAL));
365 /* Left column heading */
366 alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
367 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 0, 6);
368 gtk_widget_show (alignment);
370 vbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 6));
371 label = gtk_label_new (NULL);
372 tmp = g_strdup_printf ("<b>%s</b>", _("Select contacts to link"));
373 gtk_label_set_markup (GTK_LABEL (label), tmp);
375 gtk_box_pack_start (vbox, label, FALSE, TRUE, 0);
376 gtk_widget_show (label);
378 /* Individual selector */
379 individual_manager = empathy_individual_manager_dup_singleton ();
380 priv->individual_store = EMPATHY_INDIVIDUAL_STORE (
381 empathy_individual_store_manager_new (individual_manager));
382 g_object_unref (individual_manager);
384 empathy_individual_store_set_show_protocols (priv->individual_store, FALSE);
386 priv->individual_view = empathy_individual_view_new (priv->individual_store,
387 EMPATHY_INDIVIDUAL_VIEW_FEATURE_INDIVIDUAL_DRAG |
388 EMPATHY_INDIVIDUAL_VIEW_FEATURE_INDIVIDUAL_DROP |
389 EMPATHY_INDIVIDUAL_VIEW_FEATURE_PERSONA_DROP,
390 EMPATHY_INDIVIDUAL_FEATURE_NONE);
391 empathy_individual_view_set_show_offline (priv->individual_view, TRUE);
392 empathy_individual_view_set_show_untrusted (priv->individual_view, FALSE);
394 g_signal_connect (priv->individual_view, "row-activated",
395 (GCallback) row_activated_cb, self);
396 g_signal_connect (priv->individual_view, "drag-motion",
397 (GCallback) individual_view_drag_motion_cb, self);
398 g_signal_connect (priv->individual_view, "drag-persona-received",
399 (GCallback) individual_view_drag_persona_received_cb, self);
401 /* Add a checkbox column to the selector */
402 priv->toggle_renderer = gtk_cell_renderer_toggle_new ();
403 g_signal_connect (priv->toggle_renderer, "toggled",
404 (GCallback) row_toggled_cb, self);
406 priv->toggle_column = gtk_tree_view_column_new ();
407 gtk_tree_view_column_pack_start (priv->toggle_column, priv->toggle_renderer,
409 gtk_tree_view_column_set_cell_data_func (priv->toggle_column,
410 priv->toggle_renderer,
411 (GtkTreeCellDataFunc) contact_toggle_cell_data_func, self, NULL);
413 gtk_tree_view_insert_column (GTK_TREE_VIEW (priv->individual_view),
414 priv->toggle_column, 0);
416 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
417 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
418 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
419 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
421 gtk_container_add (GTK_CONTAINER (scrolled_window),
422 GTK_WIDGET (priv->individual_view));
423 gtk_widget_show (GTK_WIDGET (priv->individual_view));
425 gtk_box_pack_start (vbox, scrolled_window, TRUE, TRUE, 0);
426 gtk_widget_show (scrolled_window);
429 priv->search_widget = empathy_live_search_new (
430 GTK_WIDGET (priv->individual_view));
431 empathy_individual_view_set_live_search (priv->individual_view,
432 EMPATHY_LIVE_SEARCH (priv->search_widget));
434 gtk_box_pack_end (vbox, priv->search_widget, FALSE, TRUE, 0);
436 gtk_container_add (GTK_CONTAINER (alignment), GTK_WIDGET (vbox));
437 gtk_paned_pack1 (paned, alignment, TRUE, FALSE);
438 gtk_widget_show (GTK_WIDGET (vbox));
440 /* Right column heading */
441 alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
442 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 6, 0);
443 gtk_widget_show (alignment);
445 vbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 6));
446 label = gtk_label_new (NULL);
447 tmp = g_strdup_printf ("<b>%s</b>", _("New contact preview"));
448 gtk_label_set_markup (GTK_LABEL (label), tmp);
450 gtk_box_pack_start (vbox, label, FALSE, TRUE, 0);
451 gtk_widget_show (label);
453 /* New individual preview */
454 priv->preview_widget = empathy_individual_widget_new (priv->new_individual,
455 EMPATHY_INDIVIDUAL_WIDGET_SHOW_DETAILS);
456 gtk_box_pack_start (vbox, priv->preview_widget, FALSE, TRUE, 0);
457 gtk_widget_show (priv->preview_widget);
460 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
461 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
462 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
463 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
466 priv->persona_store = empathy_persona_store_new (priv->new_individual);
467 empathy_persona_store_set_show_protocols (priv->persona_store, TRUE);
468 persona_view = empathy_persona_view_new (priv->persona_store,
469 EMPATHY_PERSONA_VIEW_FEATURE_ALL);
470 empathy_persona_view_set_show_offline (persona_view, TRUE);
472 g_signal_connect (persona_view, "drag-individual-received",
473 (GCallback) persona_view_drag_individual_received_cb, self);
475 gtk_container_add (GTK_CONTAINER (scrolled_window),
476 GTK_WIDGET (persona_view));
477 gtk_widget_show (GTK_WIDGET (persona_view));
479 gtk_box_pack_start (vbox, scrolled_window, TRUE, TRUE, 0);
480 gtk_widget_show (scrolled_window);
482 gtk_container_add (GTK_CONTAINER (alignment), GTK_WIDGET (vbox));
483 gtk_paned_pack2 (paned, alignment, TRUE, FALSE);
484 gtk_widget_show (GTK_WIDGET (vbox));
486 gtk_widget_show (GTK_WIDGET (paned));
489 label = gtk_label_new (NULL);
490 tmp = g_strdup_printf ("<i>%s</i>",
491 _("Contacts selected in the list on the left will be linked together."));
492 gtk_label_set_markup (GTK_LABEL (label), tmp);
494 gtk_widget_show (label);
496 gtk_box_pack_start (GTK_BOX (top_vbox), GTK_WIDGET (paned), TRUE, TRUE, 0);
497 gtk_box_pack_start (GTK_BOX (top_vbox), label, FALSE, TRUE, 0);
499 /* Add the main vbox to the bin */
500 gtk_box_pack_start (GTK_BOX (self), GTK_WIDGET (top_vbox), TRUE, TRUE, 0);
501 gtk_widget_show (GTK_WIDGET (top_vbox));
505 empathy_individual_linker_init (EmpathyIndividualLinker *self)
507 EmpathyIndividualLinkerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
508 EMPATHY_TYPE_INDIVIDUAL_LINKER, EmpathyIndividualLinkerPriv);
512 priv->changed_individuals = g_hash_table_new (NULL, NULL);
518 get_property (GObject *object,
523 EmpathyIndividualLinkerPriv *priv;
525 priv = GET_PRIV (object);
529 case PROP_START_INDIVIDUAL:
530 g_value_set_object (value, priv->start_individual);
532 case PROP_HAS_CHANGED:
533 g_value_set_boolean (value, empathy_individual_linker_get_has_changed (
534 EMPATHY_INDIVIDUAL_LINKER (object)));
537 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
543 set_property (GObject *object,
550 case PROP_START_INDIVIDUAL:
551 empathy_individual_linker_set_start_individual (
552 EMPATHY_INDIVIDUAL_LINKER (object), g_value_get_object (value));
555 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
561 dispose (GObject *object)
563 EmpathyIndividualLinkerPriv *priv = GET_PRIV (object);
565 tp_clear_object (&priv->individual_store);
566 tp_clear_object (&priv->persona_store);
567 tp_clear_object (&priv->start_individual);
568 tp_clear_object (&priv->new_individual);
570 G_OBJECT_CLASS (empathy_individual_linker_parent_class)->dispose (object);
574 finalize (GObject *object)
576 EmpathyIndividualLinkerPriv *priv = GET_PRIV (object);
578 g_hash_table_unref (priv->changed_individuals);
580 G_OBJECT_CLASS (empathy_individual_linker_parent_class)->finalize (object);
584 empathy_individual_linker_class_init (EmpathyIndividualLinkerClass *klass)
586 GObjectClass *object_class = G_OBJECT_CLASS (klass);
588 object_class->get_property = get_property;
589 object_class->set_property = set_property;
590 object_class->dispose = dispose;
591 object_class->finalize = finalize;
594 * EmpathyIndividualLinker:start-individual:
596 * The #FolksIndividual to link other individuals to. This individual is
597 * selected by default in the list of individuals, and cannot be unselected.
598 * This ensures that empathy_individual_linker_get_linked_personas() will
599 * always return at least one persona to link.
601 g_object_class_install_property (object_class, PROP_START_INDIVIDUAL,
602 g_param_spec_object ("start-individual",
604 "The #FolksIndividual to link other individuals to.",
605 FOLKS_TYPE_INDIVIDUAL,
606 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
609 * EmpathyIndividualLinker:has-changed:
611 * Whether #FolksIndividual<!-- -->s have been added to or removed from
612 * the linked individual currently displayed in the widget.
614 * This will be %FALSE after the widget is initialised, and set to %TRUE when
615 * an individual is checked in the individual view on the left of the widget.
616 * If the individual is later unchecked, this will be reset to %FALSE, etc.
618 g_object_class_install_property (object_class, PROP_HAS_CHANGED,
619 g_param_spec_boolean ("has-changed",
621 "Whether individuals have been added to or removed from the linked "
622 "individual currently displayed in the widget.",
624 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
626 g_type_class_add_private (object_class, sizeof (EmpathyIndividualLinkerPriv));
630 * empathy_individual_linker_new:
631 * @start_individual: (allow-none): the #FolksIndividual to link to, or %NULL
633 * Creates a new #EmpathyIndividualLinker.
635 * Return value: a new #EmpathyIndividualLinker
638 empathy_individual_linker_new (FolksIndividual *start_individual)
640 g_return_val_if_fail (start_individual == NULL ||
641 FOLKS_IS_INDIVIDUAL (start_individual), NULL);
643 return g_object_new (EMPATHY_TYPE_INDIVIDUAL_LINKER,
644 "start-individual", start_individual,
649 * empathy_individual_linker_get_start_individual:
650 * @self: an #EmpathyIndividualLinker
652 * Get the value of #EmpathyIndividualLinker:start-individual.
654 * Return value: (transfer none): the start individual for linking, or %NULL
657 empathy_individual_linker_get_start_individual (EmpathyIndividualLinker *self)
659 g_return_val_if_fail (EMPATHY_IS_INDIVIDUAL_LINKER (self), NULL);
661 return GET_PRIV (self)->start_individual;
665 * empathy_individual_linker_set_start_individual:
666 * @self: an #EmpathyIndividualLinker
667 * @individual: (allow-none): the start individual, or %NULL
669 * Set the value of #EmpathyIndividualLinker:start-individual to @individual.
672 empathy_individual_linker_set_start_individual (EmpathyIndividualLinker *self,
673 FolksIndividual *individual)
675 EmpathyIndividualLinkerPriv *priv;
677 g_return_if_fail (EMPATHY_IS_INDIVIDUAL_LINKER (self));
678 g_return_if_fail (individual == NULL || FOLKS_IS_INDIVIDUAL (individual));
680 priv = GET_PRIV (self);
682 tp_clear_object (&priv->start_individual);
683 tp_clear_object (&priv->new_individual);
684 g_hash_table_remove_all (priv->changed_individuals);
686 if (individual != NULL)
688 priv->start_individual = g_object_ref (individual);
689 priv->new_individual = folks_individual_new (
690 folks_individual_get_personas (individual));
691 empathy_individual_view_set_store (priv->individual_view,
692 priv->individual_store);
696 priv->start_individual = NULL;
697 priv->new_individual = NULL;
699 /* We only display Individuals in the individual view if we have a
700 * new_individual to link them into */
701 empathy_individual_view_set_store (priv->individual_view, NULL);
704 empathy_individual_widget_set_individual (
705 EMPATHY_INDIVIDUAL_WIDGET (priv->preview_widget), priv->new_individual);
706 empathy_persona_store_set_individual (priv->persona_store,
707 priv->new_individual);
709 g_object_freeze_notify (G_OBJECT (self));
710 g_object_notify (G_OBJECT (self), "start-individual");
711 g_object_notify (G_OBJECT (self), "has-changed");
712 g_object_thaw_notify (G_OBJECT (self));
716 * empathy_individual_linker_get_linked_personas:
717 * @self: an #EmpathyIndividualLinker
719 * Return a list of the #FolksPersona<!-- -->s which comprise the linked
720 * individual currently displayed in the widget.
722 * The return value is guaranteed to contain at least one element.
724 * Return value: (transfer none) (element-type Folks.Persona): a set of
725 * #FolksPersona<!-- -->s to link together
728 empathy_individual_linker_get_linked_personas (EmpathyIndividualLinker *self)
730 EmpathyIndividualLinkerPriv *priv;
733 g_return_val_if_fail (EMPATHY_IS_INDIVIDUAL_LINKER (self), NULL);
735 priv = GET_PRIV (self);
737 if (priv->new_individual == NULL)
740 personas = folks_individual_get_personas (priv->new_individual);
741 g_assert (personas != NULL);
746 * empathy_individual_linker_get_has_changed:
747 * @self: an #EmpathyIndividualLinker
749 * Return whether #FolksIndividual<!-- -->s have been added to or removed from
750 * the linked individual currently displayed in the widget.
752 * This will be %FALSE after the widget is initialised, and set to %TRUE when
753 * an individual is checked in the individual view on the left of the widget.
754 * If the individual is later unchecked, this will be reset to %FALSE, etc.
756 * Return value: %TRUE if the linked individual has been changed, %FALSE
760 empathy_individual_linker_get_has_changed (EmpathyIndividualLinker *self)
762 EmpathyIndividualLinkerPriv *priv;
764 g_return_val_if_fail (EMPATHY_IS_INDIVIDUAL_LINKER (self), FALSE);
766 priv = GET_PRIV (self);
768 return (g_hash_table_size (priv->changed_individuals) > 0) ? TRUE : FALSE;
772 empathy_individual_linker_set_search_text (EmpathyIndividualLinker *self,
773 const gchar *search_text)
775 g_return_if_fail (EMPATHY_IS_INDIVIDUAL_LINKER (self));
777 empathy_live_search_set_text (
778 EMPATHY_LIVE_SEARCH (GET_PRIV (self)->search_widget), search_text);