Fixes part of bug #417999
authorMatthew Barnes <mbarnes@redhat.com>
Mon, 22 Oct 2007 16:33:16 +0000 (16:33 +0000)
committerMatthew Barnes <mbarnes@src.gnome.org>
Mon, 22 Oct 2007 16:33:16 +0000 (16:33 +0000)
2007-10-22  Matthew Barnes  <mbarnes@redhat.com>

* Fixes part of bug #417999

* docs/references/libedataserverui:
Add documentation for ESourceComboBox widget.

* libedataserverui/Makefile.am:
Add e-source-combo-box.[ch].
Rename test-source-option-menu to test-source-combo-box.

* libedataserverui/e-source-combo-box.c:
* libedataserverui/e-source-combo-box.h:
New widget replaces ESourceOptionMenu.  Same functionality, but
ESourceComboBox is a subclass of GtkComboBox, which itself replaces
GtkOptionMenu (deprecated).

* libedataserverui/e-source-option-menu.h:
Deprecate ESourceOptionMenu.

* libedataserverui/e-name-selector-dialog.glade:
List categories in a GtkComboBox instead of a GtkOptionMenu.

* libedataserverui/e-name-selector-dialog.h:
Replace the ESourceList member pointer with a placeholder,
to maintain ABI compatibility.

* libedataserverui/e-name-selector-dialog.c:
Use ESourceComboBox instead of ESourceOptionMenu.
Refactor some messy bits.

* libedataserverui/e-name-selector-entry.c (populate_popup):
* libedataserverui/e-name-selector-list.c (enl_tree_button_press_event):
Use gtk_radio_menu_item_get_group() instead of
gtk_radio_menu_item_group() (deprecated).

* libedataserverui/test-source-option-menu.c:
Test ESourceComboBox instead of ESourceOptionMenu.
Rename the file appropriately.

svn path=/trunk/; revision=8138

15 files changed:
ChangeLog
docs/reference/libedataserverui/libedataserverui-docs.sgml
docs/reference/libedataserverui/libedataserverui-sections.txt
docs/reference/libedataserverui/libedataserverui.types
libedataserverui/ChangeLog
libedataserverui/Makefile.am
libedataserverui/e-name-selector-dialog.c
libedataserverui/e-name-selector-dialog.glade
libedataserverui/e-name-selector-dialog.h
libedataserverui/e-name-selector-entry.c
libedataserverui/e-name-selector-list.c
libedataserverui/e-source-combo-box.c [new file with mode: 0644]
libedataserverui/e-source-combo-box.h [new file with mode: 0644]
libedataserverui/e-source-option-menu.h
libedataserverui/test-source-combo-box.c [moved from libedataserverui/test-source-option-menu.c with 80% similarity]

