From 286555acc6754954dc1094ba7169f8432ed1c7e0 Mon Sep 17 00:00:00 2001 From: Juan Pablo Ugarte Date: Mon, 17 Aug 2020 19:08:46 -0300 Subject: GladeCatalog: Load templates from extra catalog paths. Load template files as new GObject types and add them to "User templates" widget group. --- gladeui/glade-catalog.c | 88 +++++++++++++++++++++++ gladeui/glade-private.h | 17 ++++- gladeui/glade-template.c | 154 +++++++++++++++++++++++++++++------------ gladeui/glade-utils.c | 20 +++--- gladeui/glade-widget-adaptor.c | 30 +++++++- 5 files changed, 250 insertions(+), 59 deletions(-) (limited to 'gladeui') diff --git a/gladeui/glade-catalog.c b/gladeui/glade-catalog.c index c629cc1c..6b34d2ed 100644 --- a/gladeui/glade-catalog.c +++ b/gladeui/glade-catalog.c @@ -607,6 +607,91 @@ glade_catalog_get_extra_paths (void) return catalog_paths; } +static void +load_templates_from_path (GladeCatalog *catalog, + GladeWidgetGroup *group, + const gchar *path) +{ + GError *error = NULL; + GDir *dir; + + if (!g_file_test (path, G_FILE_TEST_IS_DIR)) + return; + + if ((dir = g_dir_open (path, 0, &error)) != NULL) + { + const gchar *filename; + GladeXmlNode *class_node = glade_xml_node_new (catalog->context, + GLADE_TAG_GLADE_WIDGET_CLASS); + + while ((filename = g_dir_read_name (dir))) + { + g_autofree gchar *tmpl_type = NULL, *tmpl_parent = NULL; + g_autofree gchar *abs_filename = NULL, *generic_name = NULL; + GladeWidgetAdaptor *adaptor; + + if (!g_str_has_suffix (filename, ".ui") && + !g_str_has_suffix (filename, ".glade")) + continue; + + /* Allways use absolute paths */ + if (g_path_is_absolute (filename)) + abs_filename = g_strdup (filename); + else + abs_filename = g_build_filename (path, filename, NULL); + + /* Load template and parse type and parent */ + if (!_glade_template_load (abs_filename, &tmpl_type, &tmpl_parent)) + continue; + + /* Add data to class_node */ + generic_name = g_ascii_strdown (tmpl_type, -1); + glade_xml_node_set_property_string (class_node, GLADE_TAG_NAME, tmpl_type); + glade_xml_node_set_property_string (class_node, GLADE_XML_TAG_TEMPLATE, abs_filename); + glade_xml_node_set_property_string (class_node, GLADE_TAG_TITLE, tmpl_type); + glade_xml_node_set_property_string (class_node, GLADE_TAG_GENERIC_NAME, generic_name); + + /* Load from fake catalog */ + adaptor = glade_widget_adaptor_from_catalog (catalog, class_node, NULL); + + /* Append adaptor to catalog */ + catalog->adaptors = g_list_prepend (catalog->adaptors, adaptor); + + /* And group */ + group->adaptors = g_list_prepend (group->adaptors, adaptor); + } + + g_dir_close (dir); + } +} + +static GList * +load_user_templates_catalog (GList *catalogs) +{ + GladeWidgetGroup *group; + GladeCatalog *catalog; + GList *l; + + /* Use just one group for all the adaptors */ + group = g_slice_new0 (GladeWidgetGroup); + group->name = g_strdup ("user-templates"); + group->title = g_strdup (_("User templates")); + group->expanded = FALSE; + + /* Create a runtime catalog for user templates */ + catalog = catalog_allocate (); + catalog->context = glade_xml_context_new (glade_xml_doc_new (), NULL); + catalog->name = g_strdup( "user-templates"); + catalog->widget_groups = g_list_prepend (NULL, group); + + /* Load templates from extra catalog paths */ + for (l = catalog_paths; l; l = g_list_next (l)) + load_templates_from_path (catalog, group, l->data); + + /* Prepend instead of append to give priority over other catalogs */ + return g_list_prepend (catalogs, catalog); +} + /** * glade_catalog_load_all: * @@ -694,6 +779,9 @@ glade_catalog_load_all (void) g_list_free (adaptors); + /* Load User defined templates */ + catalogs = load_user_templates_catalog (catalogs); + if (icon_warning) { g_message ("%s", icon_warning->str); diff --git a/gladeui/glade-private.h b/gladeui/glade-private.h index 016184c0..a5c744ef 100644 --- a/gladeui/glade-private.h +++ b/gladeui/glade-private.h @@ -87,6 +87,8 @@ _glade_property_def_reset_version (GladePropertyDef *property_def); /* glade-utils.c */ +gchar *_glade_util_compose_get_type_func (const gchar *name); + void _glade_util_dialog_set_hig (GtkDialog *dialog); gchar *_glade_util_strreplace (gchar *str, @@ -104,9 +106,18 @@ void _glade_xml_error_reset_last (void); gchar *_glade_xml_error_get_last_message (void); /* glade-template.c */ -GType _glade_template_generate_type_from_file (GladeCatalog *catalog, - const gchar *parent, - const gchar *filename); +gchar *_glade_template_load (const gchar *filename, + gchar **type, + gchar **parent); + +gboolean _glade_template_parse (const gchar *tmpl, + gchar **type, + gchar **parent); + +GType _glade_template_generate_type (const gchar *type, + const gchar *parent); + +const gchar *_glade_template_lookup (const gchar *type); G_END_DECLS diff --git a/gladeui/glade-template.c b/gladeui/glade-template.c index 067eeedb..b5248ecb 100644 --- a/gladeui/glade-template.c +++ b/gladeui/glade-template.c @@ -1,7 +1,7 @@ /* * glade-template.c: * - * Copyright (C) 2017-2018 Juan Pablo Ugarte. + * Copyright (C) 2017-2020 Juan Pablo Ugarte. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as @@ -72,74 +72,140 @@ start_element (GMarkupParseContext *context, data->parent = g_strdup (attribute_values[i]); } -GType -_glade_template_generate_type_from_file (GladeCatalog *catalog, - const gchar *name, - const gchar *filename) +gboolean +_glade_template_parse (const gchar *tmpl, gchar **type, gchar **parent) { GMarkupParser parser = { start_element, NULL, }; GMarkupParseContext *context; ParserData data = { 0, }; - GType parent_type; - GTypeQuery query; - GTypeInfo *info; - gchar *template = NULL; - gsize len = 0; - GError *error = NULL; - g_return_val_if_fail (name != NULL, 0); - g_return_val_if_fail (filename != NULL, 0); + context = g_markup_parse_context_new (&parser, 0, &data, NULL); + + g_markup_parse_context_parse (context, tmpl, -1, NULL); - if (g_path_is_absolute (filename)) - g_file_get_contents (filename, &template, &len, &error); - else + /* + while (g_markup_parse_context_parse (context, tmpl, 128, NULL) && + (data.class == NULL || data.parent == NULL)) + tmpl += 128; +*/ + + g_markup_parse_context_end_parse (context, NULL); + + if (data.class && data.parent) { - gchar *fullpath = g_build_filename (glade_catalog_get_prefix (catalog), - filename, NULL); - g_file_get_contents (fullpath, &template, &len, &error); - g_free (fullpath); + *type = data.class; + *parent = data.parent; + + return TRUE; } - if (error) + g_free (data.class); + g_free (data.parent); + + return FALSE; +} + +static GType +get_type_from_name (const gchar *name) +{ + g_autofree gchar *func_name = NULL; + static GModule *allsymbols = NULL; + GType (*get_type) (void); + GType type = 0; + + if (g_once_init_enter (&allsymbols)) { - g_warning ("Error loading template file %s for %s class - %s", filename, name, error->message); - return G_TYPE_INVALID; + GModule *symbols = g_module_open (NULL, 0); + g_once_init_leave (&allsymbols, symbols); } - context = g_markup_parse_context_new (&parser, 0, &data, NULL); - g_markup_parse_context_parse (context, template, -1, NULL); - g_markup_parse_context_end_parse (context, NULL); - - if (!g_str_equal (name, data.class)) + if ((type = g_type_from_name (name)) == 0 && + ((func_name = _glade_util_compose_get_type_func (name)) != NULL)) { - g_warning ("Template %s is for class %s, not %s", filename, data.class, name); - return G_TYPE_INVALID; + if (g_module_symbol (allsymbols, func_name, (gpointer) & get_type)) + { + g_assert (get_type); + type = get_type (); + } } - parent_type = glade_util_get_type_from_name (data.parent, FALSE); - g_return_val_if_fail (parent_type != 0, 0); + return type; +} - g_type_query (parent_type, &query); - g_return_val_if_fail (query.type != 0, 0); +gchar * +_glade_template_load (const gchar *filename, gchar **type, gchar **parent) +{ + g_autoptr(GError) error = NULL; + gchar *template = NULL; + gsize len = 0; + + g_return_val_if_fail (filename != NULL, NULL); + + g_file_get_contents (filename, &template, &len, &error); + + if (error) + g_warning ("Error loading template file %s - %s", filename, error->message); - if (g_once_init_enter (&templates)) + if (!template || !_glade_template_parse (template, type, parent)) + *type = *parent = NULL; + else { - GHashTable *table = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) g_bytes_unref); - g_once_init_leave (&templates, table); + GType tmpl_type = get_type_from_name (*type); + + /* Type is already registered, do not try to load it as a template */ + if (tmpl_type != G_TYPE_INVALID) + { + g_clear_pointer (type, g_free); + g_clear_pointer (parent, g_free); + g_free (template); + return NULL; + } + + if (g_once_init_enter (&templates)) + { + GHashTable *table = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_bytes_unref); + g_once_init_leave (&templates, table); + } + + /* Add template to global hash table */ + g_hash_table_insert (templates, + g_strdup (*type), + g_bytes_new_take (template, len)); } - /* Add template to global hash table */ - g_hash_table_insert (templates, g_strdup (name), g_bytes_new_take (template, len)); + return template; +} + +GType +_glade_template_generate_type (const gchar *type, const gchar *parent) +{ + GType parent_type; + GTypeQuery query; + GTypeInfo *info; + + /* make sure the template is loaded */ + g_return_val_if_fail (g_hash_table_lookup (templates, type) != NULL, G_TYPE_INVALID); + + parent_type = glade_util_get_type_from_name (parent, FALSE); + g_return_val_if_fail (parent_type != 0, 0); + + g_type_query (parent_type, &query); + g_return_val_if_fail (query.type != 0, 0); info = g_new0 (GTypeInfo, 1); info->class_size = query.class_size; info->instance_size = query.instance_size; info->instance_init = glade_template_instance_init; - g_free (data.class); - g_free (data.parent); + return g_type_register_static (parent_type, type, info, 0); +} - return g_type_register_static (parent_type, name, info, 0); +const gchar * +_glade_template_lookup (const gchar *type) +{ + GBytes *tmpl = g_hash_table_lookup (templates, type); + return (tmpl) ? g_bytes_get_data (tmpl, NULL) : ""; } + diff --git a/gladeui/glade-utils.c b/gladeui/glade-utils.c index e7d91636..904e3ebb 100644 --- a/gladeui/glade-utils.c +++ b/gladeui/glade-utils.c @@ -65,8 +65,8 @@ * * Returns: the type function getter */ -static gchar * -glade_util_compose_get_type_func (const gchar *name) +gchar * +_glade_util_compose_get_type_func (const gchar *name) { gchar *retval; GString *tmp; @@ -118,23 +118,23 @@ glade_util_get_type_from_name (const gchar *name, gboolean have_func) GType type = 0; gchar *func_name = (gchar *) name; + if (g_once_init_enter (&allsymbols)) + { + GModule *symbols = g_module_open (NULL, 0); + g_once_init_leave (&allsymbols, symbols); + } + if ((type = g_type_from_name (name)) == 0 && (have_func || - (func_name = glade_util_compose_get_type_func (name)) != NULL)) + (func_name = _glade_util_compose_get_type_func (name)) != NULL)) { - - if (!allsymbols) - allsymbols = g_module_open (NULL, 0); - if (g_module_symbol (allsymbols, func_name, (gpointer) & get_type)) { g_assert (get_type); type = get_type (); } else - { - g_warning (_("We could not find the symbol \"%s\""), func_name); - } + g_warning (_("We could not find the symbol \"%s\""), func_name); if (!have_func) g_free (func_name); diff --git a/gladeui/glade-widget-adaptor.c b/gladeui/glade-widget-adaptor.c index f26f3914..7cbe3b41 100644 --- a/gladeui/glade-widget-adaptor.c +++ b/gladeui/glade-widget-adaptor.c @@ -2761,7 +2761,9 @@ glade_widget_adaptor_from_catalog (GladeCatalog *catalog, gchar *name, *generic_name, *icon_name, *adaptor_icon_name, *adaptor_name, *func_name = NULL, *template; gchar *title, *translated_title, *parent_name; - GType object_type, adaptor_type, parent_type; + GType object_type = G_TYPE_INVALID; + GType adaptor_type = G_TYPE_INVALID; + GType parent_type = G_TYPE_INVALID; gchar *missing_icon = NULL; GWADerivedClassData data; @@ -2808,7 +2810,31 @@ glade_widget_adaptor_from_catalog (GladeCatalog *catalog, glade_xml_get_property_string (class_node, GLADE_XML_TAG_TEMPLATE)) != NULL) { - object_type = _glade_template_generate_type_from_file (catalog, name, template); + g_autofree gchar *tmpl_type = NULL, *tmpl_parent = NULL; + const gchar *tmpl = NULL; + + if ((tmpl = _glade_template_lookup (name))) + _glade_template_parse (tmpl, &tmpl_type, &tmpl_parent); + else + { + if (g_path_is_absolute (template)) + tmpl = _glade_template_load (template, &tmpl_type, &tmpl_parent); + else + { + const gchar *prefix = glade_catalog_get_prefix (catalog); + g_autofree gchar *fullpath = g_build_filename (prefix, template, NULL); + tmpl = _glade_template_load (fullpath, &tmpl_type, &tmpl_parent); + } + } + + if (tmpl && tmpl_type && tmpl_parent) + { + if (g_str_equal (name, tmpl_type)) + object_type = _glade_template_generate_type (tmpl_type, tmpl_parent); + else + g_warning ("Template %s is for class %s, not %s", template, tmpl_type, name); + } + g_free (template); } else -- cgit v1.2.1