diff options
Diffstat (limited to 'e-util/e-config.c')
-rw-r--r-- | e-util/e-config.c | 1508 |
1 files changed, 0 insertions, 1508 deletions
diff --git a/e-util/e-config.c b/e-util/e-config.c deleted file mode 100644 index 064ca44a79..0000000000 --- a/e-util/e-config.c +++ /dev/null @@ -1,1508 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Authors: Michael Zucchi <notzed@ximian.com> - * - * Copyright 2004 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string.h> -#include <stdlib.h> - -#include <glib.h> - -#include <gtk/gtknotebook.h> -#include <gtk/gtkvbox.h> -#include <gtk/gtkhbox.h> -#include <gtk/gtktable.h> -#include <gtk/gtklabel.h> -#include <gtk/gtkframe.h> -#include <gtk/gtkalignment.h> - -#include <libgnomeui/gnome-druid.h> -#include <libgnomeui/gnome-druid-page-standard.h> -#include <libgnomeui/gnome-druid-page-edge.h> - -#include "e-config.h" - -#include <e-util/e-icon-factory.h> - -#include <libgnome/gnome-i18n.h> - -#define d(x) - -struct _EConfigFactory { - struct _EConfigFactory *next, *prev; - - char *id; - EConfigFactoryFunc factory; - void *factory_data; -}; - -struct _menu_node { - struct _menu_node *next, *prev; - - GSList *menu; - EConfigItemsFunc free; - EConfigItemsFunc abort; - EConfigItemsFunc commit; - void *data; -}; - -struct _widget_node { - struct _widget_node *next, *prev; - - EConfig *config; - - struct _menu_node *context; - EConfigItem *item; - struct _GtkWidget *widget; /* widget created by the factory, if any */ - struct _GtkWidget *frame; /* if created by us */ - - int empty:1; /* set if empty (i.e. hidden) */ -}; - -struct _check_node { - struct _check_node *next, *prev; - - char *pageid; - EConfigCheckFunc check; - void *data; -}; - -struct _EConfigPrivate { - EDList menus; - EDList widgets; - EDList checks; - - struct _widget_node *druid_page; /* current druid page if using the druid */ -}; - -static GObjectClass *ep_parent; - -static void -ep_init(GObject *o) -{ - EConfig *emp = (EConfig *)o; - struct _EConfigPrivate *p; - - p = emp->priv = g_malloc0(sizeof(struct _EConfigPrivate)); - - e_dlist_init(&p->menus); - e_dlist_init(&p->widgets); - e_dlist_init(&p->checks); -} - -static void -ep_finalise(GObject *o) -{ - EConfig *emp = (EConfig *)o; - struct _EConfigPrivate *p = emp->priv; - struct _menu_node *mnode; - struct _widget_node *wn; - struct _check_node *cn; - - d(printf("finalising EConfig %p\n", o)); - - g_free(emp->id); - - while ((mnode = (struct _menu_node *)e_dlist_remhead(&p->menus))) { - if (mnode->free) - mnode->free(emp, mnode->menu, mnode->data); - - g_free(mnode); - } - - while ( (wn = (struct _widget_node *)e_dlist_remhead(&p->widgets)) ) { - g_free(wn); - } - - while ( (cn = (struct _check_node *)e_dlist_remhead(&p->widgets)) ) { - g_free(cn->pageid); - g_free(cn); - } - - g_free(p); - - ((GObjectClass *)ep_parent)->finalize(o); -} - -static void -ec_target_free(EConfig *ep, EConfigTarget *t) -{ - g_free(t); - g_object_unref(ep); -} - -static void -ec_set_target(EConfig *emp, EConfigTarget *target) -{ - if (emp->target) - e_config_target_free(emp, target); - - emp->target = target; -} - -static void -ep_class_init(GObjectClass *klass) -{ - d(printf("EConfig class init %p '%s'\n", klass, g_type_name(((GObjectClass *)klass)->g_type_class.g_type))); - - klass->finalize = ep_finalise; - ((EConfigClass *)klass)->set_target = ec_set_target; - ((EConfigClass *)klass)->target_free = ec_target_free; -} - -static void -ep_base_init(GObjectClass *klass) -{ - e_dlist_init(&((EConfigClass *)klass)->factories); -} - -/** - * e_config_get_type: - * - * Standard GObject method. Used to subclass for the concrete - * implementations. - * - * Return value: EConfig type. - **/ -GType -e_config_get_type(void) -{ - static GType type = 0; - - if (type == 0) { - static const GTypeInfo info = { - sizeof(EConfigClass), - (GBaseInitFunc)ep_base_init, NULL, - (GClassInitFunc)ep_class_init, NULL, NULL, - sizeof(EConfig), 0, - (GInstanceInitFunc)ep_init - }; - ep_parent = g_type_class_ref(G_TYPE_OBJECT); - type = g_type_register_static(G_TYPE_OBJECT, "EConfig", &info, 0); - } - - return type; -} - -/** - * e_config_construct: - * @ep: The instance to initialise. - * @type: The type of configuration manager, @E_CONFIG_BOOK or - * @E_CONFIG_DRUID. - * @id: The name of the configuration window this manager drives. - * - * Used by implementing classes to initialise base parameters. - * - * Return value: @ep is returned. - **/ -EConfig *e_config_construct(EConfig *ep, int type, const char *id) -{ - g_assert(type == E_CONFIG_BOOK || type == E_CONFIG_DRUID); - - ep->type = type; - ep->id = g_strdup(id); - - return ep; -} - -/** - * e_config_add_items: - * @ec: An initialised implementing instance of EConfig. - * @items: A list of EConfigItem's to add to the configuration manager - * @ec. - * @commitfunc: If supplied, called to commit the configuration items - * to persistent storage. - * @abortfunc: If supplied, called to abort/undo the storage of these - * items permanently. - * @freefunc: If supplied, called to free the item list (and/or items) - * once they are no longer needed. - * @data: Data for the callback methods. - * - * Add new EConfigItems to the configuration window. Nothing will be - * done with them until the widget is built. - * - * TODO: perhaps commit and abort should just be signals. - **/ -void -e_config_add_items(EConfig *ec, GSList *items, EConfigItemsFunc commitfunc, EConfigItemsFunc abortfunc, EConfigItemsFunc freefunc, void *data) -{ - struct _menu_node *node; - - node = g_malloc(sizeof(*node)); - node->menu = items; - node->commit = commitfunc; - node->abort = abortfunc; - node->free = freefunc; - node->data = data; - e_dlist_addtail(&ec->priv->menus, (EDListNode *)node); -} - -/** - * e_config_add_page_check: - * @ec: Initialised implemeting instance of EConfig. - * @pageid: pageid to check. - * @check: checking callback. - * @data: user-data for the callback. - * - * Add a page-checking function callback. It will be called to validate the - * data in the given page or pages. If @pageid is NULL then it will be called - * to validate every page, or the whole configuration window. - * - * In the latter case, the pageid in the callback will be either the - * specific page being checked, or NULL when the whole config window - * is being checked. - * - * The page check function is used to validate input before allowing - * the druid to continue or the notebook to close. - **/ -void -e_config_add_page_check(EConfig *ec, const char *pageid, EConfigCheckFunc check, void *data) -{ - struct _check_node *cn; - - cn = g_malloc0(sizeof(*cn)); - cn->pageid = g_strdup(pageid); - cn->check = check; - cn->data = data; - - e_dlist_addtail(&ec->priv->checks, (EDListNode *)cn); -} - -static void -ec_add_static_items(EConfig *ec) -{ - struct _EConfigFactory *f; - EConfigClass *klass = (EConfigClass *)G_OBJECT_GET_CLASS(ec); - - f = (struct _EConfigFactory *)klass->factories.head; - while (f->next) { - if (f->id == NULL - || !strcmp(f->id, ec->id)) { - f->factory(ec, f->factory_data); - } - f = f->next; - } -} - -static int -ep_cmp(const void *ap, const void *bp) -{ - struct _widget_node *a = *((void **)ap); - struct _widget_node *b = *((void **)bp); - - return strcmp(a->item->path, b->item->path); -} - -static void -ec_druid_check_current(EConfig *ec) -{ - g_return_if_fail(ec->priv->druid_page != NULL); - - if (e_config_page_check(ec, ec->priv->druid_page->item->path)) { - gtk_widget_set_sensitive(((GnomeDruid *)ec->widget)->next, TRUE); - } else { - gtk_widget_set_sensitive(((GnomeDruid *)ec->widget)->next, FALSE); - } -} - -static void -ec_druid_cancel(GnomeDruid *druid, struct _widget_node *wn) -{ - d(printf("finishing druid, calling abort\n")); - e_config_abort(wn->config); - - if (wn->config->window) - gtk_widget_destroy(wn->config->window); -} - -static void -ec_druid_finish(GnomeDruidPage *page, GnomeDruid *druid, struct _widget_node *wn) -{ - d(printf("finishing druid, calling commit\n")); - e_config_commit(wn->config); - - /* TODO: allow the commit to fail? Do we care? */ - if (wn->config->window) - gtk_widget_destroy(wn->config->window); -} - -static void -ec_druid_prepare(GnomeDruidPage *page, GnomeDruid *druid, struct _widget_node *wn) -{ - d(printf("prepare page '%s'\n", wn->item->path)); - wn->config->priv->druid_page = wn; - ec_druid_check_current(wn->config); -} - -static gboolean -ec_druid_prev(GnomeDruidPage *page, GnomeDruid *druid, struct _widget_node *wn) -{ - EConfig *ec = wn->config; - - d(printf("prev page from '%s'\n", wn->item->path)); - if (wn->prev) { - for (wn = wn->prev;wn->prev;wn=wn->prev) { - if (!wn->empty && wn->frame != NULL - && (wn->item->type == E_CONFIG_PAGE - || wn->item->type == E_CONFIG_PAGE_START - || wn->item->type == E_CONFIG_PAGE_FINISH)) - break; - } - } - - if (wn->prev) { - d(printf(" is %s\n",wn->item->path)); - gnome_druid_set_page((GnomeDruid *)ec->widget, (GnomeDruidPage *)wn->frame); - ec->priv->druid_page = wn; - } else { - /* do we need to indicate first? */ - ec->priv->druid_page = NULL; - } - - return wn->prev != NULL; -} - -static gboolean -ec_druid_next(GnomeDruidPage *page, GnomeDruid *druid, struct _widget_node *wn) -{ - EConfig *ec = wn->config; - - d(printf("next page from '%s'\n", wn->item->path)); - if (wn->next) { - for (wn = wn->next;wn->next;wn=wn->next) { - if (!wn->empty && wn->frame != NULL - && (wn->item->type == E_CONFIG_PAGE - || wn->item->type == E_CONFIG_PAGE_START - || wn->item->type == E_CONFIG_PAGE_FINISH)) - break; - } - } - - if (wn->next) { - d(printf(" is %s\n",wn->item->path)); - gnome_druid_set_page((GnomeDruid *)ec->widget, (GnomeDruidPage *)wn->frame); - ec->priv->druid_page = wn; - } else { - /* do we need to indicate last? */ - ec->priv->druid_page = NULL; - } - - return wn->next != NULL; -} - -static void -ec_rebuild(EConfig *emp) -{ - struct _EConfigPrivate *p = emp->priv; - struct _widget_node *wn, *sectionnode = NULL, *pagenode = NULL; - GtkWidget *book = NULL, *page = NULL, *section = NULL, *root = NULL, *druid = NULL; - int pageno = 0, sectionno = 0, itemno = 0; - - d(printf("target changed, rebuilding:\n")); - - /* TODO: This code is pretty complex, and will probably just - * become more complex with time. It could possibly be split - * into the two base types, but there would be a lot of code - * duplication */ - - for (wn = (struct _widget_node *)p->widgets.head;wn->next;wn=wn->next) { - struct _EConfigItem *item = wn->item; - GtkWidget *w; - - d(printf(" '%s'\n", item->path)); - - /* If the last section doesn't contain anything, hide it */ - if (sectionnode != NULL - && sectionnode->frame != NULL - && (item->type == E_CONFIG_PAGE_START - || item->type == E_CONFIG_PAGE_FINISH - || item->type == E_CONFIG_PAGE - || item->type == E_CONFIG_SECTION - || item->type == E_CONFIG_SECTION_TABLE)) { - if ( (sectionnode->empty = itemno == 0) ) { - gtk_widget_hide(sectionnode->frame); - sectionno--; - } else - gtk_widget_show(sectionnode->frame); - d(printf("%s section '%s' [sections=%d]\n", sectionnode->empty?"hiding":"showing", sectionnode->item->path, sectionno)); - } - - /* If the last page doesn't contain anything, hide it */ - if (pagenode != NULL - && pagenode->frame != NULL - && (item->type == E_CONFIG_PAGE_START - || item->type == E_CONFIG_PAGE_FINISH - || item->type == E_CONFIG_PAGE)) { - if ( (pagenode->empty = sectionno == 0) ) { - gtk_widget_hide(pagenode->frame); - pageno--; - } else - gtk_widget_show(pagenode->frame); - d(printf("%s page '%s' [section=%d]\n", pagenode->empty?"hiding":"showing", pagenode->item->path, pageno)); - } - - /* Now process the item */ - switch (item->type) { - case E_CONFIG_BOOK: - case E_CONFIG_DRUID: - /* Only one of BOOK or DRUID may be define, it - is used by the defining code to mark the - type of the config window. It is - cross-checked with the code's defined - type. */ - if (root != NULL) { - g_warning("EConfig book/druid redefined at: %s", item->path); - break; - } - - if (wn->widget == NULL) { - if (item->type != emp->type) { - g_warning("EConfig book/druid type mismatch"); - break; - } - if (item->factory) { - root = item->factory(emp, item, NULL, wn->widget, wn->context->data); - } else if (item->type == E_CONFIG_BOOK) { - root = book = gtk_notebook_new(); - gtk_widget_show(book); - } else if (item->type == E_CONFIG_DRUID) { - root = druid = gnome_druid_new(); - gtk_widget_show(druid); - } else - abort(); - - if (item->type == E_CONFIG_DRUID) - g_signal_connect(root, "cancel", G_CALLBACK(ec_druid_cancel), wn); - - emp->widget = root; - wn->widget = root; - } else { - root = wn->widget; - } - - if (item->type == E_CONFIG_BOOK) - book = root; - else - druid = root; - - page = NULL; - pagenode = NULL; - section = NULL; - sectionnode = NULL; - pageno = 0; - sectionno = 0; - break; - case E_CONFIG_PAGE_START: - case E_CONFIG_PAGE_FINISH: - if (root == NULL) { - g_warning("EConfig page defined before container widget: %s", item->path); - break; - } - if (emp->type != E_CONFIG_DRUID) { - g_warning("EConfig druid start/finish pages can't be used on E_CONFIG_BOOKs"); - break; - } - - if (wn->widget == NULL) { - if (item->factory) { - page = item->factory(emp, item, root, wn->frame, wn->context->data); - } else { - page = gnome_druid_page_edge_new(item->type == E_CONFIG_PAGE_START?GNOME_EDGE_START:GNOME_EDGE_FINISH); - gtk_widget_show(page); - gnome_druid_page_edge_set_title((GnomeDruidPageEdge *)page, item->label); - gnome_druid_insert_page((GnomeDruid *)druid, pagenode?(GnomeDruidPage *)pagenode->frame:NULL, (GnomeDruidPage *)page); - } - if (item->type == E_CONFIG_PAGE_FINISH) { - g_signal_connect(page, "back", G_CALLBACK(ec_druid_prev), wn); - g_signal_connect(page, "finish", G_CALLBACK(ec_druid_finish), wn); - } else - g_signal_connect(page, "next", G_CALLBACK(ec_druid_next), wn); - wn->frame = page; - wn->widget = page; - } - pageno++; - page = NULL; - pagenode = wn; /* need this for previous page linking */ - section = NULL; - sectionnode = NULL; - sectionno = 1; /* never want to hide these */ - break; - case E_CONFIG_PAGE: { - int connect = 0; /* connect druid signals */ - - /* CONFIG_PAGEs depend on the config type. - E_CONFIG_BOOK: - The page is a VBox, stored in the notebook. - E_CONFIG_DRUID - The page is a GnomeDruidPageStandard, - any sections automatically added are added to - the vbox inside it. */ - sectionno = 0; - if (root == NULL) { - g_warning("EConfig page defined before container widget: %s", item->path); - break; - } - - if (item->factory) { - page = item->factory(emp, item, root, wn->frame, wn->context->data); - if (emp->type == E_CONFIG_DRUID) { - if (page) { - g_assert(GNOME_IS_DRUID_PAGE_STANDARD(page)); - connect = wn->frame != page; - wn->frame = page; - page = ((GnomeDruidPageStandard *)page)->vbox; - } else - wn->frame = page; - } else { - wn->frame = page; - if (page) - gtk_notebook_reorder_child((GtkNotebook *)book, page, pageno); - } - if (page) - sectionno = 1; - } else if (wn->widget == NULL) { - if (emp->type == E_CONFIG_DRUID) { - w = gnome_druid_page_standard_new(); - gtk_widget_show(w); - gnome_druid_page_standard_set_title((GnomeDruidPageStandard *)w, item->label); - gnome_druid_insert_page((GnomeDruid *)druid, pagenode?(GnomeDruidPage *)pagenode->frame:NULL, (GnomeDruidPage *)w); - wn->frame = w; - page = ((GnomeDruidPageStandard *)w)->vbox; - connect = TRUE; - } else { - w = gtk_label_new_with_mnemonic (item->label); - gtk_widget_show(w); - page = gtk_vbox_new(FALSE, 12); - gtk_container_set_border_width((GtkContainer *)page, 12); - gtk_widget_show(page); - gtk_notebook_insert_page((GtkNotebook *)book, page, w, pageno); - wn->frame = page; - } - } else - page = wn->widget; - - d(printf("page %d:%s widget %p\n", pageno, item->path, page)); - - if (wn->widget && wn->widget != page) { - d(printf("destroy old widget for page '%s'\n", item->path)); - gtk_widget_destroy(wn->widget); - } - - if (connect) { - g_signal_connect(wn->frame, "next", G_CALLBACK(ec_druid_next), wn); - g_signal_connect(wn->frame, "back", G_CALLBACK(ec_druid_prev), wn); - /* GnomeDruid bug, need to connect_after */ - g_signal_connect_after(wn->frame, "prepare", G_CALLBACK(ec_druid_prepare), wn); - } - - pageno++; - pagenode = wn; - section = NULL; - sectionnode = NULL; - wn->widget = page; - if (page) - g_signal_connect(page, "destroy", G_CALLBACK(gtk_widget_destroyed), &wn->widget); - break; } - case E_CONFIG_SECTION: - case E_CONFIG_SECTION_TABLE: - /* The section factory is always called with - the parent vbox object. Even for druid - pages. */ - if (page == NULL) { - /*g_warning("EConfig section '%s' has no parent page", item->path);*/ - section = NULL; - wn->widget = NULL; - wn->frame = NULL; - goto nopage; - } - - itemno = 0; - if (item->factory) { - section = item->factory(emp, item, page, wn->widget, wn->context->data); - wn->frame = section; - if (section) - itemno = 1; - - if (section - && ((item->type == E_CONFIG_SECTION && !GTK_IS_BOX(section)) - || (item->type == E_CONFIG_SECTION_TABLE && !GTK_IS_TABLE(section)))) - g_warning("EConfig section type is wrong"); - } else { - GtkWidget *frame; - GtkWidget *label = NULL; - - if (wn->frame) { - d(printf("Item %s, clearing generated section widget\n", wn->item->path)); - gtk_widget_destroy(wn->frame); - wn->widget = NULL; - wn->frame = NULL; - } - - if (item->label) { - char *txt = g_strdup_printf("<span weight=\"bold\">%s</span>", item->label); - - label = g_object_new(gtk_label_get_type(), - "label", txt, - "use_markup", TRUE, - "xalign", 0.0, NULL); - g_free(txt); - } - - if (item->type == E_CONFIG_SECTION) - section = gtk_vbox_new(FALSE, 6); - else { - section = gtk_table_new(1, 1, FALSE); - gtk_table_set_col_spacings((GtkTable *)section, 6); - gtk_table_set_row_spacings((GtkTable *)section, 6); - } - - frame = g_object_new(gtk_frame_get_type(), - "shadow_type", GTK_SHADOW_NONE, - "label_widget", label, - "child", g_object_new(gtk_alignment_get_type(), - "left_padding", 12, - "top_padding", 6, - "child", section, NULL), - NULL); - gtk_widget_show_all(frame); - gtk_box_pack_start((GtkBox *)page, frame, FALSE, FALSE, 0); - wn->frame = frame; - } - nopage: - if (wn->widget && wn->widget != section) { - d(printf("destroy old widget for section '%s'\n", item->path)); - gtk_widget_destroy(wn->widget); - } - - d(printf("Item %s, setting section widget\n", wn->item->path)); - - sectionno++; - wn->widget = section; - if (section) - g_signal_connect(section, "destroy", G_CALLBACK(gtk_widget_destroyed), &wn->widget); - sectionnode = wn; - break; - case E_CONFIG_ITEM: - case E_CONFIG_ITEM_TABLE: - /* generated sections never retain their widgets on a rebuild */ - if (sectionnode->item->factory == NULL) - wn->widget = NULL; - - /* ITEMs are called with the section parent. - The type depends on the section type, - either a GtkTable, or a GtkVBox */ - w = NULL; - if (section == NULL) { - wn->widget = NULL; - wn->frame = NULL; - g_warning("EConfig item has no parent section: %s", item->path); - } else if ((item->type == E_CONFIG_ITEM && !GTK_IS_BOX(section)) - || (item->type == E_CONFIG_ITEM_TABLE && !GTK_IS_TABLE(section))) - g_warning("EConfig item parent type is incorrect: %s", item->path); - else if (item->factory) - w = item->factory(emp, item, section, wn->widget, wn->context->data); - - d(printf("item %d:%s widget %p\n", itemno, item->path, w)); - - if (wn->widget && wn->widget != w) { - d(printf("destroy old widget for item '%s'\n", item->path)); - gtk_widget_destroy(wn->widget); - } - - wn->widget = w; - if (w) { - g_signal_connect(w, "destroy", G_CALLBACK(gtk_widget_destroyed), &wn->widget); - itemno++; - } - break; - } - } - - /* If the last section doesn't contain anything, hide it */ - if (sectionnode != NULL && sectionnode->frame != NULL) { - if ( (sectionnode->empty = itemno == 0) ) { - gtk_widget_hide(sectionnode->frame); - sectionno--; - } else - gtk_widget_show(sectionnode->frame); - d(printf("%s section '%s' [sections=%d]\n", sectionnode->empty?"hiding":"showing", sectionnode->item->path, sectionno)); - } - - /* If the last page doesn't contain anything, hide it */ - if (pagenode != NULL && pagenode->frame != NULL) { - if ( (pagenode->empty = sectionno == 0) ) { - gtk_widget_hide(pagenode->frame); - pageno--; - } else - gtk_widget_show(pagenode->frame); - d(printf("%s page '%s' [section=%d]\n", pagenode->empty?"hiding":"showing", pagenode->item->path, pageno)); - } - - if (book) { - /* make this depend on flags?? */ - if (gtk_notebook_get_n_pages((GtkNotebook *)book) == 1) { - gtk_notebook_set_show_tabs((GtkNotebook *)book, FALSE); - gtk_notebook_set_show_border((GtkNotebook *)book, FALSE); - } - } -} - -/** - * e_config_set_target: - * @emp: An initialised EConfig. - * @target: A target allocated from @emp. - * - * Sets the target object for the config window. Generally the target - * is set only once, and will supply its own "changed" signal which - * can be used to drive the modal. This is a virtual method so that - * the implementing class can connect to the changed signal and - * initiate a e_config_target_changed() call where appropriate. - **/ -void -e_config_set_target(EConfig *emp, EConfigTarget *target) -{ - if (emp->target != target) - ((EConfigClass *)G_OBJECT_GET_CLASS(emp))->set_target(emp, target); -} - -static void -ec_widget_destroy(GtkWidget *w, EConfig *ec) -{ - if (ec->target) { - e_config_target_free(ec, ec->target); - ec->target = NULL; - } - - g_object_unref(ec); -} - -/** - * e_config_create_widget: - * @emp: An initialised EConfig object. - * - * Create the widget described by @emp. Only the core widget - * appropriate for the given type is created, i.e. a GtkNotebook for - * the E_CONFIG_BOOK type and a GnomeDruid for the E_CONFIG_DRUID - * type. - * - * This object will be self-driving, but will not close itself once - * complete. - * - * Unless reffed otherwise, the management object @emp will be - * finalised when the widget is. - * - * Return value: The widget, also available in @emp.widget - **/ -GtkWidget * -e_config_create_widget(EConfig *emp) -{ - struct _EConfigPrivate *p = emp->priv; - struct _menu_node *mnode; - GPtrArray *items = g_ptr_array_new(); - GSList *l; - /*char *domain = NULL;*/ - int i; - - g_assert(emp->target != NULL); - - ec_add_static_items(emp); - - /* FIXME: need to override old ones with new names */ - for (mnode = (struct _menu_node *)p->menus.head;mnode->next;mnode=mnode->next) - for (l=mnode->menu; l; l = l->next) { - struct _EConfigItem *item = l->data; - struct _widget_node *wn = g_malloc0(sizeof(*wn)); - - wn->item = item; - wn->context = mnode; - wn->config = emp; - g_ptr_array_add(items, wn); - } - - qsort(items->pdata, items->len, sizeof(items->pdata[0]), ep_cmp); - - for (i=0;i<items->len;i++) { - struct _widget_node *wn = items->pdata[i]; - - e_dlist_addtail(&p->widgets, (EDListNode *)wn); - } - - g_ptr_array_free(items, TRUE); - ec_rebuild(emp); - - /* auto-unref it */ - g_signal_connect(emp->widget, "destroy", G_CALLBACK(ec_widget_destroy), emp); - - /* FIXME: for some reason ec_rebuild puts the widget on page 1, this is just to override that */ - if (emp->type == E_CONFIG_BOOK) - gtk_notebook_set_current_page((GtkNotebook *)emp->widget, 0); - - return emp->widget; -} - -static void -ec_dialog_response(GtkWidget *d, int id, EConfig *ec) -{ - if (id == GTK_RESPONSE_OK) - e_config_commit(ec); - else - e_config_abort(ec); - - gtk_widget_destroy(d); -} - -/** - * e_config_create_window: - * @emp: Initialised and configured EMConfig derived instance. - * @parent: Parent window or NULL. - * @title: Title of window or dialog. - * - * Create a managed GtkWindow object from @emp. This window will be - * fully driven by the EConfig @emp. If @emp.type is - * @E_CONFIG_DRUID, then this will be a toplevel GtkWindow containing - * a GnomeDruid. If it is @E_CONFIG_BOOK then it will be a GtkDialog - * containing a Nnotebook. - * - * Unless reffed otherwise, the management object @emp will be - * finalised when the widget is. - * - * Return value: The window widget. This is also stored in @emp.window. - **/ -GtkWidget * -e_config_create_window(EConfig *emp, struct _GtkWindow *parent, const char *title) -{ - GtkWidget *w; - - e_config_create_widget(emp); - - if (emp->type == E_CONFIG_BOOK) { - w = gtk_dialog_new_with_buttons(title, parent, - GTK_DIALOG_DESTROY_WITH_PARENT | - GTK_DIALOG_NO_SEPARATOR, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, GTK_RESPONSE_OK, - NULL); - g_signal_connect(w, "response", G_CALLBACK(ec_dialog_response), emp); - - gtk_widget_ensure_style (w); - gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (w)->vbox), 0); - gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (w)->action_area), 12); - - gtk_box_pack_start((GtkBox *)((GtkDialog *)w)->vbox, emp->widget, TRUE, TRUE, 0); - } else { - /* response is handled directly by the druid stuff */ - w = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_title ((GtkWindow *)w, title); - gtk_container_add((GtkContainer *)w, emp->widget); - gtk_window_set_type_hint((GtkWindow *)w, GDK_WINDOW_TYPE_HINT_DIALOG); - } - - emp->window = w; - gtk_widget_show(w); - - return w; -} - -/** - * e_config_target_changed: - * @emp: - * @how: - * - * Indicate that the target has changed. This may be called by the - * self-aware target itself, or by the driving code. If @how is - * %E_CONFIG_TARGET_CHANGED_REBUILD, then the entire configuration - * widget may be recreated based on the changed target. - * - * This is used to sensitise Druid next/back buttons and the Apply - * button for the Notebook mode. - **/ -void e_config_target_changed(EConfig *emp, e_config_target_change_t how) -{ - if (how == E_CONFIG_TARGET_CHANGED_REBUILD) - ec_rebuild(emp); - - if (emp->type == E_CONFIG_DRUID) { - if (emp->priv->druid_page) { - gnome_druid_set_page((GnomeDruid *)emp->widget, (GnomeDruidPage *)emp->priv->druid_page->frame); - ec_druid_check_current(emp); - } - } else { - if (emp->window) { - if (e_config_page_check(emp, NULL)) { - gtk_dialog_set_response_sensitive((GtkDialog *)emp->window, GTK_RESPONSE_OK, TRUE); - } else { - gtk_dialog_set_response_sensitive((GtkDialog *)emp->window, GTK_RESPONSE_OK, FALSE); - } - } - } - - /* virtual method/signal? */ -} - -/** - * e_config_abort: - * @ec: - * - * Signify that the stateful configuration changes must be discarded - * to all listeners. This is used by self-driven druid or notebook, or - * may be used by code using the widget directly. - **/ -void e_config_abort(EConfig *ec) -{ - struct _EConfigPrivate *p = ec->priv; - struct _menu_node *mnode; - - /* TODO: should these just be signals? */ - - for (mnode = (struct _menu_node *)p->menus.head;mnode->next;mnode=mnode->next) - if (mnode->abort) - mnode->abort(ec, mnode->menu, mnode->data); -} - -/** - * e_config_commit: - * @ec: - * - * Signify that the stateful configuration changes should be saved. - * This is used by the self-driven druid or notebook, or may be used - * by code driving the widget directly. - **/ -void e_config_commit(EConfig *ec) -{ - struct _EConfigPrivate *p = ec->priv; - struct _menu_node *mnode; - - /* TODO: should these just be signals? */ - - for (mnode = (struct _menu_node *)p->menus.head;mnode->next;mnode=mnode->next) - if (mnode->commit) - mnode->commit(ec, mnode->menu, mnode->data); -} - -/** - * e_config_page_check: - * @ec: - * @pageid: The path of the page item. - * - * Check that a given page is complete. If @pageid is NULL, then check - * the whole config. No check is made that the page actually exists. - * - * Return value: FALSE if the data is inconsistent/incomplete. - **/ -gboolean e_config_page_check(EConfig *ec, const char *pageid) -{ - struct _EConfigPrivate *p = ec->priv; - struct _check_node *mnode; - - for (mnode = (struct _check_node *)p->checks.head;mnode->next;mnode=mnode->next) - if ((pageid == NULL - || mnode->pageid == NULL - || strcmp(mnode->pageid, pageid) == 0) - && !mnode->check(ec, pageid, mnode->data)) - return FALSE; - - return TRUE; -} - -/** - * e_config_page_get: - * @ec: - * @pageid: The path of the page item. - * - * Retrieve the page widget corresponding to @pageid. - * - * Return value: The page widget. It will be the root GtkNotebook - * container or the GnomeDruidPage object. - **/ -GtkWidget *e_config_page_get(EConfig *ec, const char *pageid) -{ - struct _widget_node *wn; - - for (wn = (struct _widget_node *)ec->priv->widgets.head;wn->next;wn=wn->next) - if (!wn->empty - && (wn->item->type == E_CONFIG_PAGE - || wn->item->type == E_CONFIG_PAGE_START - || wn->item->type == E_CONFIG_PAGE_FINISH) - && !strcmp(wn->item->path, pageid)) - return wn->frame; - - return NULL; -} - -/** - * e_config_page_next: - * @ec: - * @pageid: The path of the page item. - * - * Find the path of the next visible page after @pageid. If @pageid - * is NULL then find the first visible page. - * - * Return value: The path of the next page, or @NULL if @pageid was the - * last configured and visible page. - **/ -const char *e_config_page_next(EConfig *ec, const char *pageid) -{ - struct _widget_node *wn; - int found; - - found = pageid == NULL ? 1:0; - for (wn = (struct _widget_node *)ec->priv->widgets.head;wn->next;wn=wn->next) - if (!wn->empty - && (wn->item->type == E_CONFIG_PAGE - || wn->item->type == E_CONFIG_PAGE_START - || wn->item->type == E_CONFIG_PAGE_FINISH)) { - if (found) - return wn->item->path; - else if (strcmp(wn->item->path, pageid) == 0) - found = 1; - } - - return NULL; -} - -/** - * e_config_page_next: - * @ec: - * @pageid: The path of the page item. - * - * Find the path of the previous visible page before @pageid. If @pageid - * is NULL then find the last visible page. - * - * Return value: The path of the previous page, or @NULL if @pageid was the - * first configured and visible page. - **/ -const char *e_config_page_prev(EConfig *ec, const char *pageid) -{ - struct _widget_node *wn; - int found; - - found = pageid == NULL ? 1:0; - for (wn = (struct _widget_node *)ec->priv->widgets.tailpred;wn->prev;wn=wn->prev) - if (!wn->empty - && (wn->item->type == E_CONFIG_PAGE - || wn->item->type == E_CONFIG_PAGE_START - || wn->item->type == E_CONFIG_PAGE_FINISH)) { - if (found) - return wn->item->path; - else if (strcmp(wn->item->path, pageid) == 0) - found = 1; - } - - return NULL; -} - -/* ********************************************************************** */ - -/** - * e_config_class_add_factory: - * @klass: Implementing class pointer. - * @id: The name of the configuration window you're interested in. - * This may be NULL to be called for all windows. - * @func: An EConfigFactoryFunc to call when the window @id is being - * created. - * @data: Callback data. - * - * Add a config factory which will be called to add_items() any - * extra items's if wants to, to the current Config window. - * - * TODO: Make the id a pattern? - * - * Return value: A handle to the factory. - **/ -EConfigFactory * -e_config_class_add_factory(EConfigClass *klass, const char *id, EConfigFactoryFunc func, void *data) -{ - struct _EConfigFactory *f = g_malloc0(sizeof(*f)); - - f->id = g_strdup(id); - f->factory = func; - f->factory_data = data; - e_dlist_addtail(&klass->factories, (EDListNode *)f); - - return f; -} - -/** - * e_config_class_remove_factory: - * @f: Handle from :class_add_factory() call. - * - * Remove a config factory. The handle @f may only be removed once. - **/ -void -e_config_class_remove_factory(EConfigClass *klass, EConfigFactory *f) -{ - e_dlist_remove((EDListNode *)f); - g_free(f->id); - g_free(f); -} - -/** - * e_config_target_new: - * @ep: Parent EConfig object. - * @type: type, up to implementor - * @size: Size of object to allocate. - * - * Allocate a new config target suitable for this class. Implementing - * classes will define the actual content of the target. - **/ -void *e_config_target_new(EConfig *ep, int type, size_t size) -{ - EConfigTarget *t; - - g_assert(size >= sizeof(EConfigTarget)); - - t = g_malloc0(size); - t->config = ep; - g_object_ref(ep); - t->type = type; - - return t; -} - -/** - * e_config_target_free: - * @ep: Parent EConfig object. - * @o: The target to fre. - * - * Free a target. The implementing class can override this method to - * free custom targets. - **/ -void -e_config_target_free(EConfig *ep, void *o) -{ - EConfigTarget *t = o; - - ((EConfigClass *)G_OBJECT_GET_CLASS(ep))->target_free(ep, t); -} - -/* ********************************************************************** */ - -/* Config menu plugin handler */ - -/* -<e-plugin - class="org.gnome.mail.plugin.config:1.0" - id="org.gnome.mail.plugin.config.item:1.0" - type="shlib" - location="/opt/gnome2/lib/camel/1.0/libcamelimap.so" - name="imap" - description="IMAP4 and IMAP4v1 mail store"> - <hook class="org.gnome.mail.configMenu:1.0" - handler="HandleConfig"> - <menu id="any" target="select"> - <item - type="item|toggle|radio|image|submenu|bar" - active - path="foo/bar" - label="label" - icon="foo" - activate="ep_view_emacs"/> - </menu> - </extension> - -*/ - -static void *emph_parent_class; -#define emph ((EConfigHook *)eph) - -static const EPluginHookTargetKey ech_item_types[] = { - { "book", E_CONFIG_BOOK }, - { "druid", E_CONFIG_DRUID }, - - { "page", E_CONFIG_PAGE }, - { "page_start", E_CONFIG_PAGE_START }, - { "page_finish", E_CONFIG_PAGE_FINISH }, - { "section", E_CONFIG_SECTION }, - { "section_table", E_CONFIG_SECTION_TABLE }, - { "item", E_CONFIG_ITEM }, - { "item_table", E_CONFIG_ITEM_TABLE }, - { 0 }, -}; - -static void -ech_commit(EConfig *ec, GSList *items, void *data) -{ - struct _EConfigHookGroup *group = data; - - if (group->commit && group->hook->hook.plugin->enabled) - e_plugin_invoke(group->hook->hook.plugin, group->commit, ec->target); -} - -static void -ech_abort(EConfig *ec, GSList *items, void *data) -{ - struct _EConfigHookGroup *group = data; - - if (group->abort && group->hook->hook.plugin->enabled) - e_plugin_invoke(group->hook->hook.plugin, group->abort, ec->target); -} - -static gboolean -ech_check(EConfig *ec, const char *pageid, void *data) -{ - struct _EConfigHookGroup *group = data; - EConfigHookPageCheckData hdata; - - if (!group->hook->hook.plugin->enabled) - return TRUE; - - hdata.config = ec; - hdata.target = ec->target; - hdata.pageid = pageid?pageid:""; - - return GPOINTER_TO_INT(e_plugin_invoke(group->hook->hook.plugin, group->check, &hdata)); -} - -static void -ech_config_factory(EConfig *emp, void *data) -{ - struct _EConfigHookGroup *group = data; - - d(printf("config factory called %s\n", group->id?group->id:"all menus")); - - if (emp->target->type != group->target_type - || !group->hook->hook.plugin->enabled) - return; - - if (group->items) - e_config_add_items(emp, group->items, ech_commit, ech_abort, NULL, group); - - if (group->check) - e_config_add_page_check(emp, NULL, ech_check, group); -} - -static void -emph_free_item(struct _EConfigItem *item) -{ - g_free(item->path); - g_free(item->label); - g_free(item->user_data); - g_free(item); -} - -static void -emph_free_group(struct _EConfigHookGroup *group) -{ - g_slist_foreach(group->items, (GFunc)emph_free_item, NULL); - g_slist_free(group->items); - - g_free(group->id); - g_free(group); -} - -static struct _GtkWidget * -ech_config_widget_factory(EConfig *ec, EConfigItem *item, GtkWidget *parent, GtkWidget *old, void *data) -{ - struct _EConfigHookGroup *group = data; - - if (group->hook->hook.plugin->enabled) { - EConfigHookItemFactoryData hdata; - - hdata.config = ec; - hdata.item = item; - hdata.target = ec->target; - hdata.parent = parent; - hdata.old = old; - - return (struct _GtkWidget *)e_plugin_invoke(group->hook->hook.plugin, (char *)item->user_data, &hdata); - } else - return NULL; -} - -static struct _EConfigItem * -emph_construct_item(EPluginHook *eph, EConfigHookGroup *menu, xmlNodePtr root, EConfigHookTargetMap *map) -{ - struct _EConfigItem *item; - - d(printf(" loading config item\n")); - item = g_malloc0(sizeof(*item)); - if ((item->type = e_plugin_hook_id(root, ech_item_types, "type")) == -1) - goto error; - item->path = e_plugin_xml_prop(root, "path"); - item->label = e_plugin_xml_prop_domain(root, "label", eph->plugin->domain); - item->user_data = e_plugin_xml_prop(root, "factory"); - - if (item->path == NULL - || (item->label == NULL && item->user_data == NULL)) - goto error; - - if (item->user_data) - item->factory = ech_config_widget_factory; - - d(printf(" path=%s label=%s factory=%s\n", item->path, item->label, (char *)item->user_data)); - - return item; -error: - d(printf("error!\n")); - emph_free_item(item); - return NULL; -} - -static struct _EConfigHookGroup * -emph_construct_menu(EPluginHook *eph, xmlNodePtr root) -{ - struct _EConfigHookGroup *menu; - xmlNodePtr node; - EConfigHookTargetMap *map; - EConfigHookClass *klass = (EConfigHookClass *)G_OBJECT_GET_CLASS(eph); - char *tmp; - - d(printf(" loading menu\n")); - menu = g_malloc0(sizeof(*menu)); - - tmp = xmlGetProp(root, "target"); - if (tmp == NULL) - goto error; - map = g_hash_table_lookup(klass->target_map, tmp); - xmlFree(tmp); - if (map == NULL) - goto error; - - menu->target_type = map->id; - menu->id = e_plugin_xml_prop(root, "id"); - if (menu->id == NULL) { - g_warning("Plugin '%s' missing 'id' field in group for '%s'\n", eph->plugin->name, - ((EPluginHookClass *)G_OBJECT_GET_CLASS(eph))->id); - goto error; - } - menu->check = e_plugin_xml_prop(root, "check"); - menu->commit = e_plugin_xml_prop(root, "commit"); - menu->abort = e_plugin_xml_prop(root, "abort"); - menu->hook = (EConfigHook *)eph; - node = root->children; - while (node) { - if (0 == strcmp(node->name, "item")) { - struct _EConfigItem *item; - - item = emph_construct_item(eph, menu, node, map); - if (item) - menu->items = g_slist_append(menu->items, item); - } - node = node->next; - } - - return menu; -error: - emph_free_group(menu); - return NULL; -} - -static int -emph_construct(EPluginHook *eph, EPlugin *ep, xmlNodePtr root) -{ - xmlNodePtr node; - EConfigClass *klass; - - d(printf("loading config hook\n")); - - if (((EPluginHookClass *)emph_parent_class)->construct(eph, ep, root) == -1) - return -1; - - klass = ((EConfigHookClass *)G_OBJECT_GET_CLASS(eph))->config_class; - - node = root->children; - while (node) { - if (strcmp(node->name, "group") == 0) { - struct _EConfigHookGroup *group; - - group = emph_construct_menu(eph, node); - if (group) { - e_config_class_add_factory(klass, group->id, ech_config_factory, group); - emph->groups = g_slist_append(emph->groups, group); - } - } - node = node->next; - } - - eph->plugin = ep; - - return 0; -} - -static void -emph_finalise(GObject *o) -{ - EPluginHook *eph = (EPluginHook *)o; - - g_slist_foreach(emph->groups, (GFunc)emph_free_group, NULL); - g_slist_free(emph->groups); - - ((GObjectClass *)emph_parent_class)->finalize(o); -} - -static void -emph_class_init(EPluginHookClass *klass) -{ - ((GObjectClass *)klass)->finalize = emph_finalise; - klass->construct = emph_construct; - - /* this is actually an abstract implementation but list it anyway */ - klass->id = "org.gnome.evolution.config:1.0"; - - d(printf("EConfigHook: init class %p '%s'\n", klass, g_type_name(((GObjectClass *)klass)->g_type_class.g_type))); - - ((EConfigHookClass *)klass)->target_map = g_hash_table_new(g_str_hash, g_str_equal); - ((EConfigHookClass *)klass)->config_class = g_type_class_ref(e_config_get_type()); -} - -/** - * e_config_hook_get_type: - * - * Standard GObject function to get the object type. - * - * Return value: The EConfigHook class type. - **/ -GType -e_config_hook_get_type(void) -{ - static GType type = 0; - - if (!type) { - static const GTypeInfo info = { - sizeof(EConfigHookClass), NULL, NULL, (GClassInitFunc) emph_class_init, NULL, NULL, - sizeof(EConfigHook), 0, (GInstanceInitFunc) NULL, - }; - - emph_parent_class = g_type_class_ref(e_plugin_hook_get_type()); - type = g_type_register_static(e_plugin_hook_get_type(), "EConfigHook", &info, 0); - } - - return type; -} - -/** - * e_config_hook_class_add_target_map: - * - * @klass: The dervied EconfigHook class. - * @map: A map used to describe a single EConfigTarget type for this - * class. - * - * Add a targe tmap to a concrete derived class of EConfig. The - * target map enumates the target types available for the implenting - * class. - **/ -void e_config_hook_class_add_target_map(EConfigHookClass *klass, const EConfigHookTargetMap *map) -{ - g_hash_table_insert(klass->target_map, (void *)map->type, (void *)map); -} |