Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / libedataserverui / e-name-selector-dialog.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /* e-name-selector-dialog.c - Dialog that lets user pick EDestinations.
4  *
5  * Copyright (C) 2004 Novell, Inc.
6  *
7  * This library 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 GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  * Author: Hans Petter Jansson <hpj@novell.com>
22  */
23
24 #include <config.h>
25 #include <string.h>
26 #include <gtk/gtk.h>
27 #include <gdk/gdkkeysyms.h>
28 #include <gtk/gtkalignment.h>
29 #include <gtk/gtkbutton.h>
30 #include <gtk/gtkentry.h>
31 #include <gtk/gtklabel.h>
32 #include <gtk/gtkscrolledwindow.h>
33 #include <gtk/gtkstock.h>
34 #include <glib/gi18n-lib.h>
35 #include <libedataserverui/e-source-option-menu.h>
36 #include <libedataserverui/e-destination-store.h>
37 #include <libedataserverui/e-contact-store.h>
38 #include <libedataserverui/e-book-auth-util.h>
39 #include "libedataserver/e-sexp.h"
40 #include "libedataserver/e-categories.h"
41 #include "libedataserver/libedataserver-private.h"
42 #include "e-name-selector-dialog.h"
43
44 typedef struct {
45         gchar        *name;
46
47         GtkBox       *section_box;
48         GtkLabel     *label;  
49         GtkButton    *transfer_button;
50         GtkButton    *remove_button;
51         GtkTreeView  *destination_view;
52 }
53 Section;
54
55 typedef struct {
56         GtkTreeView *view;
57         GtkButton   *button;
58         ENameSelectorDialog *dlg_ptr;
59 } SelData;
60
61 typedef struct _ENameSelectorDialogPrivate      ENameSelectorDialogPrivate;
62 struct _ENameSelectorDialogPrivate
63 {
64         guint destination_index;
65 };
66
67 static ESource *find_first_source             (ESourceList *source_list);
68 static void     search_changed                (ENameSelectorDialog *name_selector_dialog);
69 static void     source_selected               (ENameSelectorDialog *name_selector_dialog, ESource *source);
70 static void     transfer_button_clicked       (ENameSelectorDialog *name_selector_dialog, GtkButton *transfer_button);
71 static void     contact_selection_changed     (ENameSelectorDialog *name_selector_dialog);
72 static void     setup_name_selector_model     (ENameSelectorDialog *name_selector_dialog);
73 static void     shutdown_name_selector_model  (ENameSelectorDialog *name_selector_dialog);
74 static void     contact_activated             (ENameSelectorDialog *name_selector_dialog, GtkTreePath *path);
75 static void     destination_activated         (ENameSelectorDialog *name_selector_dialog, GtkTreePath *path,
76                                                GtkTreeViewColumn *column, GtkTreeView *tree_view);
77 static gboolean destination_key_press         (ENameSelectorDialog *name_selector_dialog, GdkEventKey *event, GtkTreeView *tree_view);
78 static void remove_button_clicked (GtkButton *button, SelData *data);
79 static void     remove_books                  (ENameSelectorDialog *name_selector_dialog);
80 static void     contact_column_formatter      (GtkTreeViewColumn *column, GtkCellRenderer *cell,
81                                                GtkTreeModel *model, GtkTreeIter *iter,
82                                                ENameSelectorDialog *name_selector_dialog);
83 static void     destination_column_formatter  (GtkTreeViewColumn *column, GtkCellRenderer *cell,
84                                                GtkTreeModel *model, GtkTreeIter *iter,
85                                                ENameSelectorDialog *name_selector_dialog);
86
87 /* ------------------ *
88  * Class/object setup *
89  * ------------------ */
90
91 G_DEFINE_TYPE (ENameSelectorDialog, e_name_selector_dialog, GTK_TYPE_DIALOG);
92
93 #define E_NAME_SELECTOR_DIALOG_GET_PRIVATE(obj) \
94         (G_TYPE_INSTANCE_GET_PRIVATE ((obj), E_TYPE_NAME_SELECTOR_DIALOG, ENameSelectorDialogPrivate))
95
96
97 static void
98 e_name_selector_dialog_get_property (GObject *object, guint prop_id,
99                                      GValue *value, GParamSpec *pspec)
100 {
101 }
102
103 static void
104 e_name_selector_dialog_set_property (GObject *object, guint prop_id,
105                                      const GValue *value, GParamSpec *pspec)
106 {
107 }
108
109 /* FIXME: category_list should become part of ENameSelectorDialog structure */
110 GList *category_list;
111
112 static void
113 e_name_selector_dialog_populate_categories (ENameSelectorDialog *name_selector_dialog)
114 {
115         GtkWidget *category_option_menu;
116         GtkWidget *category_menu;
117         GList *l;
118         category_option_menu = glade_xml_get_widget (name_selector_dialog->gui, "optionmenu-category");
119
120         /* Categories are already sorted */
121         category_list = e_categories_get_list () ;
122         category_list = g_list_prepend (category_list, _("Any Category"));
123
124         category_menu = gtk_menu_new ();
125         l = category_list;
126         while (l) {     
127                 GtkWidget *item;
128                 item = gtk_menu_item_new_with_label (l->data);
129                 gtk_menu_shell_append (GTK_MENU_SHELL (category_menu), item);
130                 l = l->next;
131         }
132         gtk_widget_show_all (category_menu);
133         gtk_option_menu_set_menu (GTK_OPTION_MENU (category_option_menu), category_menu);
134         
135         g_signal_connect_swapped (category_option_menu, "changed", G_CALLBACK (search_changed), name_selector_dialog);
136 }
137
138 static void
139 e_name_selector_dialog_init (ENameSelectorDialog *name_selector_dialog)
140 {
141         GtkTreeSelection  *contact_selection;
142         GtkTreeViewColumn *column;
143         GtkCellRenderer   *cell_renderer;
144         GtkWidget         *widget;
145         GtkWidget         *container;
146         GtkWidget         *label;
147         GtkTreeSelection  *selection;
148         ESourceList       *source_list;
149         char              *gladefile;
150         GConfClient *gconf_client;      
151         char *uid;
152
153         ENameSelectorDialogPrivate *priv = E_NAME_SELECTOR_DIALOG_GET_PRIVATE (name_selector_dialog);
154         priv->destination_index = 0;
155         
156         /* Get Glade GUI */
157         gladefile = g_build_filename (E_DATA_SERVER_UI_GLADEDIR,
158                                       "e-name-selector-dialog.glade",
159                                       NULL);
160         name_selector_dialog->gui = glade_xml_new (gladefile, NULL, GETTEXT_PACKAGE);
161         g_free (gladefile);
162
163         widget = glade_xml_get_widget (name_selector_dialog->gui, "name-selector-box");
164         if (!widget) {
165                 g_warning ("ENameSelectorDialog can't load Glade interface!");
166                 g_object_unref (name_selector_dialog->gui);
167                 name_selector_dialog->gui = NULL;
168                 return;
169         }
170
171         /* Get addressbook sources */
172
173         if (!e_book_get_addressbooks (&source_list, NULL)) {
174                 g_warning ("ENameSelectorDialog can't find any addressbooks!");
175                 g_object_unref (name_selector_dialog->gui);
176                 return;
177         }
178
179         /* Reparent it to inside ourselves */
180
181         g_object_ref (widget);
182         gtk_container_remove (GTK_CONTAINER (widget->parent), widget);
183         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (name_selector_dialog)->vbox), widget, TRUE, TRUE, 0);
184         g_object_unref (widget);
185
186         /* Store pointers to relevant widgets */
187
188         name_selector_dialog->contact_view = GTK_TREE_VIEW (
189                 glade_xml_get_widget (name_selector_dialog->gui, "source-tree-view"));
190         name_selector_dialog->status_label = GTK_LABEL (
191                 glade_xml_get_widget (name_selector_dialog->gui, "status-message"));
192         name_selector_dialog->destination_box = GTK_BOX (
193                 glade_xml_get_widget (name_selector_dialog->gui, "destination-box"));
194         name_selector_dialog->search_entry = GTK_ENTRY (
195                 glade_xml_get_widget (name_selector_dialog->gui, "search"));
196
197         /* Create size group for transfer buttons */
198
199         name_selector_dialog->button_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
200
201         /* Set up contacts view */
202
203         column = gtk_tree_view_column_new ();
204         cell_renderer = GTK_CELL_RENDERER (gtk_cell_renderer_text_new ());
205         gtk_tree_view_column_pack_start (column, cell_renderer, TRUE);
206         gtk_tree_view_column_set_cell_data_func (column, cell_renderer,
207                                                  (GtkTreeCellDataFunc) contact_column_formatter,
208                                                  name_selector_dialog, NULL);
209
210         selection = gtk_tree_view_get_selection (name_selector_dialog->contact_view);
211         gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
212         gtk_tree_view_append_column (name_selector_dialog->contact_view, column);
213         g_signal_connect_swapped (name_selector_dialog->contact_view, "row-activated",
214                                   G_CALLBACK (contact_activated), name_selector_dialog);
215
216         /* Listen for changes to the contact selection */
217
218         contact_selection = gtk_tree_view_get_selection (name_selector_dialog->contact_view);
219         g_signal_connect_swapped (contact_selection, "changed",
220                                   G_CALLBACK (contact_selection_changed), name_selector_dialog);
221
222         /* Set up our data structures */
223
224         name_selector_dialog->name_selector_model = e_name_selector_model_new ();
225         name_selector_dialog->sections            = g_array_new (FALSE, FALSE, sizeof (Section));
226         name_selector_dialog->source_list         = source_list;
227
228         setup_name_selector_model (name_selector_dialog);
229
230         /* Create source menu */
231
232         widget = e_source_option_menu_new (name_selector_dialog->source_list);
233         
234         gconf_client = gconf_client_get_default();
235         uid = gconf_client_get_string (gconf_client, "/apps/evolution/addressbook/display/primary_addressbook",
236                         NULL);
237         g_object_unref (gconf_client);
238         if (uid) {
239                 ESource *source = e_source_list_peek_source_by_uid(name_selector_dialog->source_list, uid);
240                 if (source) {
241                         e_source_option_menu_select ((ESourceOptionMenu *)widget, source);
242                         source_selected (name_selector_dialog, source);
243                 }
244                 else {
245                         source_selected (name_selector_dialog, find_first_source (name_selector_dialog->source_list));
246                 }
247                 g_free (uid);
248         }
249         else {
250                 source_selected (name_selector_dialog, find_first_source (name_selector_dialog->source_list));
251         }
252
253         g_signal_connect_swapped (widget, "source_selected", G_CALLBACK (source_selected), name_selector_dialog);
254
255         label = glade_xml_get_widget (name_selector_dialog->gui, "AddressBookLabel");
256         gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
257
258         gtk_widget_show (widget);
259
260         container = glade_xml_get_widget (name_selector_dialog->gui, "source-menu-box");
261         gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
262
263         e_name_selector_dialog_populate_categories (name_selector_dialog);
264
265         /* Set up search-as-you-type signal */
266
267         widget = glade_xml_get_widget (name_selector_dialog->gui, "search");
268         g_signal_connect_swapped (widget, "changed", G_CALLBACK (search_changed), name_selector_dialog);
269
270         /* Display initial source */
271
272         /* TODO: Remember last used source */
273
274
275         /* Set up dialog defaults */
276
277         gtk_dialog_add_buttons (GTK_DIALOG (name_selector_dialog),
278                                 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
279                                 NULL);
280
281         gtk_dialog_set_default_response (GTK_DIALOG (name_selector_dialog), GTK_RESPONSE_CLOSE);
282         gtk_window_set_modal            (GTK_WINDOW (name_selector_dialog), TRUE);
283         gtk_window_set_default_size     (GTK_WINDOW (name_selector_dialog), 472, 512);
284         gtk_window_set_resizable        (GTK_WINDOW (name_selector_dialog), TRUE);
285         gtk_dialog_set_has_separator    (GTK_DIALOG (name_selector_dialog), FALSE);
286         gtk_container_set_border_width  (GTK_CONTAINER (name_selector_dialog), 4);
287         gtk_window_set_title            (GTK_WINDOW (name_selector_dialog), _("Select Contacts from Address Book"));
288         gtk_widget_grab_focus (widget);
289 }
290         
291 /* Partial, repeatable destruction. Release references. */
292 static void
293 e_name_selector_dialog_dispose (GObject *object)
294 {
295         ENameSelectorDialog *name_selector_dialog = E_NAME_SELECTOR_DIALOG (object);
296
297         remove_books (name_selector_dialog);
298         shutdown_name_selector_model (name_selector_dialog);
299
300         if (G_OBJECT_CLASS (e_name_selector_dialog_parent_class)->dispose)
301                 G_OBJECT_CLASS (e_name_selector_dialog_parent_class)->dispose (object);
302 }
303
304 /* Final, one-time destruction. Free all. */
305 static void
306 e_name_selector_dialog_finalize (GObject *object)
307 {
308         ENameSelectorDialog *name_selector_dialog = E_NAME_SELECTOR_DIALOG (object);
309
310         g_array_free (name_selector_dialog->sections, TRUE);
311         g_object_unref (name_selector_dialog->source_list);
312         g_object_unref (name_selector_dialog->button_size_group);
313         g_list_free (category_list);
314
315         if (G_OBJECT_CLASS (e_name_selector_dialog_parent_class)->finalize)
316                 G_OBJECT_CLASS (e_name_selector_dialog_parent_class)->finalize (object);
317 }
318
319 static void
320 e_name_selector_dialog_class_init (ENameSelectorDialogClass *name_selector_dialog_class)
321 {
322         GObjectClass *object_class = G_OBJECT_CLASS (name_selector_dialog_class);
323
324         object_class->get_property = e_name_selector_dialog_get_property;
325         object_class->set_property = e_name_selector_dialog_set_property;
326         object_class->dispose      = e_name_selector_dialog_dispose;
327         object_class->finalize     = e_name_selector_dialog_finalize;
328
329         /* Install properties */
330
331         /* Install signals */
332
333         g_type_class_add_private (object_class, sizeof(ENameSelectorDialogPrivate));
334
335 }
336
337 /**
338  * e_name_selector_dialog_new:
339  *
340  * Creates a new #ENameSelectorDialog.
341  *
342  * Return value: A new #ENameSelectorDialog.
343  **/
344 ENameSelectorDialog *
345 e_name_selector_dialog_new (void)
346 {
347           return g_object_new (E_TYPE_NAME_SELECTOR_DIALOG, NULL);
348 }
349
350 /* --------- *
351  * Utilities *
352  * --------- */
353
354 static gchar *
355 escape_sexp_string (const gchar *string)
356 {
357         GString *gstring;
358         gchar   *encoded_string;
359
360         gstring = g_string_new ("");
361         e_sexp_encode_string (gstring, string);
362
363         encoded_string = gstring->str;
364         g_string_free (gstring, FALSE);
365
366         return encoded_string;
367 }
368
369 static void
370 sort_iter_to_contact_store_iter (ENameSelectorDialog *name_selector_dialog, GtkTreeIter *iter,
371                                  gint *email_n)
372 {
373         ETreeModelGenerator *contact_filter;
374         GtkTreeIter          child_iter;
375         gint                 email_n_local;
376
377         contact_filter = e_name_selector_model_peek_contact_filter (name_selector_dialog->name_selector_model);
378
379         gtk_tree_model_sort_convert_iter_to_child_iter (name_selector_dialog->contact_sort,
380                                                         &child_iter, iter);
381         e_tree_model_generator_convert_iter_to_child_iter (contact_filter, iter, &email_n_local, &child_iter);
382
383         if (email_n)
384                 *email_n = email_n_local;
385 }
386
387 static ESource *
388 find_first_source (ESourceList *source_list)
389 {
390         GSList *groups, *sources, *l, *m;
391                         
392         groups = e_source_list_peek_groups (source_list);
393         for (l = groups; l; l = l->next) {
394                 ESourceGroup *group = l->data;
395                                 
396                 sources = e_source_group_peek_sources (group);
397                 for (m = sources; m; m = m->next) {
398                         ESource *source = m->data;
399
400                         return source;
401                 }                               
402         }
403
404         return NULL;
405 }
406
407 static void
408 add_destination (EDestinationStore *destination_store, EContact *contact, gint email_n)
409 {
410         EDestination *destination;
411
412         /* Transfer (actually, copy into a destination and let the model filter out the
413          * source automatically) */
414
415         destination = e_destination_new ();
416         e_destination_set_contact (destination, contact, email_n);
417         e_destination_store_append_destination (destination_store, destination);
418         g_object_unref (destination);
419 }
420
421 static void
422 remove_books (ENameSelectorDialog *name_selector_dialog)
423 {
424         EContactStore *contact_store;
425         GList         *books;
426         GList         *l;
427
428         if (!name_selector_dialog->name_selector_model)
429                 return;
430
431         contact_store = e_name_selector_model_peek_contact_store (name_selector_dialog->name_selector_model);
432
433         /* Remove books (should be just one) being viewed */
434         books = e_contact_store_get_books (contact_store);
435         for (l = books; l; l = g_list_next (l)) {
436                 EBook *book = l->data;
437                 e_contact_store_remove_book (contact_store, book);
438         }
439         g_list_free (books);
440
441         /* See if we have a book pending; stop loading it if so */
442         if (name_selector_dialog->pending_book) {
443                 e_book_cancel (name_selector_dialog->pending_book, NULL);
444                 g_object_unref (name_selector_dialog->pending_book);
445                 name_selector_dialog->pending_book = NULL;
446         }
447 }
448
449 /* ------------------ *
450  * Section management *
451  * ------------------ */
452
453 static gint
454 find_section_by_transfer_button (ENameSelectorDialog *name_selector_dialog, GtkButton *transfer_button)
455 {
456         gint i;
457
458         for (i = 0; i < name_selector_dialog->sections->len; i++) {
459                 Section *section = &g_array_index (name_selector_dialog->sections, Section, i);
460
461                 if (section->transfer_button == transfer_button)
462                         return i;
463         }
464
465         return -1;
466 }
467
468 static gint
469 find_section_by_tree_view (ENameSelectorDialog *name_selector_dialog, GtkTreeView *tree_view)
470 {
471         gint i;
472
473         for (i = 0; i < name_selector_dialog->sections->len; i++) {
474                 Section *section = &g_array_index (name_selector_dialog->sections, Section, i);
475
476                 if (section->destination_view == tree_view)
477                         return i;
478         }
479
480         return -1;
481 }
482
483 static gint
484 find_section_by_name (ENameSelectorDialog *name_selector_dialog, const gchar *name)
485 {
486         gint i;
487
488         for (i = 0; i < name_selector_dialog->sections->len; i++) {
489                 Section *section = &g_array_index (name_selector_dialog->sections, Section, i);
490
491                 if (!strcmp (name, section->name))
492                         return i;
493         }
494
495         return -1;
496 }
497
498 static void
499 selection_changed (GtkTreeSelection *selection, SelData *data)
500 {
501         GtkTreeSelection *contact_selection;
502         gboolean          have_selection = FALSE;
503
504         contact_selection = gtk_tree_view_get_selection (data->view);
505         if (gtk_tree_selection_count_selected_rows (contact_selection) > 0)
506                 have_selection = TRUE;
507         gtk_widget_set_sensitive (GTK_WIDGET (data->button), have_selection);
508 }
509
510 static gint
511 add_section (ENameSelectorDialog *name_selector_dialog,
512              const gchar *name, const gchar *pretty_name, EDestinationStore *destination_store)
513 {
514         Section            section;
515         GtkTreeViewColumn *column;
516         GtkCellRenderer   *cell_renderer;
517         GtkWidget         *vbox, *hbox, *chbox;
518         GtkWidget         *widget, *image, *label;
519         SelData           *data;
520         GtkTreeSelection  *selection;
521         gchar             *text;
522
523         g_assert (name != NULL);
524         g_assert (pretty_name != NULL);
525         g_assert (E_IS_DESTINATION_STORE (destination_store));
526
527         memset (&section, 0, sizeof (Section));
528
529         section.name = g_strdup (name);
530         section.section_box      = GTK_BOX (gtk_hbox_new (FALSE, 12));
531         section.label = GTK_LABEL (gtk_label_new_with_mnemonic (pretty_name));
532         section.transfer_button  = GTK_BUTTON (gtk_button_new());
533         section.remove_button  = GTK_BUTTON (gtk_button_new());
534         section.destination_view = GTK_TREE_VIEW (gtk_tree_view_new ());
535
536         gtk_label_set_mnemonic_widget (GTK_LABEL (section.label), GTK_WIDGET (section.destination_view));
537
538         if (pango_parse_markup (pretty_name, -1, '_', NULL,
539                                 &text, NULL, NULL))  {
540                 atk_object_set_name (gtk_widget_get_accessible (
541                                         GTK_WIDGET (section.destination_view)), text);
542                 g_free (text);
543         }
544
545         /* Set up transfer button */
546         g_signal_connect_swapped (section.transfer_button, "clicked",
547                                   G_CALLBACK (transfer_button_clicked), name_selector_dialog);
548         
549         /*data for the remove callback*/
550         data = g_malloc0(sizeof(SelData));
551         data->view = section.destination_view;
552         data->dlg_ptr = name_selector_dialog;
553
554         /*Associate to an object destroy so that it gets freed*/
555         g_object_set_data_full ((GObject *)section.destination_view, "sel-remove-data", data, g_free);
556         
557         g_signal_connect(section.remove_button, "clicked",
558                                   G_CALLBACK (remove_button_clicked), data);
559         
560         /* Set up view */
561         column = gtk_tree_view_column_new ();
562         cell_renderer = GTK_CELL_RENDERER (gtk_cell_renderer_text_new ());
563         gtk_tree_view_column_pack_start (column, cell_renderer, TRUE);
564         gtk_tree_view_column_set_cell_data_func (column, cell_renderer,
565                                                  (GtkTreeCellDataFunc) destination_column_formatter,
566                                                  name_selector_dialog, NULL);
567         gtk_tree_view_append_column (section.destination_view, column);
568         gtk_tree_view_set_headers_visible (section.destination_view, FALSE);
569         gtk_tree_view_set_model (section.destination_view, GTK_TREE_MODEL (destination_store));
570
571         vbox = gtk_vbox_new (FALSE, 0);
572         chbox = gtk_hbox_new (FALSE, 0);
573         gtk_box_pack_start (GTK_BOX (chbox), vbox, FALSE, FALSE, 12);
574
575         /* Pack button (in an alignment) */
576         widget = gtk_alignment_new (0.5, 0.0, 0.0, 0.0);
577         gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (section.transfer_button));
578         gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, TRUE, 6);
579         gtk_size_group_add_widget (name_selector_dialog->button_size_group, GTK_WIDGET (section.transfer_button));
580         
581         /*to get the image embedded in the button*/
582         widget = gtk_alignment_new (0.7, 0.5, 0.0, 0.0);
583         gtk_container_add (GTK_CONTAINER (section.transfer_button), GTK_WIDGET (widget));
584
585         hbox = gtk_hbox_new (FALSE, 2);
586         gtk_widget_show (GTK_WIDGET(hbox));
587         gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET(hbox));
588
589         label = gtk_label_new_with_mnemonic (_("_Add"));
590         gtk_widget_show (label);
591         gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
592
593         image = gtk_image_new_from_stock ("gtk-go-forward", GTK_ICON_SIZE_BUTTON);
594         gtk_widget_show (image);
595         gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
596         
597         widget = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
598         gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (section.remove_button));
599         gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, TRUE, 0);
600         gtk_size_group_add_widget (name_selector_dialog->button_size_group, GTK_WIDGET (section.remove_button));
601         gtk_widget_set_sensitive (GTK_WIDGET (section.remove_button), FALSE);
602
603         widget = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
604         gtk_container_add (GTK_CONTAINER (section.remove_button), widget);
605
606         hbox = gtk_hbox_new (FALSE, 2);
607         gtk_widget_show (hbox);
608         gtk_container_add (GTK_CONTAINER (widget), hbox);
609
610         image = gtk_image_new_from_stock ("gtk-go-back", GTK_ICON_SIZE_BUTTON);
611         gtk_widget_show (image);
612         gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
613
614         label = gtk_label_new_with_mnemonic (_("_Remove"));
615         gtk_widget_show (label);
616         gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
617
618         vbox = gtk_vbox_new (FALSE, 0);
619         
620         widget = gtk_alignment_new (0.5, 0.0, 0.0, 0.0);
621         gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (section.label));
622         gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, TRUE, 0);
623
624         /* Pack view (in a scrolled window) */
625         widget = gtk_scrolled_window_new (NULL, NULL);
626         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
627         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
628         gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (section.destination_view));
629         gtk_box_pack_start (GTK_BOX (chbox), widget, TRUE, TRUE, 0);
630         gtk_box_pack_start (GTK_BOX (vbox), chbox, TRUE, TRUE, 0);
631         gtk_box_pack_start (section.section_box, vbox, TRUE, TRUE, 0);
632
633         /*data for 'changed' callback*/
634         data = g_malloc0(sizeof(SelData));
635         data->view = section.destination_view;
636         data->button = section.remove_button;
637         g_object_set_data_full ((GObject *)section.destination_view, "sel-change-data", data, g_free);
638         selection = gtk_tree_view_get_selection(section.destination_view);
639         gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
640
641         g_signal_connect(selection, "changed",
642                                   G_CALLBACK (selection_changed), data);
643
644         g_signal_connect_swapped (section.destination_view, "row-activated",
645                                   G_CALLBACK (destination_activated), name_selector_dialog);
646         g_signal_connect_swapped (section.destination_view, "key-press-event",
647                                   G_CALLBACK (destination_key_press), name_selector_dialog);
648
649         gtk_widget_show_all (GTK_WIDGET (section.section_box));
650
651         /* Pack this section's box into the dialog */
652         gtk_box_pack_start (name_selector_dialog->destination_box,
653                             GTK_WIDGET (section.section_box), TRUE, TRUE, 0);
654
655         g_array_append_val (name_selector_dialog->sections, section);
656
657         /* Make sure UI is consistent */
658         contact_selection_changed (name_selector_dialog);
659
660         return name_selector_dialog->sections->len - 1;
661 }
662
663 static void
664 free_section (ENameSelectorDialog *name_selector_dialog, gint n)
665 {
666         Section *section;
667
668         g_assert (n >= 0);
669         g_assert (n < name_selector_dialog->sections->len);
670
671         section = &g_array_index (name_selector_dialog->sections, Section, n);
672
673         g_free (section->name);
674         gtk_widget_destroy (GTK_WIDGET (section->section_box));
675 }
676
677 static void
678 model_section_added (ENameSelectorDialog *name_selector_dialog, const gchar *name)
679 {
680         gchar             *pretty_name;
681         EDestinationStore *destination_store;
682
683         e_name_selector_model_peek_section (name_selector_dialog->name_selector_model, name,
684                                             &pretty_name, &destination_store);
685         add_section (name_selector_dialog, name, pretty_name, destination_store);
686         g_free (pretty_name);
687 }
688
689 static void
690 model_section_removed (ENameSelectorDialog *name_selector_dialog, const gchar *name)
691 {
692         gint section_index;
693
694         section_index = find_section_by_name (name_selector_dialog, name);
695         g_assert (section_index >= 0);
696
697         free_section (name_selector_dialog, section_index);
698         g_array_remove_index (name_selector_dialog->sections, section_index);
699 }
700
701 /* -------------------- *
702  * Addressbook selector *
703  * -------------------- */
704
705 static void
706 status_message(EBookView *view, const gchar *message, ENameSelectorDialog *dialog) 
707 {
708         if(message == NULL)
709                 gtk_label_set_text(dialog->status_label, "");
710         else
711                 gtk_label_set_text(dialog->status_label, message);
712 }
713
714 static void
715 sequence_complete(EBookView *view, EBookViewStatus status, ENameSelectorDialog *dialog)
716 {
717         status_message(view, NULL, dialog);
718 }
719
720 static void
721 book_opened (EBook *book, EBookStatus status, gpointer data)
722 {
723         ENameSelectorDialog *name_selector_dialog = E_NAME_SELECTOR_DIALOG (data);
724         EContactStore       *contact_store;
725         EBookView           *view; 
726
727         if (status != E_BOOK_ERROR_OK) {
728                 /* TODO: Handle errors gracefully */
729                 gtk_label_set_text(name_selector_dialog->status_label, "Error loading addressbook");
730                 g_warning ("ENameSelectorDialog failed to open book!");
731                 return;
732         }
733
734         contact_store = e_name_selector_model_peek_contact_store (name_selector_dialog->name_selector_model);
735         e_contact_store_add_book (contact_store, book);
736         view = find_contact_source_by_book_return_view(contact_store, book);
737         g_signal_connect(view, "status_message", G_CALLBACK(status_message), name_selector_dialog);
738         g_signal_connect(view, "sequence_complete", G_CALLBACK(sequence_complete), name_selector_dialog);
739
740         g_object_unref (book);
741         name_selector_dialog->pending_book = NULL;
742 }
743
744 static void
745 source_selected (ENameSelectorDialog *name_selector_dialog, ESource *source)
746 {
747         /* Remove any previous books being shown or loaded */
748         remove_books (name_selector_dialog);
749
750         /* Start loading selected book */
751         name_selector_dialog->pending_book = e_load_book_source (source, book_opened,
752                                                                  name_selector_dialog);
753 }
754
755 /* --------------- *
756  * Other UI events *
757  * --------------- */
758
759 static void
760 search_changed (ENameSelectorDialog *name_selector_dialog)
761 {
762         EContactStore *contact_store;
763         EBookQuery    *book_query;
764         GtkWidget     *category_option_menu;
765         const gchar   *text;
766         gint          category_id;      
767         gchar         *text_escaped;
768         gchar         *query_string;
769         const gchar   *category;
770         gchar         *category_escaped;
771
772         category_option_menu = glade_xml_get_widget(name_selector_dialog->gui, "optionmenu-category");
773         category_id = gtk_option_menu_get_history (GTK_OPTION_MENU(category_option_menu));
774         category = g_list_nth_data (category_list, category_id);
775         if (!category)
776                 return;
777         category_escaped = escape_sexp_string (category);
778
779         text = gtk_entry_get_text (name_selector_dialog->search_entry);
780         text_escaped = escape_sexp_string (text);
781
782         if ( !strcmp (category, _("Any Category"))) {
783                 query_string = g_strdup_printf ("(or (beginswith \"file_as\" %s) "
784                                                 "    (beginswith \"full_name\" %s) "
785                                                 "    (beginswith \"email\" %s) "
786                                                 "    (beginswith \"nickname\" %s)))",
787                                                 text_escaped, text_escaped, text_escaped, text_escaped);
788         }
789         else {
790                 query_string = g_strdup_printf ("(and (is \"category_list\" %s) "
791                                                 "(or (beginswith \"file_as\" %s) "
792                                                 "    (beginswith \"full_name\" %s) "
793                                                 "    (beginswith \"email\" %s) "
794                                                 "    (beginswith \"nickname\" %s)))",
795                                                 category_escaped,text_escaped, text_escaped, text_escaped, text_escaped);
796         }
797
798         book_query = e_book_query_from_string (query_string);
799         g_free (query_string);
800         g_free (text_escaped);
801         g_free (category_escaped);
802
803         contact_store = e_name_selector_model_peek_contact_store (name_selector_dialog->name_selector_model);
804         e_contact_store_set_query (contact_store, book_query);
805
806         e_book_query_unref (book_query);
807 }
808
809 static void
810 contact_selection_changed (ENameSelectorDialog *name_selector_dialog)
811 {
812         GtkTreeSelection *contact_selection;
813         gboolean          have_selection = FALSE;
814         gint              i;
815         
816         contact_selection = gtk_tree_view_get_selection (name_selector_dialog->contact_view);
817         if (gtk_tree_selection_count_selected_rows (contact_selection))
818                 have_selection = TRUE;
819
820         for (i = 0; i < name_selector_dialog->sections->len; i++) {
821                 Section *section = &g_array_index (name_selector_dialog->sections, Section, i);
822                 gtk_widget_set_sensitive (GTK_WIDGET (section->transfer_button), have_selection);
823         }
824 }
825
826 static void
827 contact_activated (ENameSelectorDialog *name_selector_dialog, GtkTreePath *path)
828 {
829         EContactStore     *contact_store;
830         EDestinationStore *destination_store;
831         EContact          *contact;
832         GtkTreeIter       iter;
833         Section           *section;
834         gint               email_n;
835
836         ENameSelectorDialogPrivate *priv;
837
838         /* When a contact is activated, we transfer it to the first destination on our list */
839
840         contact_store = e_name_selector_model_peek_contact_store (name_selector_dialog->name_selector_model);
841
842         /* If we have no sections, we can't transfer */
843         if (name_selector_dialog->sections->len == 0) 
844                 return;
845
846         /* Get the contact to be transferred */
847
848         if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (name_selector_dialog->contact_sort),
849                                       &iter, path))
850                 g_assert_not_reached ();
851
852         sort_iter_to_contact_store_iter (name_selector_dialog, &iter, &email_n);
853
854         contact = e_contact_store_get_contact (contact_store, &iter);
855         if (!contact) {
856                 g_warning ("ENameSelectorDialog could not get selected contact!");
857                 return;
858         }
859
860
861         priv = E_NAME_SELECTOR_DIALOG_GET_PRIVATE (name_selector_dialog);
862
863         section = &g_array_index (name_selector_dialog->sections, Section, priv->destination_index);
864         if (!e_name_selector_model_peek_section (name_selector_dialog->name_selector_model,
865                                                  section->name, NULL, &destination_store)) {
866                 g_warning ("ENameSelectorDialog has a section unknown to the model!");
867                 return;
868         }
869
870         add_destination (destination_store, contact, email_n);
871 }
872
873 static void
874 destination_activated (ENameSelectorDialog *name_selector_dialog, GtkTreePath *path,
875                        GtkTreeViewColumn *column, GtkTreeView *tree_view)
876 {
877         gint               section_index;
878         EDestinationStore *destination_store;
879         EDestination      *destination;
880         Section           *section;
881         GtkTreeIter        iter;
882
883         /* When a destination is activated, we remove it from the section */
884
885         section_index = find_section_by_tree_view (name_selector_dialog, tree_view);
886         if (section_index < 0) {
887                 g_warning ("ENameSelectorDialog got activation from unknown view!");
888                 return;
889         }
890
891         section = &g_array_index (name_selector_dialog->sections, Section, section_index);
892         if (!e_name_selector_model_peek_section (name_selector_dialog->name_selector_model,
893                                                  section->name, NULL, &destination_store)) {
894                 g_warning ("ENameSelectorDialog has a section unknown to the model!");
895                 return;
896         }
897
898         if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (destination_store), &iter, path))
899                 g_assert_not_reached ();
900
901         destination = e_destination_store_get_destination (destination_store, &iter);
902         g_assert (destination);
903
904         e_destination_store_remove_destination (destination_store, destination);
905 }
906
907 static gboolean 
908 remove_selection (ENameSelectorDialog *name_selector_dialog, GtkTreeView *tree_view)
909 {
910         gint               section_index;
911         EDestinationStore *destination_store;
912         EDestination      *destination;
913         Section           *section;
914         GtkTreeSelection  *selection;
915         GList             *rows, *l;
916
917         section_index = find_section_by_tree_view (name_selector_dialog, tree_view);
918         if (section_index < 0) {
919                 g_warning ("ENameSelectorDialog got key press from unknown view!");
920                 return FALSE;
921         }
922
923         section = &g_array_index (name_selector_dialog->sections, Section, section_index);
924         if (!e_name_selector_model_peek_section (name_selector_dialog->name_selector_model,
925                                                  section->name, NULL, &destination_store)) {
926                 g_warning ("ENameSelectorDialog has a section unknown to the model!");
927                 return FALSE;
928         }
929
930         selection = gtk_tree_view_get_selection (tree_view);
931         if (!gtk_tree_selection_count_selected_rows (selection)) {
932                 g_warning ("ENameSelectorDialog remove button clicked, but no selection!");
933                 return FALSE;
934         }
935
936         rows = gtk_tree_selection_get_selected_rows (selection, NULL);
937         rows = g_list_reverse (rows);
938
939         for (l = rows; l; l = g_list_next(l)) {
940                 GtkTreeIter iter;
941                 GtkTreePath *path = l->data;
942
943                 if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (destination_store),
944                                               &iter, path))
945                         g_assert_not_reached ();
946
947                 gtk_tree_path_free (path);
948
949                 destination = e_destination_store_get_destination (destination_store, &iter);
950                 g_assert (destination);
951
952                 e_destination_store_remove_destination (destination_store, destination);
953         }
954         g_list_free (rows);
955
956         return TRUE;
957 }
958
959 static void
960 remove_button_clicked (GtkButton *button, SelData *data)
961 {
962         GtkTreeView *view;
963         ENameSelectorDialog *name_selector_dialog;
964         
965         view = data->view; 
966         name_selector_dialog = data->dlg_ptr;
967         remove_selection (name_selector_dialog, view);
968 }
969         
970 static gboolean 
971 destination_key_press (ENameSelectorDialog *name_selector_dialog, 
972                        GdkEventKey *event, GtkTreeView *tree_view)
973 {
974
975         /* we only care about DEL key */
976         if (event->keyval != GDK_Delete)
977                 return FALSE;
978         return remove_selection (name_selector_dialog, tree_view);
979
980 }
981
982 static void
983 transfer_button_clicked (ENameSelectorDialog *name_selector_dialog, GtkButton *transfer_button)
984 {
985         EContactStore     *contact_store;
986         EDestinationStore *destination_store;
987         GtkTreeSelection  *selection;
988         EContact          *contact;
989         gint               section_index;
990         Section           *section;
991         gint               email_n;
992         GList             *rows, *l;
993
994         /* Get the contact to be transferred */
995
996         contact_store = e_name_selector_model_peek_contact_store (name_selector_dialog->name_selector_model);
997         selection = gtk_tree_view_get_selection (name_selector_dialog->contact_view);
998
999         if (!gtk_tree_selection_count_selected_rows (selection)) {
1000                 g_warning ("ENameSelectorDialog transfer button clicked, but no selection!");
1001                 return;
1002         }
1003
1004         /* Get the target section */
1005         section_index = find_section_by_transfer_button (name_selector_dialog, transfer_button);
1006         if (section_index < 0) {
1007                 g_warning ("ENameSelectorDialog got click from unknown button!");
1008                 return;
1009         }
1010
1011         section = &g_array_index (name_selector_dialog->sections, Section, section_index);
1012         if (!e_name_selector_model_peek_section (name_selector_dialog->name_selector_model,
1013                                                  section->name, NULL, &destination_store)) {
1014                 g_warning ("ENameSelectorDialog has a section unknown to the model!");
1015                 return;
1016         }
1017
1018         rows = gtk_tree_selection_get_selected_rows (selection, NULL);
1019         rows = g_list_reverse (rows);
1020
1021         for (l = rows; l; l = g_list_next(l)) {
1022                 GtkTreeIter iter;
1023                 GtkTreePath *path = l->data;
1024
1025                 if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (name_selector_dialog->contact_sort),
1026                                       &iter, path)) {
1027                         gtk_tree_path_free (path);
1028                         return ;
1029                 }
1030                         
1031                 gtk_tree_path_free (path);
1032                 sort_iter_to_contact_store_iter (name_selector_dialog, &iter, &email_n);
1033
1034                 contact = e_contact_store_get_contact (contact_store, &iter);
1035                 if (!contact) {
1036                         g_warning ("ENameSelectorDialog could not get selected contact!");
1037                         g_list_free (rows);
1038                         return;
1039                 }
1040
1041                 add_destination (destination_store, contact, email_n);
1042         }
1043         g_list_free (rows);
1044 }
1045
1046 /* --------------------- *
1047  * Main model management *
1048  * --------------------- */
1049
1050 static void
1051 setup_name_selector_model (ENameSelectorDialog *name_selector_dialog)
1052 {
1053         EContactStore       *contact_store;
1054         ETreeModelGenerator *contact_filter;
1055         GList               *new_sections;
1056         GList               *l;
1057
1058         /* Create new destination sections in UI */
1059
1060         new_sections = e_name_selector_model_list_sections (name_selector_dialog->name_selector_model);
1061
1062         for (l = new_sections; l; l = g_list_next (l)) {
1063                 gchar             *name = l->data;
1064                 gchar             *pretty_name;
1065                 EDestinationStore *destination_store;
1066
1067                 e_name_selector_model_peek_section (name_selector_dialog->name_selector_model,
1068                                                     name, &pretty_name, &destination_store);
1069
1070                 add_section (name_selector_dialog, name, pretty_name, destination_store);
1071
1072                 g_free (pretty_name);
1073                 g_free (name);
1074         }
1075
1076         g_list_free (new_sections);
1077
1078         /* Connect to section add/remove signals */
1079
1080         g_signal_connect_swapped (name_selector_dialog->name_selector_model, "section-added",
1081                                   G_CALLBACK (model_section_added), name_selector_dialog);
1082         g_signal_connect_swapped (name_selector_dialog->name_selector_model, "section-removed",
1083                                   G_CALLBACK (model_section_removed), name_selector_dialog);
1084
1085         /* Get contact store and its filter wrapper */
1086
1087         contact_store  = e_name_selector_model_peek_contact_store  (name_selector_dialog->name_selector_model);
1088         contact_filter = e_name_selector_model_peek_contact_filter (name_selector_dialog->name_selector_model);
1089
1090         /* Create sorting model on top of filter, assign it to view */
1091
1092         name_selector_dialog->contact_sort = GTK_TREE_MODEL_SORT (
1093                 gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (contact_filter)));
1094
1095         /* sort on full name as we display full name in name selector dialog */
1096         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (name_selector_dialog->contact_sort),
1097                                               E_CONTACT_FULL_NAME, GTK_SORT_ASCENDING);
1098
1099         gtk_tree_view_set_model (name_selector_dialog->contact_view,
1100                                  GTK_TREE_MODEL (name_selector_dialog->contact_sort));
1101
1102         /* Make sure UI is consistent */
1103
1104         search_changed (name_selector_dialog);
1105         contact_selection_changed (name_selector_dialog);
1106 }
1107
1108 static void
1109 shutdown_name_selector_model (ENameSelectorDialog *name_selector_dialog)
1110 {
1111         gint i;
1112
1113         /* Rid UI of previous destination sections */
1114
1115         for (i = 0; i < name_selector_dialog->sections->len; i++)
1116                 free_section (name_selector_dialog, i);
1117
1118         g_array_set_size (name_selector_dialog->sections, 0);
1119
1120         /* Free sorting model */
1121
1122         if (name_selector_dialog->contact_sort) {
1123                 g_object_unref (name_selector_dialog->contact_sort);
1124                 name_selector_dialog->contact_sort = NULL;
1125         }
1126
1127         /* Free backend model */
1128
1129         if (name_selector_dialog->name_selector_model) {
1130                 g_signal_handlers_disconnect_matched (name_selector_dialog->name_selector_model,
1131                                                       G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, name_selector_dialog);
1132
1133                 g_object_unref (name_selector_dialog->name_selector_model);
1134                 name_selector_dialog->name_selector_model = NULL;
1135         }
1136 }
1137
1138 static void
1139 deep_free_list (GList *list)
1140 {
1141         GList *l;
1142
1143         for (l = list; l; l = g_list_next (l))
1144                 g_free (l->data);
1145
1146         g_list_free (list);
1147 }
1148
1149 static void
1150 contact_column_formatter (GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model,
1151                           GtkTreeIter *iter, ENameSelectorDialog *name_selector_dialog)
1152 {
1153         EContactStore *contact_store;
1154         EContact      *contact;
1155         GtkTreeIter    contact_store_iter;
1156         GList         *email_list;
1157         gchar         *string;
1158         gchar         *full_name_str;
1159         gchar         *email_str;
1160         gint           email_n;
1161
1162         contact_store_iter = *iter;
1163         sort_iter_to_contact_store_iter (name_selector_dialog, &contact_store_iter, &email_n);
1164
1165         contact_store = e_name_selector_model_peek_contact_store (name_selector_dialog->name_selector_model);
1166         contact = e_contact_store_get_contact (contact_store, &contact_store_iter);
1167         email_list = e_contact_get (contact, E_CONTACT_EMAIL);
1168         email_str = g_list_nth_data (email_list, email_n);
1169         full_name_str = e_contact_get (contact, E_CONTACT_FULL_NAME);
1170
1171         if (e_contact_get (contact, E_CONTACT_IS_LIST)) {
1172                 string = g_strdup_printf ("%s", full_name_str ? full_name_str : "?");
1173         } else {
1174                 string = g_strdup_printf ("%s%s<%s>", full_name_str ? full_name_str : "",
1175                                           full_name_str ? " " : "",
1176                                           email_str ? email_str : "");
1177         }
1178
1179         g_free (full_name_str);
1180         deep_free_list (email_list);
1181
1182         g_object_set (cell, "text", string, NULL);
1183         g_free (string);
1184 }
1185
1186 static void
1187 destination_column_formatter (GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model,
1188                               GtkTreeIter *iter, ENameSelectorDialog *name_selector_dialog)
1189 {
1190         EDestinationStore *destination_store = E_DESTINATION_STORE (model);
1191         EDestination      *destination;
1192         GString           *buffer;
1193
1194         destination = e_destination_store_get_destination (destination_store, iter);
1195         g_assert (destination);
1196
1197         buffer = g_string_new (e_destination_get_name (destination));
1198
1199         if (!e_destination_is_evolution_list (destination)) {
1200                 const gchar *email;
1201
1202                 email = e_destination_get_email (destination);
1203                 if (email == NULL || *email == '\0')
1204                         email = "?";
1205                 g_string_append_printf (buffer, " <%s>", email);
1206         }
1207
1208         g_object_set (cell, "text", buffer->str, NULL);
1209         g_string_free (buffer, TRUE);
1210 }
1211
1212 /* ----------------------- *
1213  * ENameSelectorDialog API *
1214  * ----------------------- */
1215
1216 /**
1217  * e_name_selector_dialog_peek_model:
1218  * @name_selector_dialog: an #ENameSelectorDialog
1219  *
1220  * Gets the #ENameSelectorModel used by @name_selector_model.
1221  *
1222  * Return value: The #ENameSelectorModel being used.
1223  **/
1224 ENameSelectorModel *
1225 e_name_selector_dialog_peek_model (ENameSelectorDialog *name_selector_dialog)
1226 {
1227         g_return_val_if_fail (E_IS_NAME_SELECTOR_DIALOG (name_selector_dialog), NULL);
1228
1229         return name_selector_dialog->name_selector_model;
1230 }
1231
1232 /**
1233  * e_name_selector_dialog_set_model:
1234  * @name_selector_dialog: an #ENameSelectorDialog
1235  * @model: an #ENameSelectorModel
1236  *
1237  * Sets the model being used by @name_selector_dialog to @model.
1238  **/
1239 void
1240 e_name_selector_dialog_set_model (ENameSelectorDialog *name_selector_dialog,
1241                                   ENameSelectorModel  *model)
1242 {
1243         g_return_if_fail (E_IS_NAME_SELECTOR_DIALOG (name_selector_dialog));
1244         g_return_if_fail (E_IS_NAME_SELECTOR_MODEL (model));
1245
1246         if (model == name_selector_dialog->name_selector_model)
1247                 return;
1248
1249         shutdown_name_selector_model (name_selector_dialog);
1250         name_selector_dialog->name_selector_model = g_object_ref (model);
1251
1252         setup_name_selector_model (name_selector_dialog);
1253 }
1254
1255 /**
1256  * e_name_selector_dialog_set_destination_index:
1257  * @name_selector_dialog: an #ENameSelectorDialog
1258  * @index: index of the destination section, starting from 0.
1259  *
1260  * Sets the index number of the destination section. 
1261  **/
1262 void
1263 e_name_selector_dialog_set_destination_index (ENameSelectorDialog *name_selector_dialog,
1264                                               guint                index)
1265 {
1266         ENameSelectorDialogPrivate *priv;
1267
1268         priv = E_NAME_SELECTOR_DIALOG_GET_PRIVATE (name_selector_dialog);
1269
1270         if (index >= name_selector_dialog->sections->len)
1271                 return;
1272
1273         priv->destination_index = index;
1274 }
1275
1276 /* ----------------------------------- *
1277  * Widget creation functions for Glade *
1278  * ----------------------------------- */
1279
1280 #ifdef CATEGORIES_COMPONENTS_MOVED
1281
1282 GtkWidget *
1283 e_name_selector_dialog_create_categories (void)
1284 {
1285         ECategoriesMasterList *ecml;
1286         GtkWidget             *option_menu;
1287
1288         ecml = e_categories_master_list_wombat_new ();
1289         option_menu = e_categories_master_list_option_menu_new (ecml);
1290         g_object_unref (ecml);
1291
1292         return option_menu;
1293 }
1294
1295 #endif