index 0c0d79b..0d0b068 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2007-10-22  Matthew Barnes  <mbarnes@redhat.com>
+
+       * Fixes part of bug #417999
+
+       * docs/references/libedataserverui:
+       Add documentation for ESourceComboBox widget.
+
 2007-10-09  Matthew Barnes  <mbarnes@redhat.com>
 
        * iconv-detect.c (main): Remove an unused variable (#483301).
index 6978e60..041d4af 100644 (file)
@@ -19,6 +19,7 @@
     <xi:include href="xml/e-name-selector-list.xml"/>
     <xi:include href="xml/e-name-selector-model.xml"/>
     <xi:include href="xml/e-passwords.xml"/>
+    <xi:include href="xml/e-source-combo-box.xml"/>
     <xi:include href="xml/e-source-option-menu.xml"/>
     <xi:include href="xml/e-source-selector.xml"/>
     <xi:include href="xml/e-source-selector-dialog.xml"/>
index 29dbb66..2ae0cbd 100644 (file)
@@ -25,6 +25,29 @@ e_tree_model_generator_get_type
 </SECTION>
 
 <SECTION>
+<FILE>e-source-combo-box</FILE>
+<TITLE>ESourceComboBox</TITLE>
+ESourceComboBox
+e_source_combo_box_new
+e_source_combo_box_get_source_list
+e_source_combo_box_set_source_list
+e_source_combo_box_get_active
+e_source_combo_box_set_active
+e_source_combo_box_get_active_uid
+e_source_combo_box_set_active_uid
+<SUBSECTION Standard>
+E_SOURCE_COMBO_BOX
+E_IS_SOURCE_COMBO_BOX
+E_TYPE_SOURCE_COMBO_BOX
+E_SOURCE_COMBO_BOX_CLASS
+E_IS_SOURCE_COMBO_BOX_CLASS
+E_SOURCE_COMBO_BOX_GET_CLASS
+ESourceComboBoxClass
+<SUBSECTION Private>
+e_source_combo_box_get_type
+</SECTION>
+
+<SECTION>
 <FILE>e-source-option-menu</FILE>
 <TITLE>ESourceOptionMenu</TITLE>
 ESourceOptionMenu
index fdb4cf7..93ec342 100644 (file)
@@ -6,6 +6,7 @@
 #include <libedataserverui/e-name-selector-entry.h>
 #include <libedataserverui/e-name-selector-list.h>
 #include <libedataserverui/e-name-selector-model.h>
+#include <libedataserverui/e-source-combo-box.h>
 #include <libedataserverui/e-source-option-menu.h>
 #include <libedataserverui/e-source-selector.h>
 #include <libedataserverui/e-source-selector-dialog.h>
@@ -19,6 +20,7 @@ e_name_selector_dialog_get_type
 e_name_selector_entry_get_type
 e_name_selector_list_get_type
 e_name_selector_model_get_type
+e_source_combo_box_get_type
 e_source_option_menu_get_type
 e_source_selector_get_type
 e_source_selector_dialog_get_type
index 777920f..7833ea6 100644 (file)
@@ -1,3 +1,40 @@
+2007-10-22  Matthew Barnes  <mbarnes@redhat.com>
+
+       ** Fixes part of bug #417999
+
+       * Makefile.am:
+       Add e-source-combo-box.[ch].
+       Rename test-source-option-menu to test-source-combo-box.
+
+       * e-source-combo-box.c:
+       * e-source-combo-box.h:
+       New widget replaces ESourceOptionMenu.  Same functionality, but
+       ESourceComboBox is a subclass of GtkComboBox, which itself replaces
+       GtkOptionMenu (deprecated).
+
+       * e-source-option-menu.h:
+       Deprecate ESourceOptionMenu.
+
+       * e-name-selector-dialog.glade:
+       List categories in a GtkComboBox instead of a GtkOptionMenu.
+
+       * e-name-selector-dialog.h:
+       Replace the ESourceList member pointer with a placeholder,
+       to maintain ABI compatibility.
+
+       * e-name-selector-dialog.c:
+       Use ESourceComboBox instead of ESourceOptionMenu.
+       Refactor some messy bits.
+
+       * e-name-selector-entry.c (populate_popup):
+       * e-name-selector-list.c (enl_tree_button_press_event):
+       Use gtk_radio_menu_item_get_group() instead of
+       gtk_radio_menu_item_group() (deprecated).
+
+       * test-source-option-menu.c:
+       Test ESourceComboBox instead of ESourceOptionMenu.
+       Rename the file appropriately.
+
 2007-10-05  Srinivasa Ragavan  <sragavan@novell.com>
 
        ** Fix for bug #478404
index b3208ec..bb59830 100644 (file)
@@ -12,8 +12,8 @@ MARSHAL_GENERATED = e-data-server-ui-marshal.c e-data-server-ui-marshal.h
 
 lib_LTLIBRARIES = libedataserverui-1.2.la
 noinst_PROGRAMS =                      \
+       test-source-combo-box           \
        test-source-selector            \
-       test-source-option-menu         \
        test-contact-store              \
        test-name-selector
 
@@ -31,6 +31,7 @@ libedataserverui_1_2_la_SOURCES =     \
        e-passwords.c                   \
        e-source-selector.c             \
        e-source-selector-dialog.c      \
+       e-source-combo-box.c            \
        e-source-option-menu.c          \
        e-tree-model-generator.c
 
@@ -57,6 +58,7 @@ libedataserveruiinclude_HEADERS =     \
        e-passwords.h                   \
        e-source-selector.h             \
        e-source-selector-dialog.h      \
+       e-source-combo-box.h            \
        e-source-option-menu.h          \
        e-tree-model-generator.h
 
@@ -67,8 +69,8 @@ test_source_selector_LDADD =                                  \
        $(top_builddir)/libedataserver/libedataserver-1.2.la    \
        $(E_DATA_SERVER_UI_LIBS)
 
-test_source_option_menu_SOURCES = test-source-option-menu.c
-test_source_option_menu_LDADD =                                \
+test_source_combo_box_SOURCES = test-source-combo-box.c
+test_source_combo_box_LDADD =                                  \
        libedataserverui-1.2.la                                 \
        $(top_builddir)/libedataserver/libedataserver-1.2.la    \
        $(E_DATA_SERVER_UI_LIBS)
index f2b244d..4651586 100644 (file)
@@ -32,7 +32,7 @@
 #include <gtk/gtkscrolledwindow.h>
 #include <gtk/gtkstock.h>
 #include <glib/gi18n-lib.h>
-#include <libedataserverui/e-source-option-menu.h>
+#include <libedataserverui/e-source-combo-box.h>
 #include <libedataserverui/e-destination-store.h>
 #include <libedataserverui/e-contact-store.h>
 #include <libedataserverui/e-book-auth-util.h>
@@ -64,9 +64,8 @@ struct _ENameSelectorDialogPrivate
        guint destination_index;
 };
 
-static ESource *find_first_source             (ESourceList *source_list);
 static void     search_changed                (ENameSelectorDialog *name_selector_dialog);
-static void     source_selected               (ENameSelectorDialog *name_selector_dialog, ESource *source);
+static void     source_changed                (ENameSelectorDialog *name_selector_dialog, ESourceComboBox *source_combo_box);
 static void     transfer_button_clicked       (ENameSelectorDialog *name_selector_dialog, GtkButton *transfer_button);
 static void     contact_selection_changed     (ENameSelectorDialog *name_selector_dialog);
 static void     setup_name_selector_model     (ENameSelectorDialog *name_selector_dialog);
