From 85d3d3acd8aa8af7bda96f769557aa89b4e0ce8d Mon Sep 17 00:00:00 2001 From: Christopher James Lahey Date: Fri, 3 May 2002 18:46:18 +0000 Subject: Added e-folder-list.h. (libeshell_la_SOURCES): Added e-folder-list.c. 2002-05-03 Christopher James Lahey * Makefile.am (eshellinclude_HEADERS): Added e-folder-list.h. (libeshell_la_SOURCES): Added e-folder-list.c. * e-folder-list.c, e-folder-list.h: New widget for editing a list of folder uris. svn path=/trunk/; revision=16677 --- shell/ChangeLog | 13 +- shell/Makefile.am | 2 + shell/e-folder-list.c | 603 ++++++++++++++++++++++++++++++++++++++++++++++++++ shell/e-folder-list.h | 112 ++++++++++ 4 files changed, 728 insertions(+), 2 deletions(-) create mode 100644 shell/e-folder-list.c create mode 100644 shell/e-folder-list.h diff --git a/shell/ChangeLog b/shell/ChangeLog index 6411eeed2e..c47a18101d 100644 --- a/shell/ChangeLog +++ b/shell/ChangeLog @@ -1,3 +1,11 @@ +2002-05-03 Christopher James Lahey + + * Makefile.am (eshellinclude_HEADERS): Added e-folder-list.h. + (libeshell_la_SOURCES): Added e-folder-list.c. + + * e-folder-list.c, e-folder-list.h: New widget for editing a list + of folder uris. + 2002-04-29 Christopher James Lahey * e-storage-set-view.c (e_storage_set_view_set_checkboxes_list, @@ -6,8 +14,9 @@ 2002-04-19 Anna Marie Dirks - * glade/e-shell-config-default-folders.glade: Minor label tweaks; - changed "Default folders" to "Default Folders", and added accelerators. + * glade/e-shell-config-default-folders.glade: Minor label tweaks; + changed "Default folders" to "Default Folders", and added + accelerators. 2002-04-18 JP Rosevear diff --git a/shell/Makefile.am b/shell/Makefile.am index b30e3787f6..ea885f7233 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -58,6 +58,7 @@ eshellincludedir = $(includedir)/evolution/shell eshellinclude_HEADERS = \ Evolution.h \ + e-folder-list.h \ e-folder-tree.h \ evolution-activity-client.h \ evolution-folder-selector-button.h \ @@ -75,6 +76,7 @@ eshellinclude_HEADERS = \ libeshell_la_SOURCES = \ $(IDL_GENERATED) \ + e-folder-list.c \ e-folder-tree.c \ e-shell-corba-icon-utils.c \ e-shell-corba-icon-utils.h \ diff --git a/shell/e-folder-list.c b/shell/e-folder-list.c new file mode 100644 index 0000000000..582a513ca7 --- /dev/null +++ b/shell/e-folder-list.c @@ -0,0 +1,603 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * e-folder-list.c + * Copyright 2000, 2001, Ximian, Inc. + * + * Authors: + * Chris Lahey + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License, version 2, as published by the Free Software Foundation. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include +#include +#include "e-folder-list.h" +#include +#include +#include +#include +#include +#include +#include +#include + +static GtkVBoxClass *parent_class = NULL; +#define PARENT_TYPE (gtk_vbox_get_type ()) + +enum { + CHANGED, + OPTION_MENU_CHANGED, + LAST_SIGNAL +}; + +static guint signals [LAST_SIGNAL] = { 0, }; + +/* The arguments we take */ +enum { + ARG_0, + ARG_TITLE, + ARG_POSSIBLE_TYPES, +}; + +struct _EFolderListPrivate { + GladeXML *gui; + + ETableScrolled *scrolled_table; + char *title; + GtkFrame *frame; + ETableMemoryStore *model; + EvolutionShellClient *client; + EOptionMenu *option_menu; + + char **possible_types; +}; + +static void +e_folder_list_changed (EFolderList *efl) +{ + gtk_signal_emit (GTK_OBJECT (efl), signals[CHANGED]); +} + +static void +e_folder_list_destroy (GtkObject *object) +{ + EFolderList *efl = E_FOLDER_LIST(object); + + if (efl->priv->gui) + gtk_object_unref(GTK_OBJECT(efl->priv->gui)); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +set_frame_label (EFolderList *efl) +{ + GtkFrame *frame = efl->priv->frame; + char *title = efl->priv->title; + if (frame) { + if (title) { + gtk_frame_set_label (frame, title); + gtk_frame_set_shadow_type (frame, GTK_SHADOW_ETCHED_IN); + } else { + gtk_frame_set_label (frame, ""); + gtk_frame_set_shadow_type (frame, GTK_SHADOW_NONE); + } + } +} + +static void +e_folder_list_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + EFolderList *efl = E_FOLDER_LIST(object); + + switch (arg_id) { + case ARG_TITLE: + g_free (efl->priv->title); + efl->priv->title = g_strdup (GTK_VALUE_STRING (*arg)); + set_frame_label (efl); + break; + case ARG_POSSIBLE_TYPES: + g_strfreev (efl->priv->possible_types); + efl->priv->possible_types = e_strdupv (GTK_VALUE_POINTER (*arg)); + break; + default: + break; + } +} + +static void +e_folder_list_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + EFolderList *efl = E_FOLDER_LIST(object); + + switch (arg_id) { + case ARG_TITLE: + GTK_VALUE_STRING (*arg) = g_strdup (efl->priv->title); + break; + case ARG_POSSIBLE_TYPES: + GTK_VALUE_POINTER (*arg) = e_strdupv ((const gchar **) efl->priv->possible_types); + break; + default: + arg->type = GTK_TYPE_INVALID; + break; + } +} + +static void +e_folder_list_class_init (EFolderListClass *klass) +{ + GtkObjectClass *object_class; + GtkVBoxClass *vbox_class; + + object_class = (GtkObjectClass*) klass; + vbox_class = (GtkVBoxClass *) klass; + + glade_gnome_init(); + + parent_class = gtk_type_class (PARENT_TYPE); + + object_class->set_arg = e_folder_list_set_arg; + object_class->get_arg = e_folder_list_get_arg; + object_class->destroy = e_folder_list_destroy; + + klass->changed = NULL; + klass->option_menu_changed = NULL; + + signals [OPTION_MENU_CHANGED] = + gtk_signal_new ("option_menu_changed", + GTK_RUN_LAST, + E_OBJECT_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (EFolderListClass, option_menu_changed), + gtk_marshal_NONE__INT, + GTK_TYPE_NONE, 1, GTK_TYPE_INT); + + signals [CHANGED] = + gtk_signal_new ("changed", + GTK_RUN_LAST, + E_OBJECT_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (EFolderListClass, changed), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + E_OBJECT_CLASS_ADD_SIGNALS (object_class, signals, LAST_SIGNAL); + + gtk_object_add_arg_type ("EFolderList::title", GTK_TYPE_STRING, + GTK_ARG_READWRITE, ARG_TITLE); + gtk_object_add_arg_type ("EFolderList::possible_types", GTK_TYPE_POINTER, + GTK_ARG_READWRITE, ARG_POSSIBLE_TYPES); +} + +#define SPEC "" \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + "" + + +static ETableMemoryStoreColumnInfo columns[] = { + E_TABLE_MEMORY_STORE_STRING, + E_TABLE_MEMORY_STORE_STRING, + E_TABLE_MEMORY_STORE_STRING, + E_TABLE_MEMORY_STORE_TERMINATOR +}; + +GtkWidget * +create_custom_optionmenu (char *name, char *string1, char *string2, int int1, int int2); + +GtkWidget * +create_custom_optionmenu (char *name, char *string1, char *string2, int int1, int int2) +{ + return e_option_menu_new (NULL); +} + +GtkWidget * +create_custom_folder_list (char *name, char *string1, char *string2, int int1, int int2); + +GtkWidget * +create_custom_folder_list (char *name, char *string1, char *string2, int int1, int int2) +{ + ETableModel *model; + GtkWidget *scrolled; + model = e_table_memory_store_new (columns); + scrolled = e_table_scrolled_new (model, NULL, SPEC, NULL); + gtk_object_set_data (GTK_OBJECT (scrolled), "table-model", model); + return scrolled; +} + +static void +add_clicked (GtkButton *button, EFolderList *efl) +{ + GNOME_Evolution_Folder *folder; + + evolution_shell_client_user_select_folder (efl->priv->client, + GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (efl))), + _("Add a Folder"), + NULL, + (const gchar **) efl->priv->possible_types, + &folder); + + if (folder != NULL) { + e_table_memory_store_insert (efl->priv->model, -1, NULL, folder->displayName, folder->evolutionUri, folder->physicalUri); + e_folder_list_changed (efl); + } +} + +static void +make_list (int model_row, gpointer closure) +{ + GList **list = closure; + *list = g_list_prepend (*list, GINT_TO_POINTER (model_row)); +} + +static void +remove_row (gpointer data, gpointer user_data) +{ + ETableMemoryStore *etms = user_data; + int row = GPOINTER_TO_INT (data); + + e_table_memory_store_remove (etms, row); +} + +static void +remove_clicked (GtkButton *button, EFolderList *efl) +{ + GList *list = NULL; + ETable *table; + + table = e_table_scrolled_get_table (efl->priv->scrolled_table); + + e_table_selected_row_foreach (table, make_list, &list); + + g_list_foreach (list, remove_row, efl->priv->model); + + g_list_free (list); + + e_folder_list_changed (efl); +} + +static void +edit_clicked (GtkButton *button, EFolderList *efl) +{ + ETable *table; + GNOME_Evolution_Folder *folder; + int cursor_row; + + table = e_table_scrolled_get_table (efl->priv->scrolled_table); + cursor_row = e_table_get_cursor_row (table); + + if (cursor_row != -1) { + char *initial = e_table_model_value_at (E_TABLE_MODEL (efl->priv->model), 1, cursor_row); + evolution_shell_client_user_select_folder (efl->priv->client, + GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (efl))), + _("Edit this Folder"), + initial, + (const gchar **) efl->priv->possible_types, + &folder); + + if (folder != NULL) { + e_table_memory_store_remove (efl->priv->model, cursor_row); + e_table_memory_store_insert (efl->priv->model, -1, NULL, folder->displayName, folder->evolutionUri, folder->physicalUri); + e_folder_list_changed (efl); + } + } +} + +static void +optionmenu_changed (EOptionMenu *option_menu, int value, EFolderList *efl) +{ + gtk_signal_emit (GTK_OBJECT (efl), signals[OPTION_MENU_CHANGED], value); +} + +static void +update_buttons (EFolderList *efl) +{ + int cursor_row; + int selection_count; + ETable *table; + + table = e_table_scrolled_get_table (efl->priv->scrolled_table); + cursor_row = e_table_get_cursor_row (table); + selection_count = e_table_selected_count (table); + + + e_glade_xml_set_sensitive (efl->priv->gui, "button-edit", cursor_row != -1); + e_glade_xml_set_sensitive (efl->priv->gui, "button-remove", selection_count >= 1); +} + +static void +cursor_changed (ESelectionModel *selection_model, int row, int col, EFolderList *efl) +{ + update_buttons (efl); +} + +static void +selection_changed (ESelectionModel *selection_model, EFolderList *efl) +{ + update_buttons (efl); +} + +static void +e_folder_list_init (EFolderList *efl) +{ + GladeXML *gui; + ESelectionModel *selection_model; + + efl->priv = g_new (EFolderListPrivate, 1); + + gui = glade_xml_new (EVOLUTION_GLADEDIR "/e-folder-list.glade", NULL); + efl->priv->gui = gui; + + efl->priv->title = NULL; + efl->priv->frame = GTK_FRAME (glade_xml_get_widget(gui, "frame-toplevel")); + if (efl->priv->frame == NULL) + return; + + gtk_widget_reparent(GTK_WIDGET (efl->priv->frame), + GTK_WIDGET (efl)); + + efl->priv->option_menu = E_OPTION_MENU(glade_xml_get_widget (gui, "custom-optionmenu")); + e_folder_list_set_option_menu_strings (efl, NULL); + efl->priv->scrolled_table = E_TABLE_SCROLLED(glade_xml_get_widget(gui, "custom-folder-list")); + efl->priv->model = E_TABLE_MEMORY_STORE (gtk_object_get_data (GTK_OBJECT (efl->priv->scrolled_table), "table-model")); + + e_glade_xml_connect_widget (gui, "button-add", "clicked", + GTK_SIGNAL_FUNC (add_clicked), efl); + e_glade_xml_connect_widget (gui, "button-remove", "clicked", + GTK_SIGNAL_FUNC (remove_clicked), efl); + e_glade_xml_connect_widget (gui, "button-edit", "clicked", + GTK_SIGNAL_FUNC (edit_clicked), efl); + e_glade_xml_connect_widget (gui, "custom-optionmenu", "changed", + GTK_SIGNAL_FUNC (optionmenu_changed), efl); + + selection_model = e_table_get_selection_model (e_table_scrolled_get_table (efl->priv->scrolled_table)); + + gtk_signal_connect (GTK_OBJECT (selection_model), "selection_changed", + GTK_SIGNAL_FUNC (selection_changed), efl); + gtk_signal_connect (GTK_OBJECT (selection_model), "cursor_changed", + GTK_SIGNAL_FUNC (cursor_changed), efl); + + efl->priv->possible_types = NULL; + set_frame_label (efl); +} + +EFolderListItem * +e_folder_list_parse_xml (char *xml) +{ + xmlDoc *doc; + xmlNode *root; + xmlNode *node; + int i; + EFolderListItem *items; + + if (xml == NULL || *xml == 0) { + items = g_new (EFolderListItem, 1); + items[0].uri = NULL; + items[0].physical_uri = NULL; + items[0].display_name = NULL; + return items; + } + + doc = xmlParseMemory (xml, strlen (xml)); + + root = xmlDocGetRootElement (doc); + + for (node = root->xmlChildrenNode, i = 0; node; node = node->next, i++) + /* Intentionally empty */; + + items = g_new (EFolderListItem, i + 1); + + for (node = root->xmlChildrenNode, i = 0; node; node = node->next, i++) { + items[i].uri = e_xml_get_string_prop_by_name_with_default (node, "uri", ""); + items[i].physical_uri = e_xml_get_string_prop_by_name_with_default (node, "physical-uri", ""); + items[i].display_name = e_xml_get_string_prop_by_name_with_default (node, "display-name", ""); + } + items[i].uri = NULL; + items[i].physical_uri = NULL; + items[i].display_name = NULL; + + xmlFreeDoc (doc); + + return items; +} + +char * +e_folder_list_create_xml (EFolderListItem *items) +{ + xmlDoc *doc; + xmlNode *root; + char *xml; + xmlChar *temp; + int length; + int i; + + doc = xmlNewDoc ("1.0"); + + root = xmlNewDocNode (doc, NULL, "EvolutionFolderList", NULL); + + xmlDocSetRootElement (doc, root); + + for (i = 0; items[i].uri; i++) { + xmlNode *node = xmlNewChild (root, NULL, "folder", NULL); + e_xml_set_string_prop_by_name (node, "uri", items[i].uri); + e_xml_set_string_prop_by_name (node, "physical-uri", items[i].physical_uri); + e_xml_set_string_prop_by_name (node, "display-name", items[i].display_name); + } + + xmlDocDumpMemory (doc, &temp, &length); + + xml = g_strdup (temp); + + xmlFree (temp); + xmlFreeDoc (doc); + + return xml; +} + +void +e_folder_list_free_items (EFolderListItem *items) +{ + int i; + for (i = 0; items[i].uri; i++) { + g_free (items[i].uri); + g_free (items[i].physical_uri); + g_free (items[i].display_name); + } + g_free (items); +} + +GtkType +e_folder_list_get_type (void) +{ + static GtkType folder_list_type = 0; + + if (!folder_list_type) + { + static const GtkTypeInfo folder_list_info = + { + "EFolderList", + sizeof (EFolderList), + sizeof (EFolderListClass), + (GtkClassInitFunc) e_folder_list_class_init, + (GtkObjectInitFunc) e_folder_list_init, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; + + folder_list_type = gtk_type_unique (PARENT_TYPE, &folder_list_info); + } + + return folder_list_type; +} + +GtkWidget* +e_folder_list_new (EvolutionShellClient *client, char *xml) +{ + GtkWidget *widget = GTK_WIDGET (gtk_type_new (e_folder_list_get_type ())); + e_folder_list_construct (E_FOLDER_LIST (widget), client, xml); + return widget; +} + +GtkWidget* +e_folder_list_construct (EFolderList *efl, EvolutionShellClient *client, char *xml) +{ + efl->priv->client = client; + e_folder_list_set_xml (efl, xml); + return GTK_WIDGET (efl); +} + +void +e_folder_list_set_items (EFolderList *efl, EFolderListItem *items) +{ + int i; + e_table_memory_store_clear (efl->priv->model); + for (i = 0; items[i].uri; i++) { + e_table_memory_store_insert (efl->priv->model, -1, NULL, items[i].display_name, items[i].uri, items[i].physical_uri); + } +} + +EFolderListItem * +e_folder_list_get_items (EFolderList *efl) +{ + EFolderListItem *items; + int count; + int i; + + count = e_table_model_row_count (E_TABLE_MODEL (efl->priv->model)); + + items = g_new (EFolderListItem, count + 1); + + for (i = 0; i < count; i++) { + items[i].display_name = g_strdup (e_table_model_value_at (E_TABLE_MODEL (efl->priv->model), 0, i)); + items[i].uri = g_strdup (e_table_model_value_at (E_TABLE_MODEL (efl->priv->model), 1, i)); + items[i].physical_uri = g_strdup (e_table_model_value_at (E_TABLE_MODEL (efl->priv->model), 2, i)); + } + items[i].uri = NULL; + items[i].physical_uri = NULL; + + return items; +} + +void +e_folder_list_set_xml (EFolderList *efl, char *xml) +{ + EFolderListItem *items; + + items = e_folder_list_parse_xml (xml); + e_folder_list_set_items (efl, items); + e_folder_list_free_items (items); +} + +char * +e_folder_list_get_xml (EFolderList *efl) +{ + EFolderListItem *items; + char *xml; + + items = e_folder_list_get_items (efl); + xml = e_folder_list_create_xml (items); + e_folder_list_free_items (items); + + return xml; +} + +void +e_folder_list_set_option_menu_strings_from_array (EFolderList *efl, gchar **strings) +{ + e_option_menu_set_strings_from_array (efl->priv->option_menu, strings); + if (strings && *strings) + gtk_widget_show (GTK_WIDGET (efl->priv->option_menu)); + else + gtk_widget_hide (GTK_WIDGET (efl->priv->option_menu)); +} + +void +e_folder_list_set_option_menu_strings (EFolderList *efl, gchar *first_label, ...) +{ + char **array; + + GET_STRING_ARRAY_FROM_ELLIPSIS (array, first_label); + + e_folder_list_set_option_menu_strings_from_array (efl, array); + + g_free (array); +} + +int +e_folder_list_get_option_menu_value (EFolderList *efl) +{ + return e_option_menu_get_value (efl->priv->option_menu); +} + +void +e_folder_list_set_option_menu_value (EFolderList *efl, int value) +{ + gtk_option_menu_set_history (GTK_OPTION_MENU (efl->priv->option_menu), value); +} diff --git a/shell/e-folder-list.h b/shell/e-folder-list.h new file mode 100644 index 0000000000..d3890812ac --- /dev/null +++ b/shell/e-folder-list.h @@ -0,0 +1,112 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * e-folder-list.h + * Copyright 2000, 2001, Ximian, Inc. + * + * Authors: + * Chris Lahey + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License, version 2, as published by the Free Software Foundation. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef __E_FOLDER_LIST_H__ +#define __E_FOLDER_LIST_H__ + +#include +#include "evolution-shell-client.h" + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +/* EFolderList - A dialog displaying information about a contact. + * + * The following arguments are available: + * + * name type read/write description + * -------------------------------------------------------------------------------- + */ + +#define E_FOLDER_LIST_TYPE (e_folder_list_get_type ()) +#define E_FOLDER_LIST(obj) (GTK_CHECK_CAST ((obj), E_FOLDER_LIST_TYPE, EFolderList)) +#define E_FOLDER_LIST_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_FOLDER_LIST_TYPE, EFolderListClass)) +#define E_IS_FOLDER_LIST(obj) (GTK_CHECK_TYPE ((obj), E_FOLDER_LIST_TYPE)) +#define E_IS_FOLDER_LIST_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_FOLDER_LIST_TYPE)) + + +typedef struct _EFolderListPrivate EFolderListPrivate; +typedef struct _EFolderList EFolderList; +typedef struct _EFolderListClass EFolderListClass; + +struct _EFolderList +{ + GtkVBox parent; + + /* item specific fields */ + EFolderListPrivate *priv; +}; + +struct _EFolderListClass +{ + GtkVBoxClass parent_class; + + void (*changed) (EFolderList *efl); + void (*option_menu_changed) (EFolderList *efl, int value); +}; + +typedef struct { + char *uri; + char *physical_uri; + char *display_name; +} EFolderListItem; + + +EFolderListItem *e_folder_list_parse_xml (char *xml); +char *e_folder_list_create_xml (EFolderListItem *items); +void e_folder_list_free_items (EFolderListItem *items); + +/* Standard functions */ +GtkType e_folder_list_get_type (void); +GtkWidget *e_folder_list_new (EvolutionShellClient *client, + char *xml); +GtkWidget *e_folder_list_construct (EFolderList *efl, + EvolutionShellClient *client, + char *xml); + +/* data access functions */ +void e_folder_list_set_items (EFolderList *efl, + EFolderListItem *items); +EFolderListItem *e_folder_list_get_items (EFolderList *efl); +void e_folder_list_set_xml (EFolderList *efl, + char *xml); +char *e_folder_list_get_xml (EFolderList *efl); + +/* Option Menu functions */ +void e_folder_list_set_option_menu_strings_from_array (EFolderList *efl, + gchar **strings); +void e_folder_list_set_option_menu_strings (EFolderList *efl, + gchar *first_label, + ...); +int e_folder_list_get_option_menu_value (EFolderList *efl); +void e_folder_list_set_option_menu_value (EFolderList *efl, + int value); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __E_FOLDER_LIST_H__ */ -- cgit v1.2.3