1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /* e-name-selector-dialog.c - Dialog that lets user pick EDestinations.
5 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
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.
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.
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.
21 * Author: Hans Petter Jansson <hpj@novell.com>
24 #ifdef GTK_DISABLE_DEPRECATED
25 #undef GTK_DISABLE_DEPRECATED
30 #include <gdk/gdkkeysyms.h>
31 #include <glib/gi18n-lib.h>
33 #include <libebook/libebook.h>
34 #include <libebackend/libebackend.h>
36 #include "e-source-combo-box.h"
37 #include "e-destination-store.h"
38 #include "e-contact-store.h"
39 #include "e-client-utils.h"
40 #include "e-name-selector-dialog.h"
41 #include "e-name-selector-entry.h"
43 #define E_NAME_SELECTOR_DIALOG_GET_PRIVATE(obj) \
44 (G_TYPE_INSTANCE_GET_PRIVATE \
45 ((obj), E_TYPE_NAME_SELECTOR_DIALOG, ENameSelectorDialogPrivate))
50 GtkGrid *section_grid;
52 GtkButton *transfer_button;
53 GtkButton *remove_button;
54 GtkTreeView *destination_view;
61 ENameSelectorDialog *dlg_ptr;
64 struct _ENameSelectorDialogPrivate {
65 ESourceRegistry *registry;
66 ENameSelectorModel *name_selector_model;
67 GtkTreeModelSort *contact_sort;
68 GCancellable *cancellable;
70 GtkTreeView *contact_view;
71 GtkLabel *status_label;
72 GtkGrid *destination_vgrid;
73 GtkEntry *search_entry;
74 GtkSizeGroup *button_size_group;
75 GtkWidget *category_combobox;
76 GtkWidget *contact_window;
80 guint destination_index;
81 GSList *user_query_fields;
82 GtkSizeGroup *dest_label_size_group;
90 static void search_changed (ENameSelectorDialog *name_selector_dialog);
91 static void source_changed (ENameSelectorDialog *name_selector_dialog, ESourceComboBox *source_combo_box);
92 static void transfer_button_clicked (ENameSelectorDialog *name_selector_dialog, GtkButton *transfer_button);
93 static void contact_selection_changed (ENameSelectorDialog *name_selector_dialog);
94 static void setup_name_selector_model (ENameSelectorDialog *name_selector_dialog);
95 static void shutdown_name_selector_model (ENameSelectorDialog *name_selector_dialog);
96 static void contact_activated (ENameSelectorDialog *name_selector_dialog, GtkTreePath *path);
97 static void destination_activated (ENameSelectorDialog *name_selector_dialog, GtkTreePath *path,
98 GtkTreeViewColumn *column, GtkTreeView *tree_view);
99 static gboolean destination_key_press (ENameSelectorDialog *name_selector_dialog, GdkEventKey *event, GtkTreeView *tree_view);
100 static void remove_button_clicked (GtkButton *button, SelData *data);
101 static void remove_books (ENameSelectorDialog *name_selector_dialog);
102 static void contact_column_formatter (GtkTreeViewColumn *column, GtkCellRenderer *cell,
103 GtkTreeModel *model, GtkTreeIter *iter,
104 ENameSelectorDialog *name_selector_dialog);
105 static void destination_column_formatter (GtkTreeViewColumn *column, GtkCellRenderer *cell,
106 GtkTreeModel *model, GtkTreeIter *iter,
107 ENameSelectorDialog *name_selector_dialog);
109 /* ------------------ *
110 * Class/object setup *
111 * ------------------ */
113 G_DEFINE_TYPE_WITH_CODE (
115 e_name_selector_dialog,
117 G_IMPLEMENT_INTERFACE (
118 E_TYPE_EXTENSIBLE, NULL))
121 name_selector_dialog_populate_categories (ENameSelectorDialog *name_selector_dialog)
123 GtkWidget *combo_box;
124 GList *category_list, *iter;
126 /* "Any Category" is preloaded. */
127 combo_box = name_selector_dialog->priv->category_combobox;
128 if (gtk_combo_box_get_active (GTK_COMBO_BOX (combo_box)) == -1)
129 gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), 0);
131 /* Categories are already sorted. */
132 category_list = e_categories_get_list ();
133 for (iter = category_list; iter != NULL; iter = iter->next) {
134 /* Only add user-visible categories. */
135 if (!e_categories_is_searchable (iter->data))
138 gtk_combo_box_text_append_text (
139 GTK_COMBO_BOX_TEXT (combo_box), iter->data);
142 g_list_free (category_list);
144 g_signal_connect_swapped (
145 combo_box, "changed",
146 G_CALLBACK (search_changed), name_selector_dialog);
150 name_selector_dialog_set_registry (ENameSelectorDialog *name_selector_dialog,
151 ESourceRegistry *registry)
153 g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
154 g_return_if_fail (name_selector_dialog->priv->registry == NULL);
156 name_selector_dialog->priv->registry = g_object_ref (registry);
160 name_selector_dialog_set_property (GObject *object,
165 switch (property_id) {
167 name_selector_dialog_set_registry (
168 E_NAME_SELECTOR_DIALOG (object),
169 g_value_get_object (value));
173 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
177 name_selector_dialog_get_property (GObject *object,
182 switch (property_id) {
186 e_name_selector_dialog_get_registry (
187 E_NAME_SELECTOR_DIALOG (object)));
191 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
195 name_selector_dialog_dispose (GObject *object)
197 ENameSelectorDialogPrivate *priv;
199 priv = E_NAME_SELECTOR_DIALOG_GET_PRIVATE (object);
201 remove_books (E_NAME_SELECTOR_DIALOG (object));
202 shutdown_name_selector_model (E_NAME_SELECTOR_DIALOG (object));
204 if (priv->registry != NULL) {
205 g_object_unref (priv->registry);
206 priv->registry = NULL;
209 /* Chain up to parent's dispose() method. */
210 G_OBJECT_CLASS (e_name_selector_dialog_parent_class)->dispose (object);
214 name_selector_dialog_finalize (GObject *object)
216 ENameSelectorDialogPrivate *priv;
218 priv = E_NAME_SELECTOR_DIALOG_GET_PRIVATE (object);
220 g_slist_foreach (priv->user_query_fields, (GFunc) g_free, NULL);
221 g_slist_free (priv->user_query_fields);
223 g_array_free (priv->sections, TRUE);
224 g_object_unref (priv->button_size_group);
225 g_object_unref (priv->dest_label_size_group);
227 /* Chain up to parent's finalize() method. */
228 G_OBJECT_CLASS (e_name_selector_dialog_parent_class)->finalize (object);
232 name_selector_dialog_constructed (GObject *object)
234 ENameSelectorDialogPrivate *priv;
235 GtkTreeSelection *contact_selection;
236 GtkTreeViewColumn *column;
237 GtkCellRenderer *cell_renderer;
238 GtkTreeSelection *selection;
241 GtkWidget *name_selector_grid;
242 GtkWidget *show_contacts_label;
245 GtkWidget *show_contacts_grid;
246 GtkWidget *AddressBookLabel;
247 GtkWidget *label_category;
250 GtkWidget *label_search;
251 GtkWidget *source_menu_hgrid;
252 GtkWidget *combobox_category;
253 GtkWidget *label_contacts;
254 GtkWidget *scrolledwindow0;
255 GtkWidget *scrolledwindow1;
256 AtkRelationSet *tmp_relation_set;
257 AtkRelationType tmp_relationship;
258 AtkRelation *tmp_relation;
259 AtkObject *scrolledwindow1_relation_targets[1];
260 GtkWidget *source_tree_view;
261 GtkWidget *destination_vgrid;
262 GtkWidget *status_message;
263 GtkWidget *source_combo;
264 const gchar *extension_name;
266 priv = E_NAME_SELECTOR_DIALOG_GET_PRIVATE (object);
268 /* Chain up to parent's constructed() method. */
269 G_OBJECT_CLASS (e_name_selector_dialog_parent_class)->constructed (object);
271 name_selector_grid = g_object_new (GTK_TYPE_GRID,
272 "orientation", GTK_ORIENTATION_VERTICAL,
273 "column-homogeneous", FALSE,
276 gtk_widget_show (name_selector_grid);
277 gtk_container_set_border_width (GTK_CONTAINER (name_selector_grid), 0);
279 tmp_str = g_strconcat ("<b>", _("Show Contacts"), "</b>", NULL);
280 show_contacts_label = gtk_label_new (tmp_str);
281 gtk_widget_show (show_contacts_label);
282 gtk_container_add (GTK_CONTAINER (name_selector_grid), show_contacts_label);
283 gtk_label_set_use_markup (GTK_LABEL (show_contacts_label), TRUE);
284 gtk_misc_set_alignment (GTK_MISC (show_contacts_label), 0, 0.5);
287 hgrid = g_object_new (GTK_TYPE_GRID,
288 "orientation", GTK_ORIENTATION_HORIZONTAL,
289 "row-homogeneous", FALSE,
290 "column-spacing", 12,
292 gtk_widget_show (hgrid);
293 gtk_container_add (GTK_CONTAINER (name_selector_grid), hgrid);
295 label = gtk_label_new ("");
296 gtk_widget_show (label);
297 gtk_container_add (GTK_CONTAINER (hgrid), label);
299 show_contacts_grid = gtk_grid_new ();
300 gtk_widget_show (show_contacts_grid);
301 gtk_container_add (GTK_CONTAINER (hgrid), show_contacts_grid);
302 g_object_set (G_OBJECT (show_contacts_grid),
303 "column-spacing", 12,
306 "halign", GTK_ALIGN_FILL,
309 AddressBookLabel = gtk_label_new_with_mnemonic (_("Address B_ook:"));
310 gtk_widget_show (AddressBookLabel);
311 gtk_grid_attach (GTK_GRID (show_contacts_grid), AddressBookLabel, 0, 0, 1, 1);
312 gtk_widget_set_halign (AddressBookLabel, GTK_ALIGN_FILL);
313 gtk_label_set_justify (GTK_LABEL (AddressBookLabel), GTK_JUSTIFY_CENTER);
314 gtk_misc_set_alignment (GTK_MISC (AddressBookLabel), 0, 0.5);
316 label_category = gtk_label_new_with_mnemonic (_("Cat_egory:"));
317 gtk_widget_show (label_category);
318 gtk_grid_attach (GTK_GRID (show_contacts_grid), label_category, 0, 1, 1, 1);
319 gtk_widget_set_halign (label_category, GTK_ALIGN_FILL);
320 gtk_label_set_justify (GTK_LABEL (label_category), GTK_JUSTIFY_CENTER);
321 gtk_misc_set_alignment (GTK_MISC (label_category), 0, 0.5);
323 hgrid = g_object_new (GTK_TYPE_GRID,
324 "orientation", GTK_ORIENTATION_HORIZONTAL,
325 "row-homogeneous", FALSE,
326 "column-spacing", 12,
328 "halign", GTK_ALIGN_FILL,
330 gtk_widget_show (hgrid);
331 gtk_grid_attach (GTK_GRID (show_contacts_grid), hgrid, 1, 2, 1, 1);
333 search = gtk_entry_new ();
334 gtk_widget_show (search);
335 gtk_widget_set_hexpand (search, TRUE);
336 gtk_widget_set_halign (search, GTK_ALIGN_FILL);
337 gtk_container_add (GTK_CONTAINER (hgrid), search);
339 label_search = gtk_label_new_with_mnemonic (_("_Search:"));
340 gtk_widget_show (label_search);
341 gtk_grid_attach (GTK_GRID (show_contacts_grid), label_search, 0, 2, 1, 1);
342 gtk_widget_set_halign (label_search, GTK_ALIGN_FILL);
343 gtk_misc_set_alignment (GTK_MISC (label_search), 0, 0.5);
345 source_menu_hgrid = g_object_new (GTK_TYPE_GRID,
346 "orientation", GTK_ORIENTATION_HORIZONTAL,
347 "row-homogeneous", FALSE,
349 "halign", GTK_ALIGN_FILL,
350 "valign", GTK_ALIGN_FILL,
352 gtk_widget_show (source_menu_hgrid);
353 gtk_grid_attach (GTK_GRID (show_contacts_grid), source_menu_hgrid, 1, 0, 1, 1);
355 combobox_category = gtk_combo_box_text_new ();
356 gtk_widget_show (combobox_category);
357 g_object_set (G_OBJECT (combobox_category),
358 "halign", GTK_ALIGN_FILL,
359 "valign", GTK_ALIGN_FILL,
361 gtk_grid_attach (GTK_GRID (show_contacts_grid), combobox_category, 1, 1, 1, 1);
362 gtk_combo_box_text_append_text (
363 GTK_COMBO_BOX_TEXT (combobox_category), _("Any Category"));
365 tmp_str = g_strconcat ("<b>", _("Co_ntacts"), "</b>", NULL);
366 label_contacts = gtk_label_new_with_mnemonic (tmp_str);
367 gtk_widget_show (label_contacts);
368 gtk_container_add (GTK_CONTAINER (name_selector_grid), label_contacts);
369 gtk_label_set_use_markup (GTK_LABEL (label_contacts), TRUE);
370 gtk_misc_set_alignment (GTK_MISC (label_contacts), 0, 0.5);
373 scrolledwindow0 = gtk_scrolled_window_new (NULL, NULL);
374 priv->contact_window = scrolledwindow0;
375 gtk_widget_show (scrolledwindow0);
376 gtk_widget_set_vexpand (scrolledwindow0, TRUE);
377 gtk_widget_set_valign (scrolledwindow0, GTK_ALIGN_FILL);
378 gtk_container_add (GTK_CONTAINER (name_selector_grid), scrolledwindow0);
379 gtk_scrolled_window_set_policy (
380 GTK_SCROLLED_WINDOW (scrolledwindow0),
381 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
383 hgrid = g_object_new (GTK_TYPE_GRID,
384 "orientation", GTK_ORIENTATION_HORIZONTAL,
385 "row-homogeneous", FALSE,
386 "column-spacing", 12,
388 gtk_widget_show (hgrid);
389 gtk_scrolled_window_add_with_viewport (
390 GTK_SCROLLED_WINDOW (scrolledwindow0), hgrid);
392 label = gtk_label_new ("");
393 gtk_widget_show (label);
394 gtk_container_add (GTK_CONTAINER (hgrid), label);
396 scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
397 gtk_widget_show (scrolledwindow1);
398 gtk_container_add (GTK_CONTAINER (hgrid), scrolledwindow1);
399 gtk_widget_set_hexpand (scrolledwindow1, TRUE);
400 gtk_widget_set_halign (scrolledwindow1, GTK_ALIGN_FILL);
401 gtk_scrolled_window_set_policy (
402 GTK_SCROLLED_WINDOW (scrolledwindow1),
403 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
404 gtk_scrolled_window_set_shadow_type (
405 GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_SHADOW_IN);
407 source_tree_view = gtk_tree_view_new ();
408 gtk_widget_show (source_tree_view);
409 gtk_container_add (GTK_CONTAINER (scrolledwindow1), source_tree_view);
410 gtk_tree_view_set_headers_visible (
411 GTK_TREE_VIEW (source_tree_view), FALSE);
412 gtk_tree_view_set_enable_search (
413 GTK_TREE_VIEW (source_tree_view), FALSE);
415 destination_vgrid = g_object_new (GTK_TYPE_GRID,
416 "orientation", GTK_ORIENTATION_VERTICAL,
417 "column-homogeneous", TRUE,
420 "halign", GTK_ALIGN_FILL,
422 "valign", GTK_ALIGN_FILL,
424 gtk_widget_show (destination_vgrid);
425 gtk_container_add (GTK_CONTAINER (hgrid), destination_vgrid);
427 status_message = gtk_label_new ("");
428 gtk_widget_show (status_message);
429 gtk_container_add (GTK_CONTAINER (name_selector_grid), status_message);
430 gtk_label_set_use_markup (GTK_LABEL (status_message), TRUE);
431 gtk_misc_set_alignment (GTK_MISC (status_message), 0, 0.5);
432 gtk_misc_set_padding (GTK_MISC (status_message), 0, 3);
434 gtk_label_set_mnemonic_widget (GTK_LABEL (AddressBookLabel), source_menu_hgrid);
435 gtk_label_set_mnemonic_widget (GTK_LABEL (label_category), combobox_category);
436 gtk_label_set_mnemonic_widget (GTK_LABEL (label_search), search);
437 gtk_label_set_mnemonic_widget (GTK_LABEL (label_contacts), source_tree_view);
439 atko = gtk_widget_get_accessible (search);
440 atk_object_set_name (atko, _("Search"));
442 atko = gtk_widget_get_accessible (source_menu_hgrid);
443 atk_object_set_name (atko, _("Address Book"));
445 atko = gtk_widget_get_accessible (scrolledwindow1);
446 atk_object_set_name (atko, _("Contacts"));
447 tmp_relation_set = atk_object_ref_relation_set (atko);
448 scrolledwindow1_relation_targets[0] = gtk_widget_get_accessible (label_contacts);
449 tmp_relationship = atk_relation_type_for_name ("labelled-by");
450 tmp_relation = atk_relation_new (scrolledwindow1_relation_targets, 1, tmp_relationship);
451 atk_relation_set_add (tmp_relation_set, tmp_relation);
452 g_object_unref (G_OBJECT (tmp_relation));
453 g_object_unref (G_OBJECT (tmp_relation_set));
456 GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (object))),
457 name_selector_grid, TRUE, TRUE, 0);
459 /* Store pointers to relevant widgets */
461 priv->contact_view = GTK_TREE_VIEW (source_tree_view);
462 priv->status_label = GTK_LABEL (status_message);
463 priv->destination_vgrid = GTK_GRID (destination_vgrid);
464 priv->search_entry = GTK_ENTRY (search);
465 priv->category_combobox = combobox_category;
467 /* Create size group for transfer buttons */
469 priv->button_size_group =
470 gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
472 /* Create size group for destination labels */
474 priv->dest_label_size_group =
475 gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
477 /* Set up contacts view */
479 column = gtk_tree_view_column_new ();
480 cell_renderer = GTK_CELL_RENDERER (gtk_cell_renderer_text_new ());
481 gtk_tree_view_column_pack_start (column, cell_renderer, TRUE);
482 gtk_tree_view_column_set_cell_data_func (
483 column, cell_renderer, (GtkTreeCellDataFunc)
484 contact_column_formatter, object, NULL);
486 selection = gtk_tree_view_get_selection (priv->contact_view);
487 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
488 gtk_tree_view_append_column (priv->contact_view, column);
489 g_signal_connect_swapped (
490 priv->contact_view, "row-activated",
491 G_CALLBACK (contact_activated), object);
493 /* Listen for changes to the contact selection */
495 contact_selection = gtk_tree_view_get_selection (priv->contact_view);
496 g_signal_connect_swapped (
497 contact_selection, "changed",
498 G_CALLBACK (contact_selection_changed), object);
500 /* Set up our data structures */
502 priv->name_selector_model = e_name_selector_model_new ();
503 priv->sections = g_array_new (FALSE, FALSE, sizeof (Section));
505 setup_name_selector_model (E_NAME_SELECTOR_DIALOG (object));
507 /* Create source menu */
509 extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
510 source_combo = e_source_combo_box_new (priv->registry, extension_name);
511 g_signal_connect_swapped (
512 source_combo, "changed",
513 G_CALLBACK (source_changed), object);
515 source_changed (E_NAME_SELECTOR_DIALOG (object), E_SOURCE_COMBO_BOX (source_combo));
517 gtk_label_set_mnemonic_widget (GTK_LABEL (AddressBookLabel), source_combo);
518 gtk_widget_show (source_combo);
519 gtk_widget_set_hexpand (source_combo, TRUE);
520 gtk_widget_set_halign (source_combo, GTK_ALIGN_FILL);
521 gtk_container_add (GTK_CONTAINER (source_menu_hgrid), source_combo);
523 name_selector_dialog_populate_categories (
524 E_NAME_SELECTOR_DIALOG (object));
526 /* Set up search-as-you-type signal */
528 g_signal_connect_swapped (
530 G_CALLBACK (search_changed), object);
532 /* Display initial source */
534 source = e_source_registry_ref_default_address_book (priv->registry);
535 e_source_combo_box_set_active (
536 E_SOURCE_COMBO_BOX (source_combo), source);
537 g_object_unref (source);
539 /* Set up dialog defaults */
541 gtk_dialog_add_buttons (
543 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
546 /* Try to figure out a sane default size for the dialog. We used to hard
547 * code this to 512 so keep using 512 if the screen is big enough,
548 * otherwise use -1 (use as little as possible, use the
549 * GtkScrolledWindow's scrollbars).
551 * This should allow scrolling on tiny netbook resolutions and let
552 * others see as much of the dialog as possible.
554 * 600 pixels seems to be a good lower bound resolution to allow room
555 * above or below for other UI (window manager's?)
557 gtk_window_set_default_size (
558 GTK_WINDOW (object), 700,
559 gdk_screen_height () >= 600 ? 512 : -1);
561 gtk_dialog_set_default_response (
562 GTK_DIALOG (object), GTK_RESPONSE_CLOSE);
563 gtk_window_set_modal (GTK_WINDOW (object), TRUE);
564 gtk_window_set_resizable (GTK_WINDOW (object), TRUE);
565 gtk_container_set_border_width (GTK_CONTAINER (object), 4);
566 gtk_window_set_title (
568 _("Select Contacts from Address Book"));
569 gtk_widget_grab_focus (search);
571 e_extensible_load_extensions (E_EXTENSIBLE (object));
575 e_name_selector_dialog_class_init (ENameSelectorDialogClass *class)
577 GObjectClass *object_class;
579 g_type_class_add_private (class, sizeof (ENameSelectorDialogPrivate));
581 object_class = G_OBJECT_CLASS (class);
582 object_class->set_property = name_selector_dialog_set_property;
583 object_class->get_property = name_selector_dialog_get_property;
584 object_class->dispose = name_selector_dialog_dispose;
585 object_class->finalize = name_selector_dialog_finalize;
586 object_class->constructed = name_selector_dialog_constructed;
588 g_object_class_install_property (
591 g_param_spec_object (
594 "Data source registry",
595 E_TYPE_SOURCE_REGISTRY,
597 G_PARAM_CONSTRUCT_ONLY |
598 G_PARAM_STATIC_STRINGS));
602 e_name_selector_dialog_init (ENameSelectorDialog *name_selector_dialog)
604 name_selector_dialog->priv =
605 E_NAME_SELECTOR_DIALOG_GET_PRIVATE (name_selector_dialog);
609 * e_name_selector_dialog_new:
610 * @registry: an #ESourceRegistry
612 * Creates a new #ENameSelectorDialog.
614 * Returns: A new #ENameSelectorDialog.
616 ENameSelectorDialog *
617 e_name_selector_dialog_new (ESourceRegistry *registry)
619 g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
621 return g_object_new (
622 E_TYPE_NAME_SELECTOR_DIALOG,
623 "registry", registry, NULL);
627 * e_name_selector_dialog_get_registry:
628 * @name_selector_dialog: an #ENameSelectorDialog
630 * Returns the #ESourceRegistry that was passed to
631 * e_name_selector_dialog_new().
633 * Returns: the #ESourceRegistry
638 e_name_selector_dialog_get_registry (ENameSelectorDialog *name_selector_dialog)
640 g_return_val_if_fail (
641 E_IS_NAME_SELECTOR_DIALOG (name_selector_dialog), NULL);
643 return name_selector_dialog->priv->registry;
651 escape_sexp_string (const gchar *string)
654 gchar *encoded_string;
656 gstring = g_string_new ("");
657 e_sexp_encode_string (gstring, string);
659 encoded_string = gstring->str;
660 g_string_free (gstring, FALSE);
662 return encoded_string;
666 sort_iter_to_contact_store_iter (ENameSelectorDialog *name_selector_dialog,
670 ETreeModelGenerator *contact_filter;
671 GtkTreeIter child_iter;
674 contact_filter = e_name_selector_model_peek_contact_filter (
675 name_selector_dialog->priv->name_selector_model);
677 gtk_tree_model_sort_convert_iter_to_child_iter (
678 name_selector_dialog->priv->contact_sort, &child_iter, iter);
679 e_tree_model_generator_convert_iter_to_child_iter (
680 contact_filter, iter, &email_n_local, &child_iter);
683 *email_n = email_n_local;
687 add_destination (ENameSelectorModel *name_selector_model,
688 EDestinationStore *destination_store,
693 EDestination *destination;
694 GList *email_list, *nth;
696 /* get the correct index of an email in the contact */
697 email_list = e_name_selector_model_get_contact_emails_without_used (name_selector_model, contact, FALSE);
698 while (nth = g_list_nth (email_list, email_n), nth && nth->data == NULL) {
701 e_name_selector_model_free_emails_list (email_list);
703 /* Transfer (actually, copy into a destination and let the model filter out the
704 * source automatically) */
706 destination = e_destination_new ();
707 e_destination_set_contact (destination, contact, email_n);
709 e_destination_set_client (destination, client);
710 e_destination_store_append_destination (destination_store, destination);
711 g_object_unref (destination);
715 remove_books (ENameSelectorDialog *name_selector_dialog)
717 EContactStore *contact_store;
720 if (!name_selector_dialog->priv->name_selector_model)
723 contact_store = e_name_selector_model_peek_contact_store (
724 name_selector_dialog->priv->name_selector_model);
726 /* Remove books (should be just one) being viewed */
727 clients = e_contact_store_get_clients (contact_store);
728 for (l = clients; l; l = g_slist_next (l)) {
729 EBookClient *client = l->data;
730 e_contact_store_remove_client (contact_store, client);
732 g_slist_free (clients);
734 /* See if we have a book pending; stop loading it if so */
735 if (name_selector_dialog->priv->cancellable != NULL) {
736 g_cancellable_cancel (name_selector_dialog->priv->cancellable);
737 g_object_unref (name_selector_dialog->priv->cancellable);
738 name_selector_dialog->priv->cancellable = NULL;
742 /* ------------------ *
743 * Section management *
744 * ------------------ */
747 find_section_by_transfer_button (ENameSelectorDialog *name_selector_dialog,
748 GtkButton *transfer_button)
752 for (i = 0; i < name_selector_dialog->priv->sections->len; i++) {
753 Section *section = &g_array_index (
754 name_selector_dialog->priv->sections, Section, i);
756 if (section->transfer_button == transfer_button)
764 find_section_by_tree_view (ENameSelectorDialog *name_selector_dialog,
765 GtkTreeView *tree_view)
769 for (i = 0; i < name_selector_dialog->priv->sections->len; i++) {
770 Section *section = &g_array_index (
771 name_selector_dialog->priv->sections, Section, i);
773 if (section->destination_view == tree_view)
781 find_section_by_name (ENameSelectorDialog *name_selector_dialog,
786 for (i = 0; i < name_selector_dialog->priv->sections->len; i++) {
787 Section *section = &g_array_index (
788 name_selector_dialog->priv->sections, Section, i);
790 if (!strcmp (name, section->name))
798 selection_changed (GtkTreeSelection *selection,
801 GtkTreeSelection *contact_selection;
802 gboolean have_selection = FALSE;
804 contact_selection = gtk_tree_view_get_selection (data->view);
805 if (gtk_tree_selection_count_selected_rows (contact_selection) > 0)
806 have_selection = TRUE;
807 gtk_widget_set_sensitive (GTK_WIDGET (data->button), have_selection);
811 make_tree_view_for_section (ENameSelectorDialog *name_selector_dialog,
812 EDestinationStore *destination_store)
814 GtkTreeView *tree_view;
815 GtkTreeViewColumn *column;
816 GtkCellRenderer *cell_renderer;
818 tree_view = GTK_TREE_VIEW (gtk_tree_view_new ());
820 column = gtk_tree_view_column_new ();
821 cell_renderer = GTK_CELL_RENDERER (gtk_cell_renderer_text_new ());
822 gtk_tree_view_column_pack_start (column, cell_renderer, TRUE);
823 gtk_tree_view_column_set_cell_data_func (
824 column, cell_renderer,
825 (GtkTreeCellDataFunc) destination_column_formatter,
826 name_selector_dialog, NULL);
827 gtk_tree_view_append_column (tree_view, column);
828 gtk_tree_view_set_headers_visible (tree_view, FALSE);
829 gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (destination_store));
835 setup_section_button (ENameSelectorDialog *name_selector_dialog,
838 const gchar *label_text,
839 const gchar *icon_name,
840 gboolean icon_before_label)
842 GtkWidget *alignment;
847 gtk_size_group_add_widget (
848 name_selector_dialog->priv->button_size_group,
849 GTK_WIDGET (button));
851 alignment = gtk_alignment_new (halign, 0.5, 0.0, 0.0);
852 gtk_container_add (GTK_CONTAINER (button), GTK_WIDGET (alignment));
854 hgrid = g_object_new (GTK_TYPE_GRID,
855 "orientation", GTK_ORIENTATION_HORIZONTAL,
856 "row-homogeneous", FALSE,
859 gtk_widget_show (hgrid);
860 gtk_container_add (GTK_CONTAINER (alignment), hgrid);
862 label = gtk_label_new_with_mnemonic (label_text);
863 gtk_widget_show (label);
865 image = gtk_image_new_from_stock (icon_name, GTK_ICON_SIZE_BUTTON);
866 gtk_widget_show (image);
868 if (icon_before_label) {
869 gtk_container_add (GTK_CONTAINER (hgrid), image);
870 gtk_container_add (GTK_CONTAINER (hgrid), label);
872 gtk_container_add (GTK_CONTAINER (hgrid), label);
873 gtk_container_add (GTK_CONTAINER (hgrid), image);
878 add_section (ENameSelectorDialog *name_selector_dialog,
880 const gchar *pretty_name,
881 EDestinationStore *destination_store)
883 ENameSelectorDialogPrivate *priv;
886 GtkWidget *alignment;
887 GtkWidget *scrollwin;
889 GtkTreeSelection *selection;
893 g_assert (name != NULL);
894 g_assert (pretty_name != NULL);
895 g_assert (E_IS_DESTINATION_STORE (destination_store));
897 priv = E_NAME_SELECTOR_DIALOG_GET_PRIVATE (name_selector_dialog);
899 memset (§ion, 0, sizeof (Section));
901 section.name = g_strdup (name);
902 section.section_grid = g_object_new (GTK_TYPE_GRID,
903 "orientation", GTK_ORIENTATION_HORIZONTAL,
904 "row-homogeneous", FALSE,
905 "column-spacing", 12,
907 "valign", GTK_ALIGN_FILL,
909 section.label = GTK_LABEL (gtk_label_new_with_mnemonic (pretty_name));
910 section.transfer_button = GTK_BUTTON (gtk_button_new ());
911 section.remove_button = GTK_BUTTON (gtk_button_new ());
912 section.destination_view = make_tree_view_for_section (name_selector_dialog, destination_store);
914 gtk_label_set_mnemonic_widget (GTK_LABEL (section.label), GTK_WIDGET (section.destination_view));
916 if (pango_parse_markup (pretty_name, -1, '_', NULL,
917 &text, NULL, NULL)) {
918 atk_object_set_name (gtk_widget_get_accessible (
919 GTK_WIDGET (section.destination_view)), text);
923 /* Set up transfer button */
924 g_signal_connect_swapped (
925 section.transfer_button, "clicked",
926 G_CALLBACK (transfer_button_clicked), name_selector_dialog);
928 /*data for the remove callback*/
929 data = g_malloc0 (sizeof (SelData));
930 data->view = section.destination_view;
931 data->dlg_ptr = name_selector_dialog;
933 /*Associate to an object destroy so that it gets freed*/
934 g_object_set_data_full ((GObject *) section.destination_view, "sel-remove-data", data, g_free);
937 section.remove_button, "clicked",
938 G_CALLBACK (remove_button_clicked), data);
940 /* Alignment and vgrid for the add/remove buttons */
942 alignment = gtk_alignment_new (0.5, 0.0, 0.0, 0.0);
943 gtk_container_add (GTK_CONTAINER (section.section_grid), alignment);
945 vgrid = g_object_new (GTK_TYPE_GRID,
946 "orientation", GTK_ORIENTATION_VERTICAL,
947 "column-homogeneous", TRUE,
951 gtk_container_add (GTK_CONTAINER (alignment), vgrid);
954 gtk_container_add (GTK_CONTAINER (vgrid), GTK_WIDGET (section.transfer_button));
955 setup_section_button (name_selector_dialog, section.transfer_button, 0.7, _("_Add"), "gtk-go-forward", FALSE);
957 /* "Remove" button */
958 gtk_container_add (GTK_CONTAINER (vgrid), GTK_WIDGET (section.remove_button));
959 setup_section_button (name_selector_dialog, section.remove_button, 0.5, _("_Remove"), "gtk-go-back", TRUE);
960 gtk_widget_set_sensitive (GTK_WIDGET (section.remove_button), FALSE);
962 /* hgrid for label and scrolled window. This is a separate hgrid, instead
963 * of just using the section.section_grid directly, as it has a different
967 hgrid = g_object_new (GTK_TYPE_GRID,
968 "orientation", GTK_ORIENTATION_HORIZONTAL,
969 "row-homogeneous", FALSE,
972 "valign", GTK_ALIGN_FILL,
974 gtk_container_add (GTK_CONTAINER (section.section_grid), hgrid);
978 gtk_size_group_add_widget (priv->dest_label_size_group, GTK_WIDGET (section.label));
980 gtk_misc_set_alignment (GTK_MISC (section.label), 0.0, 0.0);
981 gtk_container_add (GTK_CONTAINER (hgrid), GTK_WIDGET (section.label));
983 /* Treeview in a scrolled window */
984 scrollwin = gtk_scrolled_window_new (NULL, NULL);
985 gtk_container_add (GTK_CONTAINER (hgrid), scrollwin);
986 gtk_widget_set_hexpand (scrollwin, TRUE);
987 gtk_widget_set_halign (scrollwin, GTK_ALIGN_FILL);
988 gtk_widget_set_vexpand (scrollwin, TRUE);
989 gtk_widget_set_valign (scrollwin, GTK_ALIGN_FILL);
990 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
991 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollwin), GTK_SHADOW_IN);
992 gtk_container_add (GTK_CONTAINER (scrollwin), GTK_WIDGET (section.destination_view));
994 /*data for 'changed' callback*/
995 data = g_malloc0 (sizeof (SelData));
996 data->view = section.destination_view;
997 data->button = section.remove_button;
998 g_object_set_data_full ((GObject *) section.destination_view, "sel-change-data", data, g_free);
999 selection = gtk_tree_view_get_selection (section.destination_view);
1000 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
1003 selection, "changed",
1004 G_CALLBACK (selection_changed), data);
1006 g_signal_connect_swapped (
1007 section.destination_view, "row-activated",
1008 G_CALLBACK (destination_activated), name_selector_dialog);
1009 g_signal_connect_swapped (
1010 section.destination_view, "key-press-event",
1011 G_CALLBACK (destination_key_press), name_selector_dialog);
1015 gtk_widget_show_all (GTK_WIDGET (section.section_grid));
1017 /* Pack this section's box into the dialog */
1018 gtk_container_add (GTK_CONTAINER (name_selector_dialog->priv->destination_vgrid), GTK_WIDGET (section.section_grid));
1019 g_object_set (G_OBJECT (section.section_grid),
1021 "valign", GTK_ALIGN_FILL,
1024 g_array_append_val (name_selector_dialog->priv->sections, section);
1026 /* Make sure UI is consistent */
1027 contact_selection_changed (name_selector_dialog);
1029 return name_selector_dialog->priv->sections->len - 1;
1033 free_section (ENameSelectorDialog *name_selector_dialog,
1039 g_assert (n < name_selector_dialog->priv->sections->len);
1041 section = &g_array_index (
1042 name_selector_dialog->priv->sections, Section, n);
1044 g_free (section->name);
1045 gtk_widget_destroy (GTK_WIDGET (section->section_grid));
1049 model_section_added (ENameSelectorDialog *name_selector_dialog,
1053 EDestinationStore *destination_store;
1055 e_name_selector_model_peek_section (
1056 name_selector_dialog->priv->name_selector_model,
1057 name, &pretty_name, &destination_store);
1058 add_section (name_selector_dialog, name, pretty_name, destination_store);
1059 g_free (pretty_name);
1063 model_section_removed (ENameSelectorDialog *name_selector_dialog,
1068 section_index = find_section_by_name (name_selector_dialog, name);
1069 g_assert (section_index >= 0);
1071 free_section (name_selector_dialog, section_index);
1072 g_array_remove_index (
1073 name_selector_dialog->priv->sections, section_index);
1076 /* -------------------- *
1077 * Addressbook selector *
1078 * -------------------- */
1081 view_progress (EBookClientView *view,
1083 const gchar *message,
1084 ENameSelectorDialog *dialog)
1086 if (message == NULL)
1087 gtk_label_set_text (dialog->priv->status_label, "");
1089 gtk_label_set_text (dialog->priv->status_label, message);
1093 view_complete (EBookClientView *view,
1094 const GError *error,
1095 ENameSelectorDialog *dialog)
1097 view_progress (view, -1, NULL, dialog);
1101 start_client_view_cb (EContactStore *store,
1102 EBookClientView *client_view,
1103 ENameSelectorDialog *name_selector_dialog)
1106 client_view, "progress",
1107 G_CALLBACK (view_progress), name_selector_dialog);
1110 client_view, "complete",
1111 G_CALLBACK (view_complete), name_selector_dialog);
1115 stop_client_view_cb (EContactStore *store,
1116 EBookClientView *client_view,
1117 ENameSelectorDialog *name_selector_dialog)
1119 g_signal_handlers_disconnect_by_func (client_view, view_progress, name_selector_dialog);
1120 g_signal_handlers_disconnect_by_func (client_view, view_complete, name_selector_dialog);
1124 book_loaded_cb (GObject *source_object,
1125 GAsyncResult *result,
1128 ENameSelectorDialog *name_selector_dialog = user_data;
1129 EClient *client = NULL;
1130 EBookClient *book_client;
1131 EContactStore *store;
1132 ENameSelectorModel *model;
1133 GError *error = NULL;
1135 e_client_utils_open_new_finish (E_SOURCE (source_object), result, &client, &error);
1137 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
1138 g_warn_if_fail (client == NULL);
1139 g_error_free (error);
1143 if (error != NULL) {
1146 message = g_strdup_printf (
1147 _("Error loading address book: %s"), error->message);
1148 gtk_label_set_text (
1149 name_selector_dialog->priv->status_label, message);
1152 g_warn_if_fail (client == NULL);
1153 g_error_free (error);
1157 book_client = E_BOOK_CLIENT (client);
1159 g_warn_if_fail (book_client != NULL);
1163 model = name_selector_dialog->priv->name_selector_model;
1164 store = e_name_selector_model_peek_contact_store (model);
1165 e_contact_store_add_client (store, book_client);
1166 g_object_unref (book_client);
1169 g_object_unref (name_selector_dialog);
1173 source_changed (ENameSelectorDialog *name_selector_dialog,
1174 ESourceComboBox *source_combo_box)
1176 GCancellable *cancellable;
1180 source = e_source_combo_box_ref_active (source_combo_box);
1182 parent = gtk_widget_get_toplevel (GTK_WIDGET (name_selector_dialog));
1183 parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
1185 /* Remove any previous books being shown or loaded */
1186 remove_books (name_selector_dialog);
1191 cancellable = g_cancellable_new ();
1192 name_selector_dialog->priv->cancellable = cancellable;
1194 /* Start loading selected book */
1195 e_client_utils_open_new (
1196 source, E_CLIENT_SOURCE_TYPE_CONTACTS, TRUE, cancellable,
1197 book_loaded_cb, g_object_ref (name_selector_dialog));
1199 g_object_unref (source);
1202 /* --------------- *
1204 * --------------- */
1207 search_changed (ENameSelectorDialog *name_selector_dialog)
1209 ENameSelectorDialogPrivate *priv = E_NAME_SELECTOR_DIALOG_GET_PRIVATE (name_selector_dialog);
1210 EContactStore *contact_store;
1211 EBookQuery *book_query;
1212 GtkWidget *combo_box;
1214 gchar *text_escaped;
1215 gchar *query_string;
1217 gchar *category_escaped;
1218 gchar *user_fields_str;
1220 combo_box = priv->category_combobox;
1221 if (gtk_combo_box_get_active (GTK_COMBO_BOX (combo_box)) == -1)
1222 gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), 0);
1224 category = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (combo_box));
1225 category_escaped = escape_sexp_string (category);
1227 text = gtk_entry_get_text (name_selector_dialog->priv->search_entry);
1228 text_escaped = escape_sexp_string (text);
1230 user_fields_str = ens_util_populate_user_query_fields (priv->user_query_fields, text, text_escaped);
1232 if (g_strcmp0 (category, _("Any Category")) == 0)
1233 query_string = g_strdup_printf (
1234 "(or (beginswith \"file_as\" %s) "
1235 " (beginswith \"full_name\" %s) "
1236 " (beginswith \"email\" %s) "
1237 " (beginswith \"nickname\" %s)%s))",
1238 text_escaped, text_escaped,
1239 text_escaped, text_escaped,
1240 user_fields_str ? user_fields_str : "");
1242 query_string = g_strdup_printf (
1243 "(and (is \"category_list\" %s) "
1244 "(or (beginswith \"file_as\" %s) "
1245 " (beginswith \"full_name\" %s) "
1246 " (beginswith \"email\" %s) "
1247 " (beginswith \"nickname\" %s)%s))",
1248 category_escaped, text_escaped, text_escaped,
1249 text_escaped, text_escaped,
1250 user_fields_str ? user_fields_str : "");
1252 book_query = e_book_query_from_string (query_string);
1254 contact_store = e_name_selector_model_peek_contact_store (
1255 name_selector_dialog->priv->name_selector_model);
1256 e_contact_store_set_query (contact_store, book_query);
1257 e_book_query_unref (book_query);
1259 g_free (query_string);
1260 g_free (text_escaped);
1261 g_free (category_escaped);
1263 g_free (user_fields_str);
1267 contact_selection_changed (ENameSelectorDialog *name_selector_dialog)
1269 GtkTreeSelection *contact_selection;
1270 gboolean have_selection = FALSE;
1273 contact_selection = gtk_tree_view_get_selection (
1274 name_selector_dialog->priv->contact_view);
1275 if (gtk_tree_selection_count_selected_rows (contact_selection))
1276 have_selection = TRUE;
1278 for (i = 0; i < name_selector_dialog->priv->sections->len; i++) {
1279 Section *section = &g_array_index (
1280 name_selector_dialog->priv->sections, Section, i);
1281 gtk_widget_set_sensitive (GTK_WIDGET (section->transfer_button), have_selection);
1286 contact_activated (ENameSelectorDialog *name_selector_dialog,
1289 EContactStore *contact_store;
1290 EDestinationStore *destination_store;
1296 /* When a contact is activated, we transfer it to the first destination on our list */
1298 contact_store = e_name_selector_model_peek_contact_store (
1299 name_selector_dialog->priv->name_selector_model);
1301 /* If we have no sections, we can't transfer */
1302 if (name_selector_dialog->priv->sections->len == 0)
1305 /* Get the contact to be transferred */
1307 if (!gtk_tree_model_get_iter (
1308 GTK_TREE_MODEL (name_selector_dialog->priv->contact_sort),
1310 g_assert_not_reached ();
1312 sort_iter_to_contact_store_iter (name_selector_dialog, &iter, &email_n);
1314 contact = e_contact_store_get_contact (contact_store, &iter);
1316 g_warning ("ENameSelectorDialog could not get selected contact!");
1320 section = &g_array_index (
1321 name_selector_dialog->priv->sections,
1322 Section, name_selector_dialog->priv->destination_index);
1323 if (!e_name_selector_model_peek_section (
1324 name_selector_dialog->priv->name_selector_model,
1325 section->name, NULL, &destination_store)) {
1326 g_warning ("ENameSelectorDialog has a section unknown to the model!");
1331 name_selector_dialog->priv->name_selector_model,
1332 destination_store, contact, email_n,
1333 e_contact_store_get_client (contact_store, &iter));
1337 destination_activated (ENameSelectorDialog *name_selector_dialog,
1339 GtkTreeViewColumn *column,
1340 GtkTreeView *tree_view)
1343 EDestinationStore *destination_store;
1344 EDestination *destination;
1348 /* When a destination is activated, we remove it from the section */
1350 section_index = find_section_by_tree_view (
1351 name_selector_dialog, tree_view);
1352 if (section_index < 0) {
1353 g_warning ("ENameSelectorDialog got activation from unknown view!");
1357 section = &g_array_index (
1358 name_selector_dialog->priv->sections, Section, section_index);
1359 if (!e_name_selector_model_peek_section (
1360 name_selector_dialog->priv->name_selector_model,
1361 section->name, NULL, &destination_store)) {
1362 g_warning ("ENameSelectorDialog has a section unknown to the model!");
1366 if (!gtk_tree_model_get_iter (
1367 GTK_TREE_MODEL (destination_store), &iter, path))
1368 g_assert_not_reached ();
1370 destination = e_destination_store_get_destination (
1371 destination_store, &iter);
1372 g_assert (destination);
1374 e_destination_store_remove_destination (
1375 destination_store, destination);
1379 remove_selection (ENameSelectorDialog *name_selector_dialog,
1380 GtkTreeView *tree_view)
1383 EDestinationStore *destination_store;
1384 EDestination *destination;
1386 GtkTreeSelection *selection;
1389 section_index = find_section_by_tree_view (
1390 name_selector_dialog, tree_view);
1391 if (section_index < 0) {
1392 g_warning ("ENameSelectorDialog got key press from unknown view!");
1396 section = &g_array_index (
1397 name_selector_dialog->priv->sections, Section, section_index);
1398 if (!e_name_selector_model_peek_section (
1399 name_selector_dialog->priv->name_selector_model,
1400 section->name, NULL, &destination_store)) {
1401 g_warning ("ENameSelectorDialog has a section unknown to the model!");
1405 selection = gtk_tree_view_get_selection (tree_view);
1406 if (!gtk_tree_selection_count_selected_rows (selection)) {
1407 g_warning ("ENameSelectorDialog remove button clicked, but no selection!");
1411 rows = gtk_tree_selection_get_selected_rows (selection, NULL);
1412 rows = g_list_reverse (rows);
1414 for (l = rows; l; l = g_list_next (l)) {
1416 GtkTreePath *path = l->data;
1418 if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (destination_store),
1420 g_assert_not_reached ();
1422 gtk_tree_path_free (path);
1424 destination = e_destination_store_get_destination (
1425 destination_store, &iter);
1426 g_assert (destination);
1428 e_destination_store_remove_destination (
1429 destination_store, destination);
1437 remove_button_clicked (GtkButton *button,
1441 ENameSelectorDialog *name_selector_dialog;
1444 name_selector_dialog = data->dlg_ptr;
1445 remove_selection (name_selector_dialog, view);
1449 destination_key_press (ENameSelectorDialog *name_selector_dialog,
1451 GtkTreeView *tree_view)
1454 /* we only care about DEL key */
1455 if (event->keyval != GDK_KEY_Delete)
1457 return remove_selection (name_selector_dialog, tree_view);
1462 transfer_button_clicked (ENameSelectorDialog *name_selector_dialog,
1463 GtkButton *transfer_button)
1465 EContactStore *contact_store;
1466 EDestinationStore *destination_store;
1467 GtkTreeSelection *selection;
1474 /* Get the contact to be transferred */
1476 contact_store = e_name_selector_model_peek_contact_store (
1477 name_selector_dialog->priv->name_selector_model);
1478 selection = gtk_tree_view_get_selection (
1479 name_selector_dialog->priv->contact_view);
1481 if (!gtk_tree_selection_count_selected_rows (selection)) {
1482 g_warning ("ENameSelectorDialog transfer button clicked, but no selection!");
1486 /* Get the target section */
1487 section_index = find_section_by_transfer_button (
1488 name_selector_dialog, transfer_button);
1489 if (section_index < 0) {
1490 g_warning ("ENameSelectorDialog got click from unknown button!");
1494 section = &g_array_index (
1495 name_selector_dialog->priv->sections, Section, section_index);
1496 if (!e_name_selector_model_peek_section (
1497 name_selector_dialog->priv->name_selector_model,
1498 section->name, NULL, &destination_store)) {
1499 g_warning ("ENameSelectorDialog has a section unknown to the model!");
1503 rows = gtk_tree_selection_get_selected_rows (selection, NULL);
1504 rows = g_list_reverse (rows);
1506 for (l = rows; l; l = g_list_next (l)) {
1508 GtkTreePath *path = l->data;
1510 if (!gtk_tree_model_get_iter (
1511 GTK_TREE_MODEL (name_selector_dialog->priv->contact_sort),
1513 gtk_tree_path_free (path);
1517 gtk_tree_path_free (path);
1518 sort_iter_to_contact_store_iter (name_selector_dialog, &iter, &email_n);
1520 contact = e_contact_store_get_contact (contact_store, &iter);
1522 g_warning ("ENameSelectorDialog could not get selected contact!");
1528 name_selector_dialog->priv->name_selector_model,
1529 destination_store, contact, email_n,
1530 e_contact_store_get_client (contact_store, &iter));
1535 /* --------------------- *
1536 * Main model management *
1537 * --------------------- */
1540 setup_name_selector_model (ENameSelectorDialog *name_selector_dialog)
1542 ETreeModelGenerator *contact_filter;
1543 EContactStore *contact_store;
1544 GList *new_sections;
1547 /* Create new destination sections in UI */
1549 new_sections = e_name_selector_model_list_sections (
1550 name_selector_dialog->priv->name_selector_model);
1552 for (l = new_sections; l; l = g_list_next (l)) {
1553 gchar *name = l->data;
1555 EDestinationStore *destination_store;
1557 e_name_selector_model_peek_section (
1558 name_selector_dialog->priv->name_selector_model,
1559 name, &pretty_name, &destination_store);
1561 add_section (name_selector_dialog, name, pretty_name, destination_store);
1563 g_free (pretty_name);
1567 g_list_free (new_sections);
1569 /* Connect to section add/remove signals */
1571 g_signal_connect_swapped (
1572 name_selector_dialog->priv->name_selector_model, "section-added",
1573 G_CALLBACK (model_section_added), name_selector_dialog);
1574 g_signal_connect_swapped (
1575 name_selector_dialog->priv->name_selector_model, "section-removed",
1576 G_CALLBACK (model_section_removed), name_selector_dialog);
1578 /* Get contact store and its filter wrapper */
1580 contact_filter = e_name_selector_model_peek_contact_filter (
1581 name_selector_dialog->priv->name_selector_model);
1583 /* Create sorting model on top of filter, assign it to view */
1585 name_selector_dialog->priv->contact_sort = GTK_TREE_MODEL_SORT (
1586 gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (contact_filter)));
1588 /* sort on full name as we display full name in name selector dialog */
1589 gtk_tree_sortable_set_sort_column_id (
1590 GTK_TREE_SORTABLE (name_selector_dialog->priv->contact_sort),
1591 E_CONTACT_FULL_NAME, GTK_SORT_ASCENDING);
1593 gtk_tree_view_set_model (
1594 name_selector_dialog->priv->contact_view,
1595 GTK_TREE_MODEL (name_selector_dialog->priv->contact_sort));
1597 contact_store = e_name_selector_model_peek_contact_store (name_selector_dialog->priv->name_selector_model);
1598 if (contact_store) {
1599 g_signal_connect (contact_store, "start-client-view", G_CALLBACK (start_client_view_cb), name_selector_dialog);
1600 g_signal_connect (contact_store, "stop-client-view", G_CALLBACK (stop_client_view_cb), name_selector_dialog);
1603 /* Make sure UI is consistent */
1605 search_changed (name_selector_dialog);
1606 contact_selection_changed (name_selector_dialog);
1610 shutdown_name_selector_model (ENameSelectorDialog *name_selector_dialog)
1614 /* Rid UI of previous destination sections */
1616 for (i = 0; i < name_selector_dialog->priv->sections->len; i++)
1617 free_section (name_selector_dialog, i);
1619 g_array_set_size (name_selector_dialog->priv->sections, 0);
1621 /* Free sorting model */
1623 if (name_selector_dialog->priv->contact_sort) {
1624 g_object_unref (name_selector_dialog->priv->contact_sort);
1625 name_selector_dialog->priv->contact_sort = NULL;
1628 /* Free backend model */
1630 if (name_selector_dialog->priv->name_selector_model) {
1631 EContactStore *contact_store;
1633 contact_store = e_name_selector_model_peek_contact_store (name_selector_dialog->priv->name_selector_model);
1634 if (contact_store) {
1635 g_signal_handlers_disconnect_by_func (contact_store, start_client_view_cb, name_selector_dialog);
1636 g_signal_handlers_disconnect_by_func (contact_store, stop_client_view_cb, name_selector_dialog);
1639 g_signal_handlers_disconnect_matched (
1640 name_selector_dialog->priv->name_selector_model,
1641 G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, name_selector_dialog);
1643 g_object_unref (name_selector_dialog->priv->name_selector_model);
1644 name_selector_dialog->priv->name_selector_model = NULL;
1649 contact_column_formatter (GtkTreeViewColumn *column,
1650 GtkCellRenderer *cell,
1651 GtkTreeModel *model,
1653 ENameSelectorDialog *name_selector_dialog)
1655 EContactStore *contact_store;
1657 GtkTreeIter contact_store_iter;
1660 gchar *full_name_str;
1664 contact_store_iter = *iter;
1665 sort_iter_to_contact_store_iter (
1666 name_selector_dialog, &contact_store_iter, &email_n);
1668 contact_store = e_name_selector_model_peek_contact_store (
1669 name_selector_dialog->priv->name_selector_model);
1670 contact = e_contact_store_get_contact (
1671 contact_store, &contact_store_iter);
1672 email_list = e_name_selector_model_get_contact_emails_without_used (
1673 name_selector_dialog->priv->name_selector_model, contact, TRUE);
1674 email_str = g_list_nth_data (email_list, email_n);
1675 full_name_str = e_contact_get (contact, E_CONTACT_FULL_NAME);
1677 if (e_contact_get (contact, E_CONTACT_IS_LIST)) {
1679 full_name_str = e_contact_get (contact, E_CONTACT_FILE_AS);
1680 string = g_strdup_printf ("%s", full_name_str ? full_name_str : "?");
1682 string = g_strdup_printf (
1683 "%s%s<%s>", full_name_str ? full_name_str : "",
1684 full_name_str ? " " : "",
1685 email_str ? email_str : "");
1688 g_free (full_name_str);
1689 e_name_selector_model_free_emails_list (email_list);
1691 g_object_set (cell, "text", string, NULL);
1696 destination_column_formatter (GtkTreeViewColumn *column,
1697 GtkCellRenderer *cell,
1698 GtkTreeModel *model,
1700 ENameSelectorDialog *name_selector_dialog)
1702 EDestinationStore *destination_store = E_DESTINATION_STORE (model);
1703 EDestination *destination;
1706 destination = e_destination_store_get_destination (destination_store, iter);
1707 g_assert (destination);
1709 buffer = g_string_new (e_destination_get_name (destination));
1711 if (!e_destination_is_evolution_list (destination)) {
1714 email = e_destination_get_email (destination);
1715 if (email == NULL || *email == '\0')
1717 g_string_append_printf (buffer, " <%s>", email);
1720 g_object_set (cell, "text", buffer->str, NULL);
1721 g_string_free (buffer, TRUE);
1724 /* ----------------------- *
1725 * ENameSelectorDialog API *
1726 * ----------------------- */
1729 * e_name_selector_dialog_peek_model:
1730 * @name_selector_dialog: an #ENameSelectorDialog
1732 * Gets the #ENameSelectorModel used by @name_selector_model.
1734 * Returns: The #ENameSelectorModel being used.
1736 ENameSelectorModel *
1737 e_name_selector_dialog_peek_model (ENameSelectorDialog *name_selector_dialog)
1739 g_return_val_if_fail (E_IS_NAME_SELECTOR_DIALOG (name_selector_dialog), NULL);
1741 return name_selector_dialog->priv->name_selector_model;
1745 * e_name_selector_dialog_set_model:
1746 * @name_selector_dialog: an #ENameSelectorDialog
1747 * @model: an #ENameSelectorModel
1749 * Sets the model being used by @name_selector_dialog to @model.
1752 e_name_selector_dialog_set_model (ENameSelectorDialog *name_selector_dialog,
1753 ENameSelectorModel *model)
1755 g_return_if_fail (E_IS_NAME_SELECTOR_DIALOG (name_selector_dialog));
1756 g_return_if_fail (E_IS_NAME_SELECTOR_MODEL (model));
1758 if (model == name_selector_dialog->priv->name_selector_model)
1761 shutdown_name_selector_model (name_selector_dialog);
1762 name_selector_dialog->priv->name_selector_model = g_object_ref (model);
1764 setup_name_selector_model (name_selector_dialog);
1768 * e_name_selector_dialog_set_destination_index:
1769 * @name_selector_dialog: an #ENameSelectorDialog
1770 * @index: index of the destination section, starting from 0.
1772 * Sets the index number of the destination section.
1775 e_name_selector_dialog_set_destination_index (ENameSelectorDialog *name_selector_dialog,
1778 g_return_if_fail (E_IS_NAME_SELECTOR_DIALOG (name_selector_dialog));
1780 if (index >= name_selector_dialog->priv->sections->len)
1783 name_selector_dialog->priv->destination_index = index;
1787 * e_name_selector_dialog_set_scrolling_policy:
1788 * @name_selector_dialog: an #ENameSelectorDialog
1789 * @hscrollbar_policy: scrolling policy for horizontal bar of the contacts window.
1790 * @vscrollbar_policy: scrolling policy for vertical bar of the contacts window.
1792 * Sets the scrolling policy for the contacts section.
1797 e_name_selector_dialog_set_scrolling_policy (ENameSelectorDialog *name_selector_dialog,
1798 GtkPolicyType hscrollbar_policy,
1799 GtkPolicyType vscrollbar_policy)
1801 GtkScrolledWindow *win = GTK_SCROLLED_WINDOW (name_selector_dialog->priv->contact_window);
1803 gtk_scrolled_window_set_policy (win, hscrollbar_policy, vscrollbar_policy);
1807 * e_name_selector_dialog_get_section_visible:
1808 * @name_selector_dialog: an #ENameSelectorDialog
1809 * @name: name of the section
1811 * Returns: whether section named @name is visible in the dialog.
1816 e_name_selector_dialog_get_section_visible (ENameSelectorDialog *name_selector_dialog,
1822 g_return_val_if_fail (E_IS_NAME_SELECTOR_DIALOG (name_selector_dialog), FALSE);
1823 g_return_val_if_fail (name != NULL, FALSE);
1825 index = find_section_by_name (name_selector_dialog, name);
1826 g_return_val_if_fail (index != -1, FALSE);
1828 section = &g_array_index (name_selector_dialog->priv->sections, Section, index);
1829 return gtk_widget_get_visible (GTK_WIDGET (section->section_grid));
1833 * e_name_selector_dialog_set_section_visible:
1834 * @name_selector_dialog: an #ENameSelectorDialog
1835 * @name: name of the section
1836 * @visible: whether to show or hide the section
1838 * Shows or hides section named @name in the dialog.
1843 e_name_selector_dialog_set_section_visible (ENameSelectorDialog *name_selector_dialog,
1850 g_return_if_fail (E_IS_NAME_SELECTOR_DIALOG (name_selector_dialog));
1851 g_return_if_fail (name != NULL);
1853 index = find_section_by_name (name_selector_dialog, name);
1854 g_return_if_fail (index != -1);
1856 section = &g_array_index (name_selector_dialog->priv->sections, Section, index);
1859 gtk_widget_show (GTK_WIDGET (section->section_grid));
1861 gtk_widget_hide (GTK_WIDGET (section->section_grid));