summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuan Pablo Ugarte <juanpablougarte@gmail.com>2020-08-17 19:08:46 -0300
committerJuan Pablo Ugarte <juanpablougarte@gmail.com>2020-08-17 19:19:48 -0300
commit286555acc6754954dc1094ba7169f8432ed1c7e0 (patch)
treea635c43c3965fade465d6cc72dc3620d65b92319
parent80de73f0b4d904e77164399811a5d7da7ecf47f3 (diff)
downloadglade-286555acc6754954dc1094ba7169f8432ed1c7e0.tar.gz
GladeCatalog: Load templates from extra catalog paths.
Load template files as new GObject types and add them to "User templates" widget group.
-rw-r--r--gladeui/glade-catalog.c88
-rw-r--r--gladeui/glade-private.h17
-rw-r--r--gladeui/glade-template.c154
-rw-r--r--gladeui/glade-utils.c20
-rw-r--r--gladeui/glade-widget-adaptor.c30
5 files changed, 250 insertions, 59 deletions
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