]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-contact-selector.c
22221dd88023e38022a54379138de4bdf224fd55
[empathy.git] / libempathy-gtk / empathy-contact-selector.c
1 /*
2 *  Copyright (C) 2007 Marco Barisione <marco@barisione.org>
3 *  Copyright (C) 2008 Collabora Ltd.
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2.1 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 *
19 *  Authors: Marco Barisione <marco@barisione.org>
20 *           Elliot Fairweather <elliot.fairweather@collabora.co.uk>
21 */
22
23 #include "config.h"
24
25 #include <glib/gi18n.h>
26 #include <gtk/gtk.h>
27
28 #include <libempathy/empathy-contact.h>
29 #include <libempathy-gtk/empathy-contact-list-store.h>
30 #include <libempathy/empathy-utils.h>
31
32 #include "empathy-contact-selector.h"
33
34 G_DEFINE_TYPE (EmpathyContactSelector, empathy_contact_selector,
35     GTK_TYPE_COMBO_BOX)
36
37 enum
38 {
39   PROP_0,
40   PROP_STORE
41 };
42
43 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyContactSelector)
44 typedef struct
45 {
46   EmpathyContactListStore *store;
47 } EmpathyContactSelectorPriv;
48
49 static void contact_selector_changed_cb (GtkComboBox *widget, gpointer data);
50
51 EmpathyContact *
52 empathy_contact_selector_get_selected (EmpathyContactSelector *selector)
53 {
54   EmpathyContactSelectorPriv *priv = GET_PRIV (selector);
55   EmpathyContact *contact = NULL;
56   GtkTreeIter iter;
57
58   g_return_val_if_fail (EMPATHY_IS_CONTACT_SELECTOR (selector), NULL);
59
60   if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (selector), &iter))
61     return NULL;
62
63   gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
64       EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, &contact, -1);
65
66   return contact;
67 }
68
69 static guint
70 contact_selector_get_number_online_contacts (GtkTreeStore *store)
71 {
72   GtkTreePath *path;
73   GtkTreeIter tmp_iter;
74   gboolean is_online;
75   guint number_online_contacts = 0;
76
77   path = gtk_tree_path_new_first ();
78
79   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &tmp_iter, path))
80     {
81       do
82         {
83           gtk_tree_model_get (GTK_TREE_MODEL (store),
84               &tmp_iter, EMPATHY_CONTACT_LIST_STORE_COL_IS_ONLINE,
85               &is_online, -1);
86           if (is_online)
87             number_online_contacts++;
88         } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &tmp_iter));
89     }
90
91   gtk_tree_path_free (path);
92
93   return number_online_contacts;
94 }
95
96 static gboolean
97 contact_selector_get_iter_for_blank_contact (GtkTreeStore *store,
98                                              GtkTreeIter *blank_iter)
99 {
100   GtkTreePath *path;
101   GtkTreeIter tmp_iter;
102   EmpathyContact *tmp_contact;
103   gboolean is_present = FALSE;
104
105   path = gtk_tree_path_new_first ();
106
107   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &tmp_iter, path))
108     {
109       do
110         {
111           gtk_tree_model_get (GTK_TREE_MODEL (store),
112               &tmp_iter, EMPATHY_CONTACT_LIST_STORE_COL_CONTACT,
113               &tmp_contact, -1);
114           if (tmp_contact == NULL)
115             {
116               *blank_iter = tmp_iter;
117               is_present = TRUE;
118               break;
119             }
120         } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &tmp_iter));
121     }
122
123   gtk_tree_path_free (path);
124
125   return is_present;
126 }
127
128 static void
129 contact_selector_add_blank_contact (EmpathyContactSelector *selector)
130 {
131   EmpathyContactSelectorPriv *priv = GET_PRIV (selector);
132   GtkTreeIter blank_iter;
133
134   gtk_tree_store_insert (GTK_TREE_STORE (priv->store), &blank_iter, NULL, 0);
135   gtk_tree_store_set (GTK_TREE_STORE (priv->store), &blank_iter,
136       EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, NULL,
137       EMPATHY_CONTACT_LIST_STORE_COL_NAME, (_("Select a contact")),
138       EMPATHY_CONTACT_LIST_STORE_COL_IS_ONLINE, FALSE, -1);
139   g_signal_handlers_block_by_func (selector,
140       contact_selector_changed_cb, NULL);
141   gtk_combo_box_set_active_iter (GTK_COMBO_BOX (selector), &blank_iter);
142   g_signal_handlers_unblock_by_func (selector,
143       contact_selector_changed_cb, NULL);
144 }
145
146 static void
147 contact_selector_remove_blank_contact (EmpathyContactSelector *selector)
148 {
149   EmpathyContactSelectorPriv *priv = GET_PRIV (selector);
150   GtkTreeIter blank_iter;
151
152   if (contact_selector_get_iter_for_blank_contact (
153         GTK_TREE_STORE (priv->store), &blank_iter))
154     gtk_tree_store_remove (GTK_TREE_STORE (priv->store), &blank_iter);
155 }
156
157 static void
158 contact_selector_manage_sensitivity (EmpathyContactSelector *selector)
159 {
160   EmpathyContactSelectorPriv *priv = GET_PRIV (selector);
161
162   /* FIXME - make this work when offline contacts are shown.
163    * The following value needs to be the number of entries shown
164    * excluding the blank entry (if present).
165    */
166   guint number_online_contacts = contact_selector_get_number_online_contacts (
167       GTK_TREE_STORE (priv->store));
168
169   if (number_online_contacts)
170     gtk_widget_set_sensitive (GTK_WIDGET (selector), TRUE);
171   else
172     gtk_widget_set_sensitive (GTK_WIDGET (selector), FALSE);
173 }
174
175 static void
176 contact_selector_manage_blank_contact (EmpathyContactSelector *selector)
177 {
178   gboolean is_popup_shown;
179
180   g_object_get (selector, "popup-shown", &is_popup_shown, NULL);
181
182   if (is_popup_shown)
183     {
184       contact_selector_remove_blank_contact (selector);
185     }
186   else
187     {
188       if (gtk_combo_box_get_active (GTK_COMBO_BOX (selector)) == -1)
189         {
190           contact_selector_add_blank_contact (selector);
191         }
192       else
193         {
194           contact_selector_remove_blank_contact (selector);
195         }
196     }
197
198     contact_selector_manage_sensitivity (selector);
199 }
200
201 static void
202 contact_selector_notify_popup_shown_cb (GtkComboBox *widget,
203                                         GParamSpec *property,
204                                         gpointer data)
205 {
206   EmpathyContactSelector *selector = EMPATHY_CONTACT_SELECTOR (widget);
207
208   contact_selector_manage_blank_contact (selector);
209 }
210
211 static void
212 contact_selector_changed_cb (GtkComboBox *widget,
213                              gpointer data)
214 {
215   EmpathyContactSelector *selector = EMPATHY_CONTACT_SELECTOR (widget);
216
217   contact_selector_manage_blank_contact (selector);
218 }
219
220 static void
221 contact_selector_store_row_changed_cb (EmpathyContactListStore *empathy_store,
222                                        GtkTreePath *empathy_path,
223                                        GtkTreeIter *empathy_iter,
224                                        gpointer data)
225 {
226   EmpathyContactSelector *selector = EMPATHY_CONTACT_SELECTOR (data);
227
228   contact_selector_manage_sensitivity (selector);
229 }
230
231
232 static GObject *
233 contact_selector_constructor (GType type,
234                               guint n_construct_params,
235                               GObjectConstructParam *construct_params)
236 {
237   GObject *object =
238       G_OBJECT_CLASS (empathy_contact_selector_parent_class)->constructor (
239           type, n_construct_params, construct_params);
240   EmpathyContactSelector *contact_selector = EMPATHY_CONTACT_SELECTOR (object);
241   EmpathyContactSelectorPriv *priv = GET_PRIV (contact_selector);
242   GtkCellRenderer *renderer;
243
244   g_object_set (priv->store, "is-compact", TRUE, "show-avatars", FALSE,
245       "show-offline", FALSE, "show-groups", FALSE,
246       "sort-criterium", EMPATHY_CONTACT_LIST_STORE_SORT_NAME, NULL);
247
248   g_signal_connect (priv->store, "row-changed",
249       G_CALLBACK (contact_selector_store_row_changed_cb),
250       (gpointer) contact_selector);
251   g_signal_connect (GTK_COMBO_BOX (contact_selector), "changed",
252       G_CALLBACK (contact_selector_changed_cb), NULL);
253   g_signal_connect (GTK_COMBO_BOX (contact_selector), "notify::popup-shown",
254       G_CALLBACK (contact_selector_notify_popup_shown_cb), NULL);
255
256   gtk_combo_box_set_model (GTK_COMBO_BOX (contact_selector),
257       GTK_TREE_MODEL (priv->store));
258   gtk_widget_set_sensitive (GTK_WIDGET (contact_selector), FALSE);
259
260   renderer = gtk_cell_renderer_pixbuf_new ();
261   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (contact_selector),
262       renderer, FALSE);
263   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (contact_selector), renderer,
264       "icon-name", EMPATHY_CONTACT_LIST_STORE_COL_ICON_STATUS, NULL);
265
266   renderer = gtk_cell_renderer_text_new ();
267   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (contact_selector),
268       renderer, TRUE);
269   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (contact_selector), renderer,
270       "text", EMPATHY_CONTACT_LIST_STORE_COL_NAME, NULL);
271
272   contact_selector_manage_blank_contact (contact_selector);
273   contact_selector_manage_sensitivity (contact_selector);
274
275   object = G_OBJECT (contact_selector);
276   return object;
277 }
278
279 static void
280 empathy_contact_selector_init (EmpathyContactSelector *empathy_contact_selector)
281 {
282   EmpathyContactSelectorPriv *priv =
283       G_TYPE_INSTANCE_GET_PRIVATE (empathy_contact_selector,
284       EMPATHY_TYPE_CONTACT_SELECTOR, EmpathyContactSelectorPriv);
285
286   empathy_contact_selector->priv = priv;
287 }
288
289 static void
290 contact_selector_set_property (GObject *object,
291                                guint prop_id,
292                                const GValue *value,
293                                GParamSpec *pspec)
294 {
295   EmpathyContactSelector *contact_selector = EMPATHY_CONTACT_SELECTOR (object);
296   EmpathyContactSelectorPriv *priv = GET_PRIV (contact_selector);
297
298   switch (prop_id)
299     {
300       case PROP_STORE:
301         priv->store = g_value_dup_object (value);
302         break;
303       default:
304         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
305         break;
306     }
307 }
308
309 static void
310 contact_selector_get_property (GObject *object,
311                                guint prop_id,
312                                GValue *value,
313                                GParamSpec *pspec)
314 {
315   EmpathyContactSelector *contact_selector = EMPATHY_CONTACT_SELECTOR (object);
316   EmpathyContactSelectorPriv *priv = GET_PRIV (contact_selector);
317
318   switch (prop_id)
319     {
320       case PROP_STORE:
321         g_value_set_object (value, priv->store);
322         break;
323       default:
324         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
325         break;
326     }
327 }
328
329 static void
330 contact_selector_dispose (GObject *object)
331 {
332   EmpathyContactSelector *selector = EMPATHY_CONTACT_SELECTOR (object);
333   EmpathyContactSelectorPriv *priv = GET_PRIV (selector);
334
335   if (priv->store)
336     {
337       g_object_unref (priv->store);
338       priv->store = NULL;
339     }
340
341   (G_OBJECT_CLASS (empathy_contact_selector_parent_class)->dispose) (object);
342 }
343
344 static void
345 empathy_contact_selector_class_init (EmpathyContactSelectorClass *klass)
346 {
347   GObjectClass *object_class = G_OBJECT_CLASS (klass);
348   object_class->constructor = contact_selector_constructor;
349   object_class->dispose = contact_selector_dispose;
350   object_class->set_property = contact_selector_set_property;
351   object_class->get_property = contact_selector_get_property;
352   g_type_class_add_private (klass, sizeof (EmpathyContactSelectorPriv));
353
354   g_object_class_install_property (object_class, PROP_STORE,
355       g_param_spec_object ("store", "store", "store",
356       EMPATHY_TYPE_CONTACT_LIST_STORE, G_PARAM_CONSTRUCT_ONLY |
357       G_PARAM_READWRITE | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
358 }
359
360 EmpathyContactSelector *
361 empathy_contact_selector_new (EmpathyContactListStore *store)
362 {
363   g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store), NULL);
364
365   return g_object_new (EMPATHY_TYPE_CONTACT_SELECTOR, "store", store, NULL);
366 }