@@ -106,33 +105,28 @@ e_name_selector_dialog_set_property (GObject *object, guint prop_id,
 {
 }
 
-/* FIXME: category_list should become part of ENameSelectorDialog structure */
-GList *category_list;
-
 static void
 e_name_selector_dialog_populate_categories (ENameSelectorDialog *name_selector_dialog)
 {
-       GtkWidget *category_option_menu;
-       GtkWidget *category_menu;
-       GList *l;
-       category_option_menu = glade_xml_get_widget (name_selector_dialog->gui, "optionmenu-category");
-
-       /* Categories are already sorted */
-       category_list = e_categories_get_list () ;
-       category_list = g_list_prepend (category_list, _("Any Category"));
-
-       category_menu = gtk_menu_new ();
-       l = category_list;
-       while (l) {     
-               GtkWidget *item;
-               item = gtk_menu_item_new_with_label (l->data);
-               gtk_menu_shell_append (GTK_MENU_SHELL (category_menu), item);
-               l = l->next;
-       }
-       gtk_widget_show_all (category_menu);
-       gtk_option_menu_set_menu (GTK_OPTION_MENU (category_option_menu), category_menu);
-       
-       g_signal_connect_swapped (category_option_menu, "changed", G_CALLBACK (search_changed), name_selector_dialog);
+       GtkWidget *combo_box;
+       GList *category_list, *iter;
+
+       /* "Any Category" is preloaded. */
+       combo_box = glade_xml_get_widget (
+               name_selector_dialog->gui, "combobox-category");
+       if (gtk_combo_box_get_active (GTK_COMBO_BOX (combo_box)) == -1)
+               gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), 0);
+
+       /* Categories are already sorted. */
+       category_list = e_categories_get_list ();
+       for (iter = category_list; iter != NULL; iter = iter->next)
+               gtk_combo_box_append_text (
+                       GTK_COMBO_BOX (combo_box), iter->data);
+       g_list_free (category_list);
+
+       g_signal_connect_swapped (
+               combo_box, "changed",
+               G_CALLBACK (search_changed), name_selector_dialog);
 }
 
 static void
@@ -223,34 +217,26 @@ e_name_selector_dialog_init (ENameSelectorDialog *name_selector_dialog)
 
        name_selector_dialog->name_selector_model = e_name_selector_model_new ();
        name_selector_dialog->sections            = g_array_new (FALSE, FALSE, sizeof (Section));
-       name_selector_dialog->source_list         = source_list;
 
        setup_name_selector_model (name_selector_dialog);
 
        /* Create source menu */
 
-       widget = e_source_option_menu_new (name_selector_dialog->source_list);
-        
+       widget = e_source_combo_box_new (source_list);
+       g_signal_connect_swapped (
+               widget, "changed",
+               G_CALLBACK (source_changed), name_selector_dialog);
+       g_object_unref (source_list);
        gconf_client = gconf_client_get_default();
        uid = gconf_client_get_string (gconf_client, "/apps/evolution/addressbook/display/primary_addressbook",
                        NULL);
        g_object_unref (gconf_client);
        if (uid) {
-               ESource *source = e_source_list_peek_source_by_uid(name_selector_dialog->source_list, uid);
-               if (source) {
-                       e_source_option_menu_select ((ESourceOptionMenu *)widget, source);
-                       source_selected (name_selector_dialog, source);
-               }
-               else {
-                       source_selected (name_selector_dialog, find_first_source (name_selector_dialog->source_list));
-               }
+               e_source_combo_box_set_active_uid (
+                       E_SOURCE_COMBO_BOX (widget), uid);
                g_free (uid);
        }
-       else {
-               source_selected (name_selector_dialog, find_first_source (name_selector_dialog->source_list));
-       }
-
-       g_signal_connect_swapped (widget, "source_selected", G_CALLBACK (source_selected), name_selector_dialog);
 
        label = glade_xml_get_widget (name_selector_dialog->gui, "AddressBookLabel");
        gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
@@ -308,9 +294,7 @@ e_name_selector_dialog_finalize (GObject *object)
        ENameSelectorDialog *name_selector_dialog = E_NAME_SELECTOR_DIALOG (object);
 
        g_array_free (name_selector_dialog->sections, TRUE);
-       g_object_unref (name_selector_dialog->source_list);
        g_object_unref (name_selector_dialog->button_size_group);
-       g_list_free (category_list);
 
        if (G_OBJECT_CLASS (e_name_selector_dialog_parent_class)->finalize)
                G_OBJECT_CLASS (e_name_selector_dialog_parent_class)->finalize (object);
@@ -384,26 +368,6 @@ sort_iter_to_contact_store_iter (ENameSelectorDialog *name_selector_dialog, GtkT
                *email_n = email_n_local;
 }
 
-static ESource *
-find_first_source (ESourceList *source_list)
-{
-       GSList *groups, *sources, *l, *m;
-                       
-       groups = e_source_list_peek_groups (source_list);
-       for (l = groups; l; l = l->next) {
-               ESourceGroup *group = l->data;
-                               
-               sources = e_source_group_peek_sources (group);
-               for (m = sources; m; m = m->next) {
-                       ESource *source = m->data;
-
-                       return source;
-               }                               
-       }
-
-       return NULL;
-}
-
 static void
 add_destination (EDestinationStore *destination_store, EContact *contact, gint email_n)
 {
@@ -742,8 +706,13 @@ book_opened (EBook *book, EBookStatus status, gpointer data)
 }
 
 static void
