]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-contact-selector.c
Added argument checking to non-static functions.
[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 changed_cb (GtkComboBox *widget, gpointer data);
50
51
52 EmpathyContact *
53 empathy_contact_selector_get_selected (EmpathyContactSelector *selector)
54 {
55   EmpathyContactSelectorPriv *priv = GET_PRIV (selector);
56   EmpathyContact *contact = NULL;
57   GtkTreeIter iter;
58
59   g_return_val_if_fail (EMPATHY_IS_CONTACT_SELECTOR (selector), NULL);
60
61   if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (selector), &iter))
62     return NULL;
63
64   gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
65       EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, &contact, -1);
66
67   return contact;
68 }
69
70
71 static guint
72 get_number_online_contacts (GtkTreeStore *store)
73 {
74   GtkTreePath *path;
75   GtkTreeIter tmp_iter;
76   gboolean is_online;
77   guint number_online_contacts = 0;
78
79   path = gtk_tree_path_new_first ();
80
81   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &tmp_iter, path))
82     {
83       do
84         {
85           gtk_tree_model_get (GTK_TREE_MODEL (store),
86               &tmp_iter, EMPATHY_CONTACT_LIST_STORE_COL_IS_ONLINE,
87               &is_online, -1);
88           if (is_online)
89             number_online_contacts++;
90         } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &tmp_iter));
91     }
92
93   gtk_tree_path_free (path);
94
95   return number_online_contacts;
96 }
97
98
99 static gboolean
100 get_iter_for_blank_contact (GtkTreeStore *store,
101                             GtkTreeIter *blank_iter)
102 {
103   GtkTreePath *path;
104   GtkTreeIter tmp_iter;
105   EmpathyContact *tmp_contact;
106   gboolean is_present = FALSE;
107
108   path = gtk_tree_path_new_first ();
109
110   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &tmp_iter, path))
111     {
112       do
113         {
114           gtk_tree_model_get (GTK_TREE_MODEL (store),
115               &tmp_iter, EMPATHY_CONTACT_LIST_STORE_COL_CONTACT,
116               &tmp_contact, -1);
117           if (tmp_contact == NULL)
118             {
119               *blank_iter = tmp_iter;
120               is_present = TRUE;
121               break;
122             }
123         } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &tmp_iter));
124     }
125
126   gtk_tree_path_free (path);
127
128   return is_present;
129 }
130
131
132 static void
133 add_blank_contact (EmpathyContactSelector *selector)
134 {
135   EmpathyContactSelectorPriv *priv = GET_PRIV (selector);
136   GtkTreeIter blank_iter;
137
138   gtk_tree_store_insert (GTK_TREE_STORE (priv->store), &blank_iter, NULL, 0);
139   gtk_tree_store_set (GTK_TREE_STORE (priv->store), &blank_iter,
140       EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, NULL,
141       EMPATHY_CONTACT_LIST_STORE_COL_NAME, (_("Select a contact")),
142       EMPATHY_CONTACT_LIST_STORE_COL_IS_ONLINE, FALSE, -1);
143   g_signal_handlers_block_by_func(selector, changed_cb, NULL);
144   gtk_combo_box_set_active_iter (GTK_COMBO_BOX (selector), &blank_iter);
145   g_signal_handlers_unblock_by_func(selector, changed_cb, NULL);
146 }
147
148
149 static void
150 remove_blank_contact (EmpathyContactSelector *selector)
151 {
152   EmpathyContactSelectorPriv *priv = GET_PRIV (selector);
153   GtkTreeIter blank_iter;
154
155   if (get_iter_for_blank_contact (GTK_TREE_STORE (priv->store), &blank_iter))
156     {
157       gtk_tree_store_remove (GTK_TREE_STORE (priv->store), &blank_iter);
158     }
159 }
160
161
162 static void
163 manage_sensitivity (EmpathyContactSelector *selector)
164 {
165   EmpathyContactSelectorPriv *priv = GET_PRIV (selector);
166
167   /* FIXME - make this work when offline contacts are shown.
168    * The following value needs to be the number of entries shown
169    * excluding the blank entry (if present).
170    */
171   guint number_online_contacts =
172       get_number_online_contacts (GTK_TREE_STORE (priv->store));
173
174   if (number_online_contacts)
175       gtk_widget_set_sensitive (GTK_WIDGET (selector), TRUE);
176   else
177       gtk_widget_set_sensitive (GTK_WIDGET (selector), FALSE);
178 }
179
180
181 static void
182 manage_blank_contact (EmpathyContactSelector *selector)
183 {
184   gboolean is_popup_shown;
185
186   g_object_get (selector, "popup-shown", &is_popup_shown, NULL);
187
188   if (is_popup_shown)
189     {
190       remove_blank_contact (selector);
191     }
192   else
193     {
194       if (gtk_combo_box_get_active (GTK_COMBO_BOX (selector)) == -1)
195         {
196           add_blank_contact (selector);
197         }
198       else
199         {
200           remove_blank_contact (selector);
201         }
202     }
203
204     manage_sensitivity (selector);
205 }
206
207
208 static void
209 notify_popup_shown_cb (GtkComboBox *widget,
210                        GParamSpec *property,
211                        gpointer data)
212 {
213   EmpathyContactSelector *selector = EMPATHY_CONTACT_SELECTOR (widget);
214
215   manage_blank_contact (selector);
216 }
217
218
219 static void
220 changed_cb (GtkComboBox *widget,
221             gpointer data)
222 {
223   EmpathyContactSelector *selector = EMPATHY_CONTACT_SELECTOR (widget);
224
225   manage_blank_contact (selector);
226 }
227
228
229 static void
230 empathy_store_row_changed_cb (EmpathyContactListStore *empathy_store,
231                               GtkTreePath *empathy_path,
232                               GtkTreeIter *empathy_iter,
233                               gpointer data)
234 {
235   EmpathyContactSelector *selector = EMPATHY_CONTACT_SELECTOR (data);
236
237   manage_sensitivity (selector);
238 }
239
240
241 static GObject *
242 empathy_contact_selector_constructor (GType type,
243                                       guint n_construct_params,
244                                       GObjectConstructParam *construct_params)
245 {
246   GObject *object =
247       G_OBJECT_CLASS (empathy_contact_selector_parent_class)->constructor (type,
248       n_construct_params, construct_params);
249   EmpathyContactSelector *contact_selector = EMPATHY_CONTACT_SELECTOR (object);
250   EmpathyContactSelectorPriv *priv = GET_PRIV (contact_selector);
251   GtkCellRenderer *renderer;
252
253   g_object_set (priv->store, "is-compact", TRUE, "show-avatars", FALSE,
254       "show-offline", FALSE, "show-groups", FALSE,
255       "sort-criterium", EMPATHY_CONTACT_LIST_STORE_SORT_NAME, NULL);
256
257   g_signal_connect (priv->store, "row-changed",
258       G_CALLBACK (empathy_store_row_changed_cb), (gpointer) contact_selector);
259   g_signal_connect (GTK_COMBO_BOX (contact_selector), "changed",
260       G_CALLBACK (changed_cb), NULL);
261   g_signal_connect (GTK_COMBO_BOX (contact_selector), "notify::popup-shown",
262       G_CALLBACK (notify_popup_shown_cb), NULL);
263
264   gtk_combo_box_set_model (GTK_COMBO_BOX (contact_selector),
265       GTK_TREE_MODEL (priv->store));
266   gtk_widget_set_sensitive (GTK_WIDGET (contact_selector), FALSE);
267
268   renderer = gtk_cell_renderer_pixbuf_new ();
269   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (contact_selector),
270       renderer, FALSE);
271   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (contact_selector), renderer,
272       "icon-name", EMPATHY_CONTACT_LIST_STORE_COL_ICON_STATUS, NULL);
273
274   renderer = gtk_cell_renderer_text_new ();
275   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (contact_selector),
276       renderer, TRUE);
277   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (contact_selector), renderer,
278       "text", EMPATHY_CONTACT_LIST_STORE_COL_NAME, NULL);
279
280   manage_blank_contact (contact_selector);
281   manage_sensitivity (contact_selector);
282
283   object = G_OBJECT (contact_selector);
284   return object;
285 }
286
287
288 static void
289 empathy_contact_selector_init (EmpathyContactSelector *empathy_contact_selector)
290 {
291   EmpathyContactSelectorPriv *priv =
292       G_TYPE_INSTANCE_GET_PRIVATE (empathy_contact_selector,
293       EMPATHY_TYPE_CONTACT_SELECTOR, EmpathyContactSelectorPriv);
294
295   empathy_contact_selector->priv = priv;
296 }
297
298
299 static void
300 empathy_contact_selector_set_property (GObject *object,
301                                        guint prop_id,
302                                        const GValue *value,
303                                        GParamSpec *pspec)
304 {
305   EmpathyContactSelector *contact_selector = EMPATHY_CONTACT_SELECTOR (object);
306   EmpathyContactSelectorPriv *priv = GET_PRIV (contact_selector);
307
308   switch (prop_id)
309     {
310       case PROP_STORE:
311         priv->store = g_value_dup_object (value);
312         break;
313       default:
314         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
315         break;
316     }
317 }
318
319
320 static void
321 empathy_contact_selector_get_property (GObject *object,
322                                        guint prop_id,
323                                        GValue *value,
324                                        GParamSpec *pspec)
325 {
326   EmpathyContactSelector *contact_selector = EMPATHY_CONTACT_SELECTOR (object);
327   EmpathyContactSelectorPriv *priv = GET_PRIV (contact_selector);
328
329   switch (prop_id)
330     {
331       case PROP_STORE:
332         g_value_set_object (value, priv->store);
333         break;
334       default:
335         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
336         break;
337     }
338 }
339
340
341 static void
342 empathy_contact_selector_dispose (GObject *object)
343 {
344   EmpathyContactSelector *selector = EMPATHY_CONTACT_SELECTOR (object);
345   EmpathyContactSelectorPriv *priv = GET_PRIV (selector);
346
347   if (priv->store)
348     {
349       g_object_unref (priv->store);
350       priv->store = NULL;
351     }
352
353   (G_OBJECT_CLASS (empathy_contact_selector_parent_class)->dispose) (object);
354 }
355
356
357 static void
358 empathy_contact_selector_class_init (EmpathyContactSelectorClass *klass)
359 {
360   GObjectClass *object_class = G_OBJECT_CLASS (klass);
361   object_class->constructor = empathy_contact_selector_constructor;
362   object_class->dispose = empathy_contact_selector_dispose;
363   object_class->set_property = empathy_contact_selector_set_property;
364   object_class->get_property = empathy_contact_selector_get_property;
365   g_type_class_add_private (klass, sizeof (EmpathyContactSelectorPriv));
366
367   g_object_class_install_property (object_class, PROP_STORE,
368       g_param_spec_object ("store", "store", "store",
369       EMPATHY_TYPE_CONTACT_LIST_STORE, G_PARAM_CONSTRUCT_ONLY |
370       G_PARAM_READWRITE | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
371 }
372
373
374 EmpathyContactSelector *
375 empathy_contact_selector_new (EmpathyContactListStore *store)
376 {
377   g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store), NULL);
378
379   return g_object_new (EMPATHY_TYPE_CONTACT_SELECTOR, "store", store, NULL);
380 }