Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / libedataserverui / e-name-selector.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /* e-name-selector.c - Unified context for contact/destination selection UI.
4  *
5  * Copyright (C) 2004 Novell, Inc.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of version 2 of the GNU Lesser General Public
9  * License as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * Authors: Hans Petter Jansson <hpj@novell.com>
21  */
22
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26
27 #include <string.h>
28 #include <glib.h>
29 #include <gtk/gtkalignment.h>
30 #include <gtk/gtkentry.h>
31 #include <gtk/gtklabel.h>
32 #include <gtk/gtkstock.h>
33 #include <glib/gi18n-lib.h>
34 #include <libebook/e-book.h>
35 #include <libebook/e-contact.h>
36 #include <libedataserverui/e-contact-store.h>
37 #include <libedataserverui/e-destination-store.h>
38 #include <libedataserverui/e-book-auth-util.h>
39 #include "e-name-selector.h"
40
41 #define PRIVATE_SOURCE_BOOKS_KEY "private-source-books"
42
43 typedef struct {
44         gchar              *name;
45         ENameSelectorEntry *entry;
46 }
47 Section;
48
49 typedef struct {
50         EBook *book;
51         guint  is_completion_book : 1;
52 }
53 SourceBook;
54
55 static void  e_name_selector_init       (ENameSelector           *name_selector);
56 static void  e_name_selector_class_init (ENameSelectorClass      *name_selector_class);
57 static void  e_name_selector_finalize   (GObject                 *object);
58
59 /* ------------------ *
60  * Class/object setup *
61  * ------------------ */
62
63 G_DEFINE_TYPE (ENameSelector, e_name_selector, G_TYPE_OBJECT);
64
65 static void
66 source_books_destroy (GArray *source_books)
67 {
68         gint i;
69
70         for (i = 0; i < source_books->len; i++) {
71                 SourceBook *source_book = &g_array_index (source_books, SourceBook, i);
72
73                 g_object_unref (source_book->book);
74         }
75
76         g_array_free (source_books, TRUE);
77 }
78
79 static void
80 e_name_selector_class_init (ENameSelectorClass *name_selector_class)
81 {
82         GObjectClass *object_class;
83
84         object_class = G_OBJECT_CLASS (name_selector_class);
85
86         object_class->finalize = e_name_selector_finalize;
87 }
88
89 static void
90 e_name_selector_init (ENameSelector *name_selector)
91 {
92         ESourceList *source_list;
93         GArray      *source_books;
94         GSList      *groups;
95         GSList      *l;
96
97         name_selector->sections = g_array_new (FALSE, FALSE, sizeof (Section));
98         name_selector->model = e_name_selector_model_new ();
99
100         /* Make a list of books */
101
102         source_books = g_array_new (FALSE, FALSE, sizeof (SourceBook));
103
104         /* This should be a private field, but we use g_object_set_data() to maintain
105          * ABI compatibility in the GNOME 2.10 branch */
106         g_object_set_data_full (G_OBJECT (name_selector), PRIVATE_SOURCE_BOOKS_KEY, source_books,
107                                 (GDestroyNotify) source_books_destroy);
108
109         if (!e_book_get_addressbooks (&source_list, NULL)) {
110                 g_warning ("ENameSelector can't find any addressbooks!");
111                 return;
112         }
113
114         groups = e_source_list_peek_groups (source_list);
115
116         for (l = groups; l; l = g_slist_next (l)) {
117                 ESourceGroup *group   = l->data;
118                 GSList       *sources = e_source_group_peek_sources (group);
119                 GSList       *m;
120
121                 for (m = sources; m; m = g_slist_next (m)) {
122                         ESource      *source = m->data;
123                         const gchar  *completion;
124                         SourceBook    source_book;
125
126                         /* We're only loading completion books for now, as we don't want
127                          * unnecessary auth prompts */
128                         completion = e_source_get_property (source, "completion");
129                         if (!completion || g_ascii_strcasecmp (completion, "true"))
130                                 continue;
131
132                         source_book.book = e_load_book_source (source, NULL, NULL);
133                         if (!source_book.book)
134                                 continue;
135
136                         source_book.is_completion_book = TRUE;
137
138                         g_array_append_val (source_books, source_book);
139                 }
140         }
141
142         g_object_unref (source_list);
143 }
144
145 static void
146 e_name_selector_finalize (GObject *object)
147 {
148         if (G_OBJECT_CLASS (e_name_selector_parent_class)->finalize)
149                 G_OBJECT_CLASS (e_name_selector_parent_class)->finalize (object);
150 }
151
152 /**
153  * e_name_selector_new:
154  *
155  * Creates a new #ENameSelector.
156  *
157  * Return value: A new #ENameSelector.
158  **/
159 ENameSelector *
160 e_name_selector_new (void)
161 {
162         return E_NAME_SELECTOR (g_object_new (E_TYPE_NAME_SELECTOR, NULL));
163 }
164
165 /* ------- *
166  * Helpers *
167  * ------- */
168
169 static gint
170 add_section (ENameSelector *name_selector, const gchar *name)
171 {
172         Section section;
173
174         g_assert (name != NULL);
175
176         memset (&section, 0, sizeof (Section));
177         section.name = g_strdup (name);
178
179         g_array_append_val (name_selector->sections, section);
180         return name_selector->sections->len - 1;
181 }
182
183 static gint
184 find_section_by_name (ENameSelector *name_selector, const gchar *name)
185 {
186         gint i;
187
188         g_assert (name != NULL);
189
190         for (i = 0; i < name_selector->sections->len; i++) {
191                 Section *section = &g_array_index (name_selector->sections, Section, i);
192
193                 if (!strcmp (name, section->name))
194                         return i;
195         }
196
197         return -1;
198 }
199
200 /* ----------------- *
201  * ENameSelector API *
202  * ----------------- */
203
204 /**
205  * e_name_selector_peek_model:
206  * @name_selector: an #ENameSelector
207  *
208  * Gets the #ENameSelectorModel used by @name_selector.
209  *
210  * Return value: The #ENameSelectorModel used by @name_selector.
211  **/
212 ENameSelectorModel *
213 e_name_selector_peek_model (ENameSelector *name_selector)
214 {
215         g_return_val_if_fail (E_IS_NAME_SELECTOR (name_selector), NULL);
216
217         return name_selector->model;
218 }
219
220 /**
221  * e_name_selector_peek_dialog:
222  * @name_selelctor: an #ENameSelector
223  *
224  * Gets the #ENameSelectorDialog used by @name_selector.
225  *
226  * Return value: The #ENameSelectorDialog used by @name_selector.
227  **/
228 ENameSelectorDialog *
229 e_name_selector_peek_dialog (ENameSelector *name_selector)
230 {
231         g_return_val_if_fail (E_IS_NAME_SELECTOR (name_selector), NULL);
232
233         if (!name_selector->dialog) {
234                 name_selector->dialog = e_name_selector_dialog_new ();
235                 e_name_selector_dialog_set_model (name_selector->dialog, name_selector->model);
236                 g_signal_connect (name_selector->dialog, "delete-event",
237                                   G_CALLBACK (gtk_widget_hide_on_delete), name_selector);
238         }
239
240         return name_selector->dialog;
241 }
242
243 /**
244  * e_name_selector_peek_section_entry:
245  * @name_selector: an #ENameSelector
246  * @name: the name of the section to peek
247  *
248  * Gets the #ENameSelectorEntry for the section specified by @name.
249  *
250  * Return value: The #ENameSelectorEntry for the named section, or %NULL if it
251  * doesn't exist in the #ENameSelectorModel.
252  **/
253 ENameSelectorEntry *
254 e_name_selector_peek_section_entry (ENameSelector *name_selector, const gchar *name)
255 {
256         EDestinationStore *destination_store;
257         Section *section;
258         gint     n;
259
260         g_return_val_if_fail (E_IS_NAME_SELECTOR (name_selector), NULL);
261         g_return_val_if_fail (name != NULL, NULL);
262
263         if (!e_name_selector_model_peek_section (name_selector->model, name,
264                                                  NULL, &destination_store))
265                 return NULL;
266
267         n = find_section_by_name (name_selector, name);
268         if (n < 0)
269                 n = add_section (name_selector, name);
270
271         section = &g_array_index (name_selector->sections, Section, n);
272
273         if (!section->entry) {
274                 GArray        *source_books;
275                 EContactStore *contact_store;
276                 gchar         *text;
277                 gint           i;
278
279                 section->entry = e_name_selector_entry_new ();
280                 if (pango_parse_markup (name, -1, '_', NULL,
281                                         &text, NULL, NULL))  {
282                         atk_object_set_name (gtk_widget_get_accessible (GTK_WIDGET (section->entry)), text);
283                         g_free (text);
284                 }
285                 e_name_selector_entry_set_destination_store (section->entry, destination_store);
286
287                 /* Create a contact store for the entry and assign our already-open books to it */
288
289                 contact_store = e_contact_store_new ();
290                 source_books = g_object_get_data (G_OBJECT (name_selector), PRIVATE_SOURCE_BOOKS_KEY);
291
292                 for (i = 0; i < source_books->len; i++) {
293                         SourceBook *source_book = &g_array_index (source_books, SourceBook, i);
294
295                         if (source_book->is_completion_book)
296                                 e_contact_store_add_book (contact_store, source_book->book);
297                 }
298
299                 e_name_selector_entry_set_contact_store (section->entry, contact_store);
300                 g_object_unref (contact_store);
301         }
302
303         return section->entry;
304 }
305
306 /**
307  * e_name_selector_peek_section_list:
308  * @name_selector: an #ENameSelector
309  * @name: the name of the section to peek
310  *
311  * Gets the #ENameSelectorList for the section specified by @name.
312  *
313  * Return value: The #ENameSelectorList for the named section, or %NULL if it
314  * doesn't exist in the #ENameSelectorModel.
315  **/
316
317 ENameSelectorList *
318 e_name_selector_peek_section_list (ENameSelector *name_selector, const gchar *name)
319 {
320         EDestinationStore *destination_store;
321         Section *section;
322         gint     n;
323
324         g_return_val_if_fail (E_IS_NAME_SELECTOR (name_selector), NULL);
325         g_return_val_if_fail (name != NULL, NULL);
326
327         if (!e_name_selector_model_peek_section (name_selector->model, name,
328                                                  NULL, &destination_store))
329                 return NULL;
330
331         n = find_section_by_name (name_selector, name);
332         if (n < 0)
333                 n = add_section (name_selector, name);
334
335         section = &g_array_index (name_selector->sections, Section, n);
336
337         if (!section->entry) {
338                 GArray        *source_books;
339                 EContactStore *contact_store;
340                 gchar         *text;
341                 gint           i;
342
343                 section->entry = (ENameSelectorEntry *) e_name_selector_list_new ();
344                 if (pango_parse_markup (name, -1, '_', NULL,
345                                         &text, NULL, NULL))  {
346                         atk_object_set_name (gtk_widget_get_accessible (GTK_WIDGET (section->entry)), text);
347                         g_free (text);
348         }
349                 e_name_selector_entry_set_destination_store (section->entry, destination_store);
350
351                 /* Create a contact store for the entry and assign our already-open books to it */
352
353                 contact_store = e_contact_store_new ();
354                 source_books = g_object_get_data (G_OBJECT (name_selector), PRIVATE_SOURCE_BOOKS_KEY);
355
356                 for (i = 0; i < source_books->len; i++) {
357                         SourceBook *source_book = &g_array_index (source_books, SourceBook, i);
358
359                         if (source_book->is_completion_book)
360                                 e_contact_store_add_book (contact_store, source_book->book);
361                 }
362
363                 e_name_selector_entry_set_contact_store (section->entry, contact_store);
364                 g_object_unref (contact_store);
365         }
366
367         return (ENameSelectorList *)section->entry;
368 }
369