-source_selected (ENameSelectorDialog *name_selector_dialog, ESource *source)
+source_changed (ENameSelectorDialog *name_selector_dialog,
+                ESourceComboBox *source_combo_box)
 {
+       ESource *source;
+
+       source = e_source_combo_box_get_active (source_combo_box);
+
        /* Remove any previous books being shown or loaded */
        remove_books (name_selector_dialog);
 
@@ -761,49 +730,54 @@ search_changed (ENameSelectorDialog *name_selector_dialog)
 {
        EContactStore *contact_store;
        EBookQuery    *book_query;
-       GtkWidget     *category_option_menu;
+       GtkWidget     *combo_box;
        const gchar   *text;
-       gint          category_id;      
        gchar         *text_escaped;
        gchar         *query_string;
-       const gchar   *category;
+       gchar         *category;
        gchar         *category_escaped;
 
-       category_option_menu = glade_xml_get_widget(name_selector_dialog->gui, "optionmenu-category");
-       category_id = gtk_option_menu_get_history (GTK_OPTION_MENU(category_option_menu));
-       category = g_list_nth_data (category_list, category_id);
-       if (!category)
-               return;
+       combo_box = glade_xml_get_widget (
+               name_selector_dialog->gui, "combobox-category");
+       if (gtk_combo_box_get_active (GTK_COMBO_BOX (combo_box)) == -1)
+               gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), 0);
+
+       category = gtk_combo_box_get_active_text (GTK_COMBO_BOX (combo_box));
        category_escaped = escape_sexp_string (category);
 
        text = gtk_entry_get_text (name_selector_dialog->search_entry);
        text_escaped = escape_sexp_string (text);
 
-       if ( !strcmp (category, _("Any Category"))) {
-               query_string = g_strdup_printf ("(or (beginswith \"file_as\" %s) "
-                                               "    (beginswith \"full_name\" %s) "
-                                               "    (beginswith \"email\" %s) "
-                                               "    (beginswith \"nickname\" %s)))",
-                                               text_escaped, text_escaped, text_escaped, text_escaped);
-       }
-       else {
-               query_string = g_strdup_printf ("(and (is \"category_list\" %s) "
-                                               "(or (beginswith \"file_as\" %s) "
-                                               "    (beginswith \"full_name\" %s) "
-                                               "    (beginswith \"email\" %s) "
-                                               "    (beginswith \"nickname\" %s)))",
-                                               category_escaped,text_escaped, text_escaped, text_escaped, text_escaped);
-       }
+       if (!strcmp (category, _("Any Category")))
+               query_string = g_strdup_printf (
+                       "(or (beginswith \"file_as\" %s) "
+                       "    (beginswith \"full_name\" %s) "
+                       "    (beginswith \"email\" %s) "
+                       "    (beginswith \"nickname\" %s)))",
+                       text_escaped, text_escaped,
+                       text_escaped, text_escaped);
+       else
+               query_string = g_strdup_printf (
+                       "(and (is \"category_list\" %s) "
+                       "(or (beginswith \"file_as\" %s) "
+                       "    (beginswith \"full_name\" %s) "
+                       "    (beginswith \"email\" %s) "
+                       "    (beginswith \"nickname\" %s)))",
+                       category_escaped, text_escaped, text_escaped,
+                       text_escaped, text_escaped);
 
        book_query = e_book_query_from_string (query_string);
-       g_free (query_string);
-       g_free (text_escaped);
-       g_free (category_escaped);
 
-       contact_store = e_name_selector_model_peek_contact_store (name_selector_dialog->name_selector_model);
+       contact_store = e_name_selector_model_peek_contact_store (
+               name_selector_dialog->name_selector_model);
        e_contact_store_set_query (contact_store, book_query);
 
        e_book_query_unref (book_query);
+
+       g_free (query_string);
+       g_free (text_escaped);
+       g_free (category_escaped);
+       g_free (category);
 }
 
 static void
index 0b21deb..0599519 100644 (file)
                  <property name="yalign">0.5</property>
                  <property name="xpad">0</property>
                  <property name="ypad">0</property>
-                 <property name="mnemonic_widget">optionmenu-category</property> 
+                 <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+                 <property name="width_chars">-1</property>
+                 <property name="single_line_mode">False</property>
+                 <property name="angle">0</property>
                </widget>
                <packing>
                  <property name="left_attach">0</property>
                  <property name="bottom_attach">2</property>
                  <property name="x_options">fill</property>
                  <property name="y_options"></property>
-               </packing>
-             </child>
-       
-             <child>
-               <widget class="GtkOptionMenu" id="optionmenu-category">
-                 <property name="visible">True</property>
-                 <property name="can_focus">True</property>
-                 <property name="history">0</property>
-               </widget>
-               <packing>
-                 <property name="left_attach">1</property>
-                 <property name="right_attach">2</property>
-                 <property name="top_attach">1</property>
-                 <property name="bottom_attach">2</property>
-                 <property name="x_options">fill</property>
-                 <property name="y_options">fill</property>
-               </packing>
+               </packing>
              </child>
 
              <child>
                  <property name="y_options">fill</property>
                </packing>
              </child>
+
+             <child>
+               <widget class="GtkComboBox" id="combobox-category">
+                 <property name="visible">True</property>
+                 <property name="items" translatable="yes">Any Category</property>
+                 <property name="add_tearoffs">False</property>
+                 <property name="focus_on_click">True</property>
+               </widget>
+               <packing>
+                 <property name="left_attach">1</property>
+                 <property name="right_attach">2</property>
+                 <property name="top_attach">1</property>
+                 <property name="bottom_attach">2</property>
+                 <property name="x_options">fill</property>
+                 <property name="y_options">fill</property>
+               </packing>
+             </child>
            </widget>
            <packing>
              <property name="padding">0</property>
