]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-individual-linker.c
3713a8bda5f09a584095cb92e4b93f10739ff253
[empathy.git] / libempathy-gtk / empathy-individual-linker.c
1 /*
2  * Copyright (C) 2010 Collabora Ltd.
3  *
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.
8  *
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.
13  *
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
18  *
19  * Authors: Philip Withnall <philip.withnall@collabora.co.uk>
20  */
21
22 #include "config.h"
23
24 #include <string.h>
25
26 #include <glib/gi18n-lib.h>
27 #include <gtk/gtk.h>
28
29 #include <telepathy-glib/util.h>
30
31 #include <folks/folks.h>
32
33 #include <libempathy/empathy-individual-manager.h>
34 #include <libempathy/empathy-utils.h>
35
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"
42
43 /**
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
48  *
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.
52  */
53
54 /**
55  * EmpathyIndividualLinker:
56  * @parent: parent object
57  *
58  * Widget which extends #GtkBin to provide a list of #FolksIndividual<!-- -->s
59  * to link together.
60  */
61
62 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyIndividualLinker)
63
64 typedef struct {
65   EmpathyIndividualStore *individual_store; /* owned */
66   EmpathyIndividualView *individual_view; /* child widget */
67   GtkWidget *preview_widget; /* child widget */
68   EmpathyPersonaStore *persona_store; /* owned */
69
70   FolksIndividual *start_individual; /* owned, allow-none */
71   FolksIndividual *new_individual; /* owned, allow-none */
72
73   /* Stores the Individuals whose Personas have been added to the
74    * new_individual */
75   /* unowned Individual (borrowed from EmpathyIndividualStore) -> bool */
76   GHashTable *changed_individuals;
77 } EmpathyIndividualLinkerPriv;
78
79 enum {
80   PROP_START_INDIVIDUAL = 1,
81 };
82
83 G_DEFINE_TYPE (EmpathyIndividualLinker, empathy_individual_linker,
84     GTK_TYPE_BIN);
85
86 static void
87 contact_toggle_cell_data_func (GtkTreeViewColumn *tree_column,
88     GtkCellRenderer *cell,
89     GtkTreeModel *tree_model,
90     GtkTreeIter *iter,
91     EmpathyIndividualLinker *self)
92 {
93   EmpathyIndividualLinkerPriv *priv;
94   FolksIndividual *individual;
95   gboolean is_group, individual_added;
96
97   priv = GET_PRIV (self);
98
99   gtk_tree_model_get (tree_model, iter,
100       EMPATHY_INDIVIDUAL_STORE_COL_IS_GROUP, &is_group,
101       EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, &individual,
102       -1);
103
104   individual_added = GPOINTER_TO_UINT (g_hash_table_lookup (
105       priv->changed_individuals, individual));
106
107   /* We don't want to show checkboxes next to the group rows.
108    * All checkboxes should be sensitive except the checkbox for the start
109    * individual, which should be permanently active and insensitive */
110   g_object_set (cell,
111       "visible", !is_group,
112       "sensitive", individual != priv->start_individual,
113       "activatable", individual != priv->start_individual,
114       "active", individual_added || individual == priv->start_individual,
115       NULL);
116
117   tp_clear_object (&individual);
118 }
119
120 static void
121 link_individual (EmpathyIndividualLinker *self,
122     FolksIndividual *individual)
123 {
124   EmpathyIndividualLinkerPriv *priv = GET_PRIV (self);
125   GList *new_persona_list;
126
127   /* Add the individual to the link */
128   g_hash_table_insert (priv->changed_individuals, individual,
129       GUINT_TO_POINTER (TRUE));
130
131   /* Add personas which are in @individual to priv->new_individual, appending
132    * them to the list of personas.
133    * This is rather slow. */
134   new_persona_list = g_list_copy (folks_individual_get_personas (
135       priv->new_individual));
136   new_persona_list = g_list_concat (new_persona_list,
137       g_list_copy (folks_individual_get_personas (individual)));
138   folks_individual_set_personas (priv->new_individual, new_persona_list);
139   g_list_free (new_persona_list);
140 }
141
142 static void
143 unlink_individual (EmpathyIndividualLinker *self,
144     FolksIndividual *individual)
145 {
146   EmpathyIndividualLinkerPriv *priv = GET_PRIV (self);
147   GList *new_persona_list, *old_persona_list, *removing_personas, *l;
148
149   /* Remove the individual from the link */
150   g_hash_table_remove (priv->changed_individuals, individual);
151
152   /* Remove personas which are in @individual from priv->new_individual.
153    * This is rather slow. */
154   old_persona_list = folks_individual_get_personas (priv->new_individual);
155   removing_personas = folks_individual_get_personas (individual);
156   new_persona_list = NULL;
157
158   for (l = old_persona_list; l != NULL; l = l->next)
159     {
160       GList *removing = g_list_find (removing_personas, l->data);
161
162       if (removing == NULL)
163         new_persona_list = g_list_prepend (new_persona_list, l->data);
164     }
165
166   new_persona_list = g_list_reverse (new_persona_list);
167   folks_individual_set_personas (priv->new_individual, new_persona_list);
168   g_list_free (new_persona_list);
169 }
170
171 static void
172 toggle_individual_row (EmpathyIndividualLinker *self,
173     GtkTreePath *path)
174 {
175   EmpathyIndividualLinkerPriv *priv = GET_PRIV (self);
176   FolksIndividual *individual;
177   GtkTreeIter iter;
178   GtkTreeModel *tree_model;
179   gboolean individual_added;
180
181   tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->individual_view));
182
183   gtk_tree_model_get_iter (tree_model, &iter, path);
184   gtk_tree_model_get (tree_model, &iter,
185       EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, &individual,
186       -1);
187
188   individual_added = GPOINTER_TO_UINT (g_hash_table_lookup (
189       priv->changed_individuals, individual));
190
191   /* Toggle the Individual's linked status */
192   if (individual_added)
193     unlink_individual (self, individual);
194   else
195     link_individual (self, individual);
196
197   g_object_unref (individual);
198 }
199
200 static void
201 row_toggled_cb (GtkCellRendererToggle *cell_renderer,
202     const gchar *path,
203     EmpathyIndividualLinker *self)
204 {
205   GtkTreePath *tree_path = gtk_tree_path_new_from_string (path);
206   toggle_individual_row (self, tree_path);
207   gtk_tree_path_free (tree_path);
208 }
209
210 static void
211 search_bar_activate_cb (EmpathyLiveSearch *search_bar,
212     EmpathyIndividualLinker *self)
213 {
214   EmpathyIndividualLinkerPriv *priv = GET_PRIV (self);
215   GtkTreeSelection *selection;
216   GList *rows, *l;
217
218   /* Toggle the status of the selected individuals */
219   selection = gtk_tree_view_get_selection (
220       GTK_TREE_VIEW (priv->individual_view));
221   rows = gtk_tree_selection_get_selected_rows (selection, NULL);
222
223   for (l = rows; l != NULL; l = l->next)
224     {
225       GtkTreePath *path = (GtkTreePath *) l->data;
226       toggle_individual_row (self, path);
227       gtk_tree_path_free (path);
228     }
229
230   g_list_free (rows);
231 }
232
233 static void
234 set_up (EmpathyIndividualLinker *self)
235 {
236   EmpathyIndividualLinkerPriv *priv;
237   EmpathyIndividualManager *individual_manager;
238   GtkCellRenderer *cell_renderer;
239   GtkWidget *top_vbox;
240   GtkPaned *paned;
241   GtkWidget *label, *scrolled_window, *search_bar;
242   GtkBox *vbox;
243   EmpathyPersonaView *persona_view;
244   gchar *tmp;
245   GtkWidget *alignment;
246
247   priv = GET_PRIV (self);
248
249   top_vbox = gtk_vbox_new (FALSE, 6);
250
251   /* Layout panes */
252   paned = GTK_PANED (gtk_hpaned_new ());
253
254   /* Left column heading */
255   alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
256   gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 0, 6);
257   gtk_widget_show (alignment);
258
259   vbox = GTK_BOX (gtk_vbox_new (FALSE, 6));
260   label = gtk_label_new (NULL);
261   tmp = g_strdup_printf ("<b>%s</b>", _("Select contacts to link"));
262   gtk_label_set_markup (GTK_LABEL (label), tmp);
263   g_free (tmp);
264   gtk_box_pack_start (vbox, label, FALSE, TRUE, 0);
265   gtk_widget_show (label);
266
267   /* Individual selector */
268   individual_manager = empathy_individual_manager_dup_singleton ();
269   priv->individual_store = empathy_individual_store_new (individual_manager);
270   g_object_unref (individual_manager);
271
272   empathy_individual_store_set_show_protocols (priv->individual_store, FALSE);
273
274   priv->individual_view = empathy_individual_view_new (priv->individual_store,
275       EMPATHY_INDIVIDUAL_VIEW_FEATURE_NONE, EMPATHY_INDIVIDUAL_FEATURE_NONE);
276   empathy_individual_view_set_show_offline (priv->individual_view, TRUE);
277
278   /* Add a checkbox column to the selector */
279   cell_renderer = gtk_cell_renderer_toggle_new ();
280   g_signal_connect (cell_renderer, "toggled", (GCallback) row_toggled_cb, self);
281   gtk_tree_view_insert_column_with_data_func (
282       GTK_TREE_VIEW (priv->individual_view), 0, NULL, cell_renderer,
283       (GtkTreeCellDataFunc) contact_toggle_cell_data_func, self, NULL);
284
285   scrolled_window = gtk_scrolled_window_new (NULL, NULL);
286   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
287       GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
288   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
289       GTK_SHADOW_IN);
290   gtk_container_add (GTK_CONTAINER (scrolled_window),
291       GTK_WIDGET (priv->individual_view));
292   gtk_widget_show (GTK_WIDGET (priv->individual_view));
293
294   gtk_box_pack_start (vbox, scrolled_window, TRUE, TRUE, 0);
295   gtk_widget_show (scrolled_window);
296
297   /* Live search */
298   search_bar = empathy_live_search_new (GTK_WIDGET (priv->individual_view));
299   empathy_individual_view_set_live_search (priv->individual_view,
300       EMPATHY_LIVE_SEARCH (search_bar));
301   g_signal_connect (search_bar, "activate", (GCallback) search_bar_activate_cb,
302       self);
303
304   gtk_box_pack_end (vbox, search_bar, FALSE, TRUE, 0);
305
306   gtk_container_add (GTK_CONTAINER (alignment), GTK_WIDGET (vbox));
307   gtk_paned_pack1 (paned, alignment, TRUE, FALSE);
308   gtk_widget_show (GTK_WIDGET (vbox));
309
310   /* Right column heading */
311   alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
312   gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 6, 0);
313   gtk_widget_show (alignment);
314
315   vbox = GTK_BOX (gtk_vbox_new (FALSE, 6));
316   label = gtk_label_new (NULL);
317   tmp = g_strdup_printf ("<b>%s</b>", _("New contact preview"));
318   gtk_label_set_markup (GTK_LABEL (label), tmp);
319   g_free (tmp);
320   gtk_box_pack_start (vbox, label, FALSE, TRUE, 0);
321   gtk_widget_show (label);
322
323   /* New individual preview */
324   priv->preview_widget = empathy_individual_widget_new (priv->new_individual,
325       EMPATHY_INDIVIDUAL_WIDGET_SHOW_DETAILS);
326   gtk_box_pack_start (vbox, priv->preview_widget, FALSE, TRUE, 0);
327   gtk_widget_show (priv->preview_widget);
328
329   /* Persona list */
330   scrolled_window = gtk_scrolled_window_new (NULL, NULL);
331   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
332       GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
333   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
334       GTK_SHADOW_IN);
335
336   priv->persona_store = empathy_persona_store_new (priv->new_individual);
337   empathy_persona_store_set_show_protocols (priv->persona_store, TRUE);
338   persona_view = empathy_persona_view_new (priv->persona_store);
339   empathy_persona_view_set_show_offline (persona_view, TRUE);
340
341   gtk_container_add (GTK_CONTAINER (scrolled_window),
342       GTK_WIDGET (persona_view));
343   gtk_widget_show (GTK_WIDGET (persona_view));
344
345   gtk_box_pack_start (vbox, scrolled_window, TRUE, TRUE, 0);
346   gtk_widget_show (scrolled_window);
347
348   gtk_container_add (GTK_CONTAINER (alignment), GTK_WIDGET (vbox));
349   gtk_paned_pack2 (paned, alignment, TRUE, FALSE);
350   gtk_widget_show (GTK_WIDGET (vbox));
351
352   gtk_widget_show (GTK_WIDGET (paned));
353
354   /* Footer label */
355   label = gtk_label_new (NULL);
356   tmp = g_strdup_printf ("<i>%s</i>",
357       _("Contacts selected in the list on the left will be linked together."));
358   gtk_label_set_markup (GTK_LABEL (label), tmp);
359   g_free (tmp);
360   gtk_widget_show (label);
361
362   gtk_box_pack_start (GTK_BOX (top_vbox), GTK_WIDGET (paned), TRUE, TRUE, 0);
363   gtk_box_pack_start (GTK_BOX (top_vbox), label, FALSE, TRUE, 0);
364
365   /* Add the main vbox to the bin */
366   gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (top_vbox));
367   gtk_widget_show (GTK_WIDGET (top_vbox));
368 }
369
370 static void
371 empathy_individual_linker_init (EmpathyIndividualLinker *self)
372 {
373   EmpathyIndividualLinkerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
374       EMPATHY_TYPE_INDIVIDUAL_LINKER, EmpathyIndividualLinkerPriv);
375
376   self->priv = priv;
377
378   priv->changed_individuals = g_hash_table_new (NULL, NULL);
379
380   set_up (self);
381 }
382
383 static void
384 get_property (GObject *object,
385     guint param_id,
386     GValue *value,
387     GParamSpec *pspec)
388 {
389   EmpathyIndividualLinkerPriv *priv;
390
391   priv = GET_PRIV (object);
392
393   switch (param_id)
394     {
395       case PROP_START_INDIVIDUAL:
396         g_value_set_object (value, priv->start_individual);
397         break;
398       default:
399         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
400         break;
401     }
402 }
403
404 static void
405 set_property (GObject *object,
406     guint param_id,
407     const GValue *value,
408     GParamSpec *pspec)
409 {
410   EmpathyIndividualLinkerPriv *priv;
411
412   priv = GET_PRIV (object);
413
414   switch (param_id)
415     {
416       case PROP_START_INDIVIDUAL:
417         empathy_individual_linker_set_start_individual (
418             EMPATHY_INDIVIDUAL_LINKER (object), g_value_get_object (value));
419         break;
420       default:
421         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
422         break;
423     }
424 }
425
426 static void
427 dispose (GObject *object)
428 {
429   EmpathyIndividualLinkerPriv *priv = GET_PRIV (object);
430
431   tp_clear_object (&priv->individual_store);
432   tp_clear_object (&priv->persona_store);
433   tp_clear_object (&priv->start_individual);
434   tp_clear_object (&priv->new_individual);
435
436   G_OBJECT_CLASS (empathy_individual_linker_parent_class)->dispose (object);
437 }
438
439 static void
440 finalize (GObject *object)
441 {
442   EmpathyIndividualLinkerPriv *priv = GET_PRIV (object);
443
444   g_hash_table_destroy (priv->changed_individuals);
445
446   G_OBJECT_CLASS (empathy_individual_linker_parent_class)->finalize (object);
447 }
448
449 static void
450 size_request (GtkWidget *widget,
451     GtkRequisition *requisition)
452 {
453   GtkBin *bin = GTK_BIN (widget);
454   GtkWidget *child;
455
456   requisition->width =
457       gtk_container_get_border_width (GTK_CONTAINER (widget)) * 2;
458   requisition->height =
459       gtk_container_get_border_width (GTK_CONTAINER (widget)) * 2;
460
461   child = gtk_bin_get_child (bin);
462
463   if (child && gtk_widget_get_visible (child))
464     {
465       GtkRequisition child_requisition;
466
467       gtk_widget_size_request (child, &child_requisition);
468
469       requisition->width += child_requisition.width;
470       requisition->height += child_requisition.height;
471     }
472 }
473
474 static void
475 size_allocate (GtkWidget *widget,
476     GtkAllocation *allocation)
477 {
478   GtkBin *bin = GTK_BIN (widget);
479   GtkAllocation child_allocation;
480   GtkWidget *child;
481
482   gtk_widget_set_allocation (widget, allocation);
483
484   child = gtk_bin_get_child (bin);
485
486   if (child && gtk_widget_get_visible (child))
487     {
488       child_allocation.x = allocation->x +
489           gtk_container_get_border_width (GTK_CONTAINER (widget));
490       child_allocation.y = allocation->y +
491           gtk_container_get_border_width (GTK_CONTAINER (widget));
492       child_allocation.width = MAX (allocation->width -
493           gtk_container_get_border_width (GTK_CONTAINER (widget)) * 2, 0);
494       child_allocation.height = MAX (allocation->height -
495           gtk_container_get_border_width (GTK_CONTAINER (widget)) * 2, 0);
496
497       gtk_widget_size_allocate (child, &child_allocation);
498     }
499 }
500
501 static void
502 empathy_individual_linker_class_init (EmpathyIndividualLinkerClass *klass)
503 {
504   GObjectClass *object_class = G_OBJECT_CLASS (klass);
505   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
506
507   object_class->get_property = get_property;
508   object_class->set_property = set_property;
509   object_class->dispose = dispose;
510   object_class->finalize = finalize;
511
512   widget_class->size_request = size_request;
513   widget_class->size_allocate = size_allocate;
514
515   /**
516    * EmpathyIndividualLinker:start-individual:
517    *
518    * The #FolksIndividual to link other individuals to. This individual is
519    * selected by default in the list of individuals, and cannot be unselected.
520    * This ensures that empathy_individual_linker_get_linked_personas() will
521    * always return at least one persona to link.
522    */
523   g_object_class_install_property (object_class, PROP_START_INDIVIDUAL,
524       g_param_spec_object ("start-individual",
525           "Start Individual",
526           "The #FolksIndividual to link other individuals to.",
527           FOLKS_TYPE_INDIVIDUAL,
528           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
529
530   g_type_class_add_private (object_class, sizeof (EmpathyIndividualLinkerPriv));
531 }
532
533 /**
534  * empathy_individual_linker_new:
535  * @start_individual: (allow-none): the #FolksIndividual to link to, or %NULL
536  *
537  * Creates a new #EmpathyIndividualLinker.
538  *
539  * Return value: a new #EmpathyIndividualLinker
540  */
541 GtkWidget *
542 empathy_individual_linker_new (FolksIndividual *start_individual)
543 {
544   g_return_val_if_fail (start_individual == NULL ||
545       FOLKS_IS_INDIVIDUAL (start_individual), NULL);
546
547   return g_object_new (EMPATHY_TYPE_INDIVIDUAL_LINKER,
548       "start-individual", start_individual,
549       NULL);
550 }
551
552 /**
553  * empathy_individual_linker_get_start_individual:
554  * @self: an #EmpathyIndividualLinker
555  *
556  * Get the value of #EmpathyIndividualLinker:start-individual.
557  *
558  * Return value: (transfer none): the start individual for linking, or %NULL
559  */
560 FolksIndividual *
561 empathy_individual_linker_get_start_individual (EmpathyIndividualLinker *self)
562 {
563   g_return_val_if_fail (EMPATHY_IS_INDIVIDUAL_LINKER (self), NULL);
564
565   return GET_PRIV (self)->start_individual;
566 }
567
568 /**
569  * empathy_individual_linker_set_start_individual:
570  * @self: an #EmpathyIndividualLinker
571  * @individual: (allow-none): the start individual, or %NULL
572  *
573  * Set the value of #EmpathyIndividualLinker:start-individual to @individual.
574  */
575 void
576 empathy_individual_linker_set_start_individual (EmpathyIndividualLinker *self,
577     FolksIndividual *individual)
578 {
579   EmpathyIndividualLinkerPriv *priv;
580
581   g_return_if_fail (EMPATHY_IS_INDIVIDUAL_LINKER (self));
582   g_return_if_fail (individual == NULL || FOLKS_IS_INDIVIDUAL (individual));
583
584   priv = GET_PRIV (self);
585
586   tp_clear_object (&priv->start_individual);
587   tp_clear_object (&priv->new_individual);
588   g_hash_table_remove_all (priv->changed_individuals);
589
590   if (individual != NULL)
591     {
592       priv->start_individual = g_object_ref (individual);
593       priv->new_individual = folks_individual_new (
594           folks_individual_get_personas (individual));
595       empathy_individual_view_set_store (priv->individual_view,
596           priv->individual_store);
597     }
598   else
599     {
600       priv->start_individual = NULL;
601       priv->new_individual = NULL;
602
603       /* We only display Individuals in the individual view if we have a
604        * new_individual to link them into */
605       empathy_individual_view_set_store (priv->individual_view, NULL);
606     }
607
608   empathy_individual_widget_set_individual (
609       EMPATHY_INDIVIDUAL_WIDGET (priv->preview_widget), priv->new_individual);
610   empathy_persona_store_set_individual (priv->persona_store,
611       priv->new_individual);
612
613   g_object_notify (G_OBJECT (self), "start-individual");
614 }
615
616 /**
617  * empathy_individual_linker_get_linked_personas:
618  * @self: an #EmpathyIndividualLinker
619  *
620  * Return a list of the #FolksPersona<!-- -->s which comprise the linked
621  * individual currently displayed in the widget.
622  *
623  * The return value is guaranteed to contain at least one element.
624  *
625  * Return value: (transfer none) (element-type Folks.Persona): a list of
626  * #FolksPersona<!-- -->s to link together
627  */
628 GList *
629 empathy_individual_linker_get_linked_personas (EmpathyIndividualLinker *self)
630 {
631   EmpathyIndividualLinkerPriv *priv;
632   GList *personas;
633
634   g_return_val_if_fail (EMPATHY_IS_INDIVIDUAL_LINKER (self), NULL);
635
636   priv = GET_PRIV (self);
637
638   if (priv->new_individual == NULL)
639     return NULL;
640
641   personas = folks_individual_get_personas (priv->new_individual);
642   g_assert (personas != NULL);
643   return personas;
644 }