Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / libedataserverui / e-source-option-menu.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* e-source-option-menu.c
3  *
4  * Copyright (C) 2003  Novell, Inc.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of version 2 of the GNU Lesser General Public
8  * License as published by the Free Software Foundation.
9  *
10  * This program 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  * 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 program; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  * Author: Ettore Perazzoli <ettore@ximian.com>
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <gtk/gtkmenu.h>
28 #include <gtk/gtkmenuitem.h>
29 #include <gtk/gtkimagemenuitem.h>
30
31 #include "e-source-option-menu.h"
32
33 /* We set data on each menu item specifying the corresponding ESource using this key.  */
34 #define MENU_ITEM_SOURCE_DATA_ID        "ESourceOptionMenu:Source"
35
36
37 struct _ESourceOptionMenuPrivate {
38         ESourceList *source_list;
39
40         ESource *selected_source;
41 };
42
43 typedef struct {
44         ESourceOptionMenu *option_menu;
45         ESource *source;
46         ESource *found_source;
47         int i;
48 } ForeachMenuItemData;
49
50 enum {
51         SOURCE_SELECTED,
52         NUM_SIGNALS
53 };
54
55 static guint signals[NUM_SIGNALS] = { 0 };
56
57 G_DEFINE_TYPE (ESourceOptionMenu, e_source_option_menu, GTK_TYPE_OPTION_MENU)
58
59 /* Selecting a source.  */
60 static void
61 select_source_foreach_menu_item (GtkWidget *menu_item,
62                                  ForeachMenuItemData *data)
63 {
64         ESource *source = gtk_object_get_data (GTK_OBJECT (menu_item), MENU_ITEM_SOURCE_DATA_ID);
65
66         if (data->found_source)
67                 return;
68
69         if (source && e_source_equal (source, data->source)) {
70                 data->found_source = source;
71                 gtk_option_menu_set_history (GTK_OPTION_MENU (data->option_menu), data->i);
72         }
73
74         data->i ++;
75 }
76
77 static void
78 select_source (ESourceOptionMenu *menu,
79                ESource *source)
80 {
81         ForeachMenuItemData *foreach_data;
82
83         foreach_data = g_new0 (ForeachMenuItemData, 1);
84         foreach_data->option_menu = menu;
85         foreach_data->source = source;
86
87         gtk_container_foreach (GTK_CONTAINER (GTK_OPTION_MENU (menu)->menu),
88                                (GtkCallback) select_source_foreach_menu_item, foreach_data);
89
90         if (foreach_data->found_source) {
91                 menu->priv->selected_source = foreach_data->found_source;
92                 g_signal_emit (menu, signals[SOURCE_SELECTED], 0, foreach_data->found_source);
93         }
94
95         g_free (foreach_data);
96 }
97
98
99 /* Menu callback.  */
100
101 static void
102 menu_item_activate_callback (GtkMenuItem *menu_item,
103                              ESourceOptionMenu *option_menu)
104 {
105         ESource *source = gtk_object_get_data (GTK_OBJECT (menu_item), MENU_ITEM_SOURCE_DATA_ID);
106
107         if (source != NULL)
108                 select_source (option_menu, source);
109 }
110
111
112 /* Functions to keep the menu in sync with the ESourceList.  */
113
114 static void
115 populate (ESourceOptionMenu *option_menu)
116 {
117         GtkWidget *menu = gtk_menu_new ();
118         GSList *groups = e_source_list_peek_groups (option_menu->priv->source_list);
119         GSList *p;
120         ESource *first_source = NULL;
121         int first_source_item = -1;
122         int selected_item = -1;
123         int i;
124
125         i = 0;
126         for (p = groups; p != NULL; p = p->next) {
127                 ESourceGroup *group = E_SOURCE_GROUP (p->data);
128                 GtkWidget *item1 = gtk_menu_item_new_with_label (e_source_group_peek_name (group));
129                 GSList *q;
130
131                 gtk_widget_set_sensitive (item1, FALSE);
132                 gtk_widget_show (item1);
133                 gtk_menu_append (GTK_MENU (menu), item1);
134
135                 i ++;
136
137                 for (q = e_source_group_peek_sources (group); q != NULL; q = q->next) {
138                         ESource *source = E_SOURCE (q->data);
139                         char *label = g_strconcat ("    ", e_source_peek_name (source), NULL);
140                         const char *colour = e_source_peek_color_spec (source);
141                         GtkWidget *item2 = gtk_image_menu_item_new_with_label (label);
142                         g_free (label);
143
144                         if (colour) {
145                                 GdkPixmap *pixmap;
146                                 GdkColor c;
147                                 GdkGC *gc;
148
149                                 pixmap = gdk_pixmap_new (gdk_get_default_root_window (), 16, 16, -1);
150                                 gdk_color_parse (colour, &c);
151                                 gdk_colormap_alloc_color (gdk_colormap_get_system(), &c, FALSE, TRUE);
152
153                                 gc = gdk_gc_new (gdk_get_default_root_window ());
154                                 gdk_gc_set_foreground (gc, &c);
155                                 gdk_draw_rectangle (pixmap, gc, TRUE, 0, 0, 16, 16);
156                                 g_object_unref (gc);
157
158                                 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item2), gtk_image_new_from_pixmap (pixmap, NULL));
159                         }
160
161                         gtk_object_set_data_full (GTK_OBJECT (item2), MENU_ITEM_SOURCE_DATA_ID, source,
162                                                   (GtkDestroyNotify) g_object_unref);
163                         g_object_ref (source);
164
165                         g_signal_connect (item2, "activate", G_CALLBACK (menu_item_activate_callback), option_menu);
166
167                         gtk_widget_show (item2);
168                         gtk_menu_append (GTK_MENU (menu), item2);
169
170                         if (first_source_item == -1) {
171                                 first_source_item = i;
172                                 first_source = source;
173                         }
174
175                         if (source == option_menu->priv->selected_source)
176                                 selected_item = i;
177
178                         i ++;
179                 }
180         }
181
182         gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu);
183
184         if (selected_item != -1) {
185                 gtk_option_menu_set_history (GTK_OPTION_MENU (option_menu), selected_item);
186         } else {
187                 if (option_menu->priv->selected_source != NULL)
188                         g_object_unref (option_menu->priv->selected_source);
189                 option_menu->priv->selected_source = first_source;
190                 if (option_menu->priv->selected_source != NULL)
191                         g_object_ref (option_menu->priv->selected_source);
192
193                 gtk_option_menu_set_history (GTK_OPTION_MENU (option_menu), first_source_item);
194         }
195 }
196
197
198 static void
199 source_list_changed_callback (ESourceList *list,
200                               ESourceOptionMenu *menu)
201 {
202         populate (menu);
203 }
204
205 static void
206 connect_signals (ESourceOptionMenu *menu)
207 {
208         g_signal_connect_object (menu->priv->source_list, "changed",
209                                  G_CALLBACK (source_list_changed_callback), G_OBJECT (menu), 0);
210 }
211
212
213 /* GObject methods.  */
214
215 static void
216 e_source_option_menu_dispose (GObject *object)
217 {
218         ESourceOptionMenuPrivate *priv = E_SOURCE_OPTION_MENU (object)->priv;
219
220         if (priv->source_list != NULL) {
221                 g_object_unref (priv->source_list);
222                 priv->source_list = NULL;
223         }
224
225         if (priv->selected_source != NULL) {
226                 g_object_unref (priv->selected_source);
227                 priv->selected_source = NULL;
228         }
229
230         (* G_OBJECT_CLASS (e_source_option_menu_parent_class)->dispose) (object);
231 }
232
233 static void
234 e_source_option_menu_finalize (GObject *object)
235 {
236         ESourceOptionMenuPrivate *priv = E_SOURCE_OPTION_MENU (object)->priv;
237
238         g_free (priv);
239
240         (* G_OBJECT_CLASS (e_source_option_menu_parent_class)->finalize) (object);
241 }
242
243
244 /* Initialization.  */
245
246 static void
247 e_source_option_menu_class_init (ESourceOptionMenuClass *class)
248 {
249         GObjectClass *object_class = G_OBJECT_CLASS (class);
250
251         object_class->dispose  = e_source_option_menu_dispose;
252         object_class->finalize = e_source_option_menu_finalize;
253
254         signals[SOURCE_SELECTED] = 
255                 g_signal_new ("source_selected",
256                               G_OBJECT_CLASS_TYPE (object_class),
257                               G_SIGNAL_RUN_LAST,
258                               G_STRUCT_OFFSET (ESourceOptionMenuClass, source_selected),
259                               NULL, NULL,
260                               g_cclosure_marshal_VOID__POINTER,
261                               G_TYPE_NONE, 1,
262                               G_TYPE_POINTER);
263 }
264
265 static void
266 e_source_option_menu_init (ESourceOptionMenu *source_option_menu)
267 {
268         ESourceOptionMenuPrivate *priv;
269
270         priv = g_new0 (ESourceOptionMenuPrivate, 1);
271
272         source_option_menu->priv = priv;
273 }
274
275
276 /* Public methods.  */
277
278 /**
279  * e_source_option_menu_new:
280  * @source_list: an #ESourceList to choose from
281  *
282  * Creates a new #ESourceOptionMenu widget that lets the user pick
283  * an #ESource from the provided #ESourceList.
284  *
285  * Return value: A new #ESourceOptionMenu.
286  **/
287 GtkWidget *
288 e_source_option_menu_new (ESourceList *source_list)
289 {
290         ESourceOptionMenu *menu;
291
292         g_return_val_if_fail (E_IS_SOURCE_LIST (source_list), NULL);
293
294         menu = g_object_new (e_source_option_menu_get_type (), NULL);
295
296         menu->priv->source_list = source_list;
297         g_object_ref (source_list);
298
299         connect_signals (menu);
300         populate (menu);
301
302         return GTK_WIDGET (menu);
303 }
304
305 /**
306  * e_source_option_menu_peek_selected:
307  * @menu: an #ESourceOptionMenu
308  *
309  * Return value: The selected #ESource, or %NULL if none was selected.
310  **/
311 ESource *
312 e_source_option_menu_peek_selected  (ESourceOptionMenu *menu)
313 {
314         g_return_val_if_fail (E_IS_SOURCE_OPTION_MENU (menu), NULL);
315
316         return menu->priv->selected_source;
317 }
318
319 /**
320  * e_source_option_menu_select:
321  * @menu: an #ESourceOptionMenu
322  * @source: an #ESource to select
323  *
324  * Programmatically selects a source in @menu. @source must be present
325  * in @menu's #ESourceList.
326  **/
327 void
328 e_source_option_menu_select (ESourceOptionMenu *menu,
329                              ESource *source)
330 {
331         g_return_if_fail (E_IS_SOURCE_OPTION_MENU (menu));
332         g_return_if_fail (E_IS_SOURCE (source));
333
334         select_source (menu, source);
335 }