index 2624831..5ce5917 100644 (file)
@@ -58,7 +58,7 @@ struct _ENameSelectorDialog {
        /* Private */
 
        EBook              *pending_book;
-       ESourceList        *source_list;
+       gpointer            unused;     /* Maintain ABI compatibility */
        ENameSelectorModel *name_selector_model;
        GtkTreeModelSort   *contact_sort;
 
index 3993b3e..853502d 100644 (file)
@@ -2210,7 +2210,7 @@ populate_popup (ENameSelectorEntry *name_selector_entry, GtkMenu *menu)
                
                        if (len > 1) {
                                menu_item = gtk_radio_menu_item_new_with_label (group, email);
-                               group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menu_item));
+                               group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (menu_item));
                                g_signal_connect (menu_item, "toggled", G_CALLBACK (destination_set_email), destination);
                        } else {
                                menu_item = gtk_menu_item_new_with_label (email);                       
index 2bb9d92..8c8834f 100644 (file)
@@ -447,7 +447,7 @@ enl_tree_button_press_event (GtkWidget *widget,
                
                        if (len > 1) {
                                menu_item = gtk_radio_menu_item_new_with_label (group, email);
-                               group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menu_item));
+                               group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (menu_item));
                                g_signal_connect (menu_item, "toggled", G_CALLBACK (destination_set_email), destination);
                        } else {
                                menu_item = gtk_menu_item_new_with_label (email);                       
diff --git a/libedataserverui/e-source-combo-box.c b/libedataserverui/e-source-combo-box.c
new file mode 100644 (file)
index 0000000..2c6d61d
--- /dev/null
@@ -0,0 +1,456 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-source-option-menu.c
+ *
+ * Copyright (C) 2007 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-source-combo-box.h"
+
+#define E_SOURCE_COMBO_BOX_GET_PRIVATE(obj) \
+       (G_TYPE_INSTANCE_GET_PRIVATE \
+       ((obj), E_TYPE_SOURCE_COMBO_BOX, ESourceComboBoxPrivate))
+
+struct _ESourceComboBoxPrivate {
+       ESourceList *source_list;
+       GHashTable *uid_index;
+       gulong handler_id;
+};
+
+enum {
+       PROP_0,
+       PROP_SOURCE_LIST
+};
+
+enum {
+       COLUMN_NAME,            /* G_TYPE_STRING */
+       COLUMN_SENSITIVE,       /* G_TYPE_BOOLEAN */
+       COLUMN_SOURCE,          /* G_TYPE_OBJECT */
+       NUM_COLUMNS
+};
+
+static gpointer parent_class = NULL;
+
+static void
+source_list_changed_cb (ESourceList *source_list,
+                        ESourceComboBox *source_combo_box)
+{
+       ESourceComboBoxPrivate *priv;
+       GtkComboBox *combo_box;
+       GtkTreeModel *model;
+       GtkListStore *store;
+       GtkTreeIter iter;
+       GtkTreePath *path;
+       GSList *groups;
+       GSList *sources;
+       const gchar *name;
+       const gchar *uid;
+       gchar *indented_name;
+
+       priv = source_combo_box->priv;
+       g_hash_table_remove_all (priv->uid_index);
+
+       combo_box = GTK_COMBO_BOX (source_combo_box);
+       gtk_combo_box_set_active (combo_box, -1);
+
+       model = gtk_combo_box_get_model (combo_box);
+       store = GTK_LIST_STORE (model);
+       gtk_list_store_clear (store);
+
+       for (groups = e_source_list_peek_groups (source_list);
+               groups != NULL; groups = groups->next) {
+
+               /* Only show source groups that have sources. */
+               if (e_source_group_peek_sources (groups->data) == NULL)
+                       continue;
+
+               name = e_source_group_peek_name (groups->data);
+               gtk_list_store_append (store, &iter);
+               gtk_list_store_set (
+                       store, &iter,
+                       COLUMN_NAME, name,
+                       COLUMN_SENSITIVE, FALSE,
+                       COLUMN_SOURCE, groups->data,
+                       -1);
+
+               for (sources = e_source_group_peek_sources (groups->data);
+                       sources != NULL; sources = sources->next) {
+
+                       name = e_source_peek_name (sources->data);
+                       indented_name = g_strconcat ("    ", name, NULL);
+                       gtk_list_store_append (store, &iter);
+                       gtk_list_store_set (
+                               store, &iter,
+                               COLUMN_NAME, indented_name,
+                               COLUMN_SENSITIVE, TRUE,
+                               COLUMN_SOURCE, sources->data,
+                               -1);
+                       g_free (indented_name);
+
+                       uid = e_source_peek_uid (sources->data);
+                       path = gtk_tree_model_get_path (model, &iter);
+                       g_hash_table_insert (
+                               priv->uid_index, g_strdup (uid),
+                               gtk_tree_row_reference_new (model, path));
+                       gtk_tree_path_free (path);
+               }
+       }
+}
+
+static GObject *
+e_source_combo_box_constructor (GType type, guint n_construct_properties,
+                                GObjectConstructParam *construct_properties)
+{
+       GtkCellRenderer *renderer;
+       GtkListStore *store;
+       GObject *object;
+
+       /* Chain up to parent's "constructor" method. */
+       object = G_OBJECT_CLASS (parent_class)->constructor (
+               type, n_construct_properties, construct_properties);
+
+       store = gtk_list_store_new (
+               NUM_COLUMNS, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_OBJECT);
+       gtk_combo_box_set_model (
+               GTK_COMBO_BOX (object), GTK_TREE_MODEL (store));
+
+       renderer = gtk_cell_renderer_text_new ();
+       gtk_cell_layout_pack_start (
+               GTK_CELL_LAYOUT (object), renderer, TRUE);
+       gtk_cell_layout_set_attributes (
+               GTK_CELL_LAYOUT (object), renderer,
+               "text", COLUMN_NAME,
+               "sensitive", COLUMN_SENSITIVE,
+               NULL);
+
+       return object;
+}
+
+static void
+e_source_combo_box_set_property (GObject *object, guint property_id,
+                                 const GValue *value, GParamSpec *pspec)
+{
+       ESourceComboBoxPrivate *priv;
+
+       priv = E_SOURCE_COMBO_BOX_GET_PRIVATE (object);
+
+       switch (property_id) {
+               case PROP_SOURCE_LIST:
+
+                       if (priv->source_list != NULL) {
+                               g_signal_handler_disconnect (
+                                       priv->source_list, priv->handler_id);
+                               g_object_unref (priv->source_list);
+                       }
+
+                       priv->source_list = g_value_dup_object (value);
+
+                       /* Reset the tree store. */
+                       source_list_changed_cb (
+                               priv->source_list,
+                               E_SOURCE_COMBO_BOX (object));
+
+                       /* Watch for source list changes. */
+                       priv->handler_id = g_signal_connect_object (
+                               priv->source_list, "changed",
+                               G_CALLBACK (source_list_changed_cb),
+                               object, 0);
+
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_source_combo_box_get_property (GObject *object, guint property_id,
+                                 GValue *value, GParamSpec *pspec)
+{
+       ESourceComboBoxPrivate *priv;
+
+       priv = E_SOURCE_COMBO_BOX_GET_PRIVATE (object);
+
+       switch (property_id) {
+               case PROP_SOURCE_LIST:
+                       g_value_set_object (value, priv->source_list);
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_source_combo_box_dispose (GObject *object)
+{
+       ESourceComboBoxPrivate *priv;
+
+       priv = E_SOURCE_COMBO_BOX_GET_PRIVATE (object);
+
+       if (priv->source_list != NULL) {
+               g_object_unref (priv->source_list);
+               priv->source_list = NULL;
+       }
+
+       g_hash_table_remove_all (priv->uid_index);
+
+       /* Chain up to parent's "dispose" method. */
+       G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+e_source_combo_box_finalize (GObject *object)
+{
+       ESourceComboBoxPrivate *priv;
+
+       priv = E_SOURCE_COMBO_BOX_GET_PRIVATE (object);
+
+       g_hash_table_destroy (priv->uid_index);
+
+       /* Chain up to parent's "finalize" method. */
+       G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+e_source_combo_box_class_init (ESourceComboBoxClass *class)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+       parent_class = g_type_class_peek_parent (class);
+
+       g_type_class_add_private (class, sizeof (ESourceComboBox));
+
+       object_class->constructor = e_source_combo_box_constructor;
+       object_class->set_property = e_source_combo_box_set_property;
+       object_class->get_property = e_source_combo_box_get_property;
+       object_class->dispose = e_source_combo_box_dispose;
+       object_class->finalize = e_source_combo_box_finalize;
+
+       g_object_class_install_property (
+               object_class,
+               PROP_SOURCE_LIST,
+               g_param_spec_object (
+                       "source-list",
+                       "source-list",
+                       "List of sources to choose from",
+                       E_TYPE_SOURCE_LIST,
+                       G_PARAM_READWRITE));
+}
+
+static void
+e_source_combo_box_init (ESourceComboBox *source_combo_box)
+{
+       source_combo_box->priv =
+               E_SOURCE_COMBO_BOX_GET_PRIVATE (source_combo_box);
+
+       source_combo_box->priv->uid_index =
+               g_hash_table_new_full (
+                       g_str_hash, g_str_equal,
+                       (GDestroyNotify) g_free,
+                       (GDestroyNotify) gtk_tree_row_reference_free);
+}
+
+GType
+e_source_combo_box_get_type (void)
+{
+       static GType type = 0;
+
+       if (G_UNLIKELY (type == 0)) {
+               static const GTypeInfo type_info = {
+                       sizeof (ESourceComboBoxClass),
+                       (GBaseInitFunc) NULL,
+                       (GBaseFinalizeFunc) NULL,
+                       (GClassInitFunc) e_source_combo_box_class_init,
+                       (GClassFinalizeFunc) NULL,
+                       NULL,  /* class_data */
+                       sizeof (ESourceComboBox),
+                       0,     /* n_preallocs */
+                       (GInstanceInitFunc) e_source_combo_box_init,
+                       NULL   /* value_table */
+               };
+
+               type = g_type_register_static (
+                       GTK_TYPE_COMBO_BOX, "ESourceComboBox", &type_info, 0);
+       }
+
+       return type;
+}
+
+/**
+ * e_source_combo_box_new:
+ * @source_list: an #ESourceList
+ *
+ * Creates a new #ESourceComboBox widget that lets the user pick an #ESource
+ * from the provided #ESourceList.
+ *
+ * Returns: a new #ESourceComboBox
+ **/
+GtkWidget *
+e_source_combo_box_new (ESourceList *source_list)
+{
+       g_return_val_if_fail (E_IS_SOURCE_LIST (source_list), NULL);
+
+       return g_object_new (
+               E_TYPE_SOURCE_COMBO_BOX,
+               "source-list", source_list, NULL);
+}
+
+/**
+ * e_source_combo_box_get_source_list:
+ * @source_combo_box: an #ESourceComboBox
+ *
+ * Returns the #ESourceList which is acting as a data source for
+ * @source_combo_box.
+ *
+ * Returns: an #ESourceList
+ **/
+ESourceList *
+e_source_combo_box_get_source_list (ESourceComboBox *source_combo_box)
+{
+       ESourceList *source_list;
+
+       g_return_val_if_fail (E_IS_SOURCE_COMBO_BOX (source_combo_box), NULL);
+
+       g_object_get (source_combo_box, "source-list", &source_list, NULL);
+
+       return source_list;
+}
+
+/**
+ * e_source_combo_box_set_source_list:
+ * @source_combo_box: an #ESourceComboBox
+ * @source_list: an #ESourceList
+ *
+ * Sets the source list used by @source_combo_box to be @source_list.  This
+ * causes the contents of @source_combo_box to be regenerated.
+ **/
+void
+e_source_combo_box_set_source_list (ESourceComboBox *source_combo_box,
+                                    ESourceList *source_list)
+{
+       g_return_if_fail (E_IS_SOURCE_COMBO_BOX (source_combo_box));
+       g_return_if_fail (E_IS_SOURCE_LIST (source_list));
+
+       g_object_set (source_combo_box, "source-list", source_list, NULL);
+}
+
+/**
+ * e_source_combo_box_get_active:
+ * @source_combo_box: an #ESourceComboBox
+ *
+ * Returns the #ESource corresponding to the currently active item, or %NULL
+ * if there is no active item.
+ *
+ * Returns: an #ESource or %NULL
+ **/
+ESource *
+e_source_combo_box_get_active (ESourceComboBox *source_combo_box)
+{
+       GtkComboBox *combo_box;
+       GtkTreeIter iter;
+       ESource *source;
+
+       g_return_val_if_fail (E_IS_SOURCE_COMBO_BOX (source_combo_box), NULL);
+
+       combo_box = GTK_COMBO_BOX (source_combo_box);
+
+       if (!gtk_combo_box_get_active_iter (combo_box, &iter))
+               return NULL;
+
+       gtk_tree_model_get (
+               gtk_combo_box_get_model (combo_box),
+               &iter, COLUMN_SOURCE, &source, -1);
+
+       return source;
+}
+
+/**
+ * e_source_combo_box_set_active:
+ * @source_combo_box: an #ESourceComboBox
+ * @source: an #ESource
+ *
+ * Sets the active item to the one corresponding to @source.
+ **/
+void
+e_source_combo_box_set_active (ESourceComboBox *source_combo_box,
+                               ESource *source)
+{
+       g_return_if_fail (E_IS_SOURCE_COMBO_BOX (source_combo_box));
+       g_return_if_fail (E_IS_SOURCE (source));
+
+       e_source_combo_box_set_active_uid (
+               source_combo_box, e_source_peek_uid (source));
+}
+
+/**
+ * e_source_combo_box_get_active_uid:
+ * @source_combo_box: an #ESourceComboBox
+ *
+ * Returns the unique ID of the #ESource corresponding to the currently
+ * active item, or %NULL if there is no active item.
+ *
+ * Returns: a unique ID string or %NULL
+ **/
+const gchar *
+e_source_combo_box_get_active_uid (ESourceComboBox *source_combo_box)
+{
+       ESource *source;
+
+       g_return_val_if_fail (E_IS_SOURCE_COMBO_BOX (source_combo_box), NULL);
+
+       source = e_source_combo_box_get_active (source_combo_box);
+       if (source == NULL)
+               return NULL;
+
+       return e_source_peek_uid (source);
+}
+
+/**
+ * e_source_combo_box_set_active_uid:
+ * @source_combo_box: an #ESourceComboBox
+ * @uid: a unique ID of an #ESource
+ *
+ * Sets the active item to the one corresponding to @uid.
+ **/
+void
+e_source_combo_box_set_active_uid (ESourceComboBox *source_combo_box,
+                                   const gchar *uid)
+{
+       ESourceComboBoxPrivate *priv;
+       GtkTreeRowReference *reference;
+       GtkComboBox *combo_box;
+       GtkTreeIter iter;
+       gboolean iter_was_set;
+
+       g_return_if_fail (E_IS_SOURCE_COMBO_BOX (source_combo_box));
+       g_return_if_fail (uid != NULL);
+
+       priv = source_combo_box->priv;
+       combo_box = GTK_COMBO_BOX (source_combo_box);
+
+       reference = g_hash_table_lookup (priv->uid_index, uid);
+       g_return_if_fail (gtk_tree_row_reference_valid (reference));
+
+       iter_was_set = gtk_tree_model_get_iter (
+               gtk_combo_box_get_model (combo_box), &iter,
+               gtk_tree_row_reference_get_path (reference));
+       g_return_if_fail (iter_was_set);
+
+       gtk_combo_box_set_active_iter (combo_box, &iter);
+}
diff --git a/libedataserverui/e-source-combo-box.h b/libedataserverui/e-source-combo-box.h
new file mode 100644 (file)
index 0000000..f76dba5
--- /dev/null
@@ -0,0 +1,79 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-source-combo-box.h
+ *
+ * Copyright (C) 2007 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _E_SOURCE_COMBO_BOX_H_
+#define _E_SOURCE_COMBO_BOX_H_
+
+#include <gtk/gtk.h>
+#include <libedataserver/e-source-list.h>
+
+#define E_TYPE_SOURCE_COMBO_BOX \
+       (e_source_combo_box_get_type ())
+#define E_SOURCE_COMBO_BOX(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_SOURCE_COMBO_BOX, ESourceComboBox))
+#define E_SOURCE_COMBO_BOX_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_SOURCE_COMBO_BOX, ESourceComboBoxClass))
+#define E_IS_SOURCE_COMBO_BOX(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_SOURCE_COMBO_BOX))
+#define E_IS_SOURCE_COMBO_BOX_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE ((cls), E_TYPE_SOURCE_COMBO_BOX))
+#define E_SOURCE_COMBO_BOX_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_SOURCE_COMBO_BOX, ESourceComboBox))
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceComboBox ESourceComboBox;
+typedef struct _ESourceComboBoxClass ESourceComboBoxClass;
+typedef struct _ESourceComboBoxPrivate ESourceComboBoxPrivate;
+
+struct _ESourceComboBox {
+       GtkComboBox parent;
+
+       ESourceComboBoxPrivate *priv;
+};
+
+struct _ESourceComboBoxClass {
+       GtkComboBoxClass parent_class;
+};
+
+GType          e_source_combo_box_get_type     (void);
+GtkWidget *    e_source_combo_box_new          (ESourceList *source_list);
+ESourceList *  e_source_combo_box_get_source_list
+                                               (ESourceComboBox *source_combo_box);
+void           e_source_combo_box_set_source_list
+                                               (ESourceComboBox *source_combo_box,
+                                                ESourceList *source_list);
+ESource *      e_source_combo_box_get_active
+                                               (ESourceComboBox *source_combo_box);
+void           e_source_combo_box_set_active
+                                               (ESourceComboBox *source_combo_box,
+                                                ESource *source);
+const gchar *  e_source_combo_box_get_active_uid
+                                               (ESourceComboBox *source_combo_box);
+void           e_source_combo_box_set_active_uid
+                                               (ESourceComboBox *source_combo_box,
+                                                const gchar *uid);
+
+G_END_DECLS
+
+#endif /* _E_SOURCE_COMBO_BOX_H_ */
index 499c2e4..0fb05c4 100644 (file)
@@ -23,6 +23,8 @@
 #ifndef _E_SOURCE_OPTION_MENU_H_
 #define _E_SOURCE_OPTION_MENU_H_
 
+#ifndef EDS_DISABLE_DEPRECATED
+
 #include "libedataserver/e-source-list.h"
 
 #include <gtk/gtkoptionmenu.h>
@@ -60,5 +62,6 @@ ESource *e_source_option_menu_peek_selected  (ESourceOptionMenu *menu);
 void     e_source_option_menu_select         (ESourceOptionMenu *menu,
                                              ESource           *source);
 
+#endif /* EDS_DISABLE_DEPRECATED */
 
 #endif /* _E_SOURCE_OPTION_MENU_H_ */
similarity index 80%
rename from libedataserverui/test-source-option-menu.c
rename to libedataserverui/test-source-combo-box.c
index 4bc3d4d..a982137 100644 (file)
@@ -1,5 +1,5 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-/* test-source-option-menu.c - Test for ESourceOptionMenu.
+/* test-source-combo-box.c - Test for ESourceComboBox.
  *
  * Copyright (C) 2003 Novell, Inc.
  *
 #include <config.h>
 #endif
 
-
-#include "e-source-option-menu.h"
+#include "e-source-combo-box.h"
 
 #include <gtk/gtkwindow.h>
 #include <gtk/gtkmain.h>
 
 static void
-source_selected_callback (ESourceOptionMenu *menu,
-                         ESource *source,
-                         void *unused_data)
+source_changed_cb (ESourceComboBox *combo_box)
 {
+       ESource *source;
+
+       source = e_source_combo_box_get_active (combo_box);
        g_print ("source selected: \"%s\"\n", e_source_peek_name (source));
 }
 
@@ -43,7 +43,7 @@ static int
 on_idle_create_widget (const char *gconf_path)
 {
        GtkWidget *window;
-       GtkWidget *option_menu;
+       GtkWidget *combo_box;
        ESourceList *source_list;
        GConfClient *gconf_client;
 
@@ -51,10 +51,12 @@ on_idle_create_widget (const char *gconf_path)
        source_list = e_source_list_new_for_gconf (gconf_client, gconf_path);
 
        window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-       option_menu = e_source_option_menu_new (source_list);
-       g_signal_connect (option_menu, "source_selected", G_CALLBACK (source_selected_callback), NULL);
+       combo_box = e_source_combo_box_new (source_list);
+       g_signal_connect (
+               combo_box, "changed",
+               G_CALLBACK (source_changed_cb), NULL);
 
-       gtk_container_add (GTK_CONTAINER (window), option_menu);
+       gtk_container_add (GTK_CONTAINER (window), combo_box);
        gtk_widget_show_all (window);
 
        g_object_unref (gconf_client);