summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuan Pablo Ugarte <juanpablougarte@gmai.com>2013-01-31 17:15:01 +0100
committerJuan Pablo Ugarte <juanpablougarte@gmai.com>2013-01-31 17:15:01 +0100
commit6552f5f48d02bfab7e7624970c3dd623511dabea (patch)
tree6ef498b7c26dc43d2fd494b5f3e85bc010cc72c3
parente12f3a4ad551591e7de6805c2da13eb7088bc2f3 (diff)
downloadglade-6552f5f48d02bfab7e7624970c3dd623511dabea.tar.gz
Revert "Reverting all composite templates support until it lands on GTK"
This reverts commit e12f3a4ad551591e7de6805c2da13eb7088bc2f3.
-rw-r--r--configure.ac2
-rw-r--r--gladeui/Makefile.am2
-rw-r--r--gladeui/glade-app.c3
-rw-r--r--gladeui/glade-composite-template.c310
-rw-r--r--gladeui/glade-composite-template.h43
-rw-r--r--gladeui/glade-editor-table.c176
-rw-r--r--gladeui/glade-palette.c65
-rw-r--r--gladeui/glade-project.c41
-rw-r--r--gladeui/glade-project.h1
-rw-r--r--gladeui/glade-property.c5
-rw-r--r--gladeui/glade-widget-adaptor.c271
-rw-r--r--gladeui/glade-widget-adaptor.h22
-rw-r--r--gladeui/glade-widget.c83
-rw-r--r--gladeui/glade-widget.h5
-rw-r--r--gladeui/glade-xml-utils.h2
-rw-r--r--gladeui/glade.h1
-rw-r--r--plugins/gtk+/glade-gtk.c200
-rw-r--r--plugins/gtk+/gtk+.xml.in14
18 files changed, 1048 insertions, 198 deletions
diff --git a/configure.ac b/configure.ac
index 78118035..3b1bf654 100644
--- a/configure.ac
+++ b/configure.ac
@@ -254,7 +254,7 @@ dnl ================================================================
dnl Check for extra functions
dnl ================================================================
AC_CHECK_FUNCS(gtk_builder_add_from_resource)
-
+AC_CHECK_FUNCS(gtk_container_class_set_template_from_string)
AC_SUBST([GLADE_PREFIX])
diff --git a/gladeui/Makefile.am b/gladeui/Makefile.am
index 141aaed8..288848d6 100644
--- a/gladeui/Makefile.am
+++ b/gladeui/Makefile.am
@@ -53,6 +53,7 @@ libgladeui_2_la_SOURCES = \
glade-object-stub.c \
glade-xml-utils.c \
glade-catalog.c \
+ glade-composite-template.c \
glade-widget-adaptor.c \
glade-widget.c \
glade-property-class.c \
@@ -122,6 +123,7 @@ libgladeuiinclude_HEADERS = \
glade-design-view.h \
glade-widget.h \
glade-widget-adaptor.h \
+ glade-composite-template.h \
glade-property.h \
glade-property-class.h \
glade-utils.h \
diff --git a/gladeui/glade-app.c b/gladeui/glade-app.c
index ccff86a9..402c5663 100644
--- a/gladeui/glade-app.c
+++ b/gladeui/glade-app.c
@@ -39,6 +39,7 @@
#include "glade-design-layout.h"
#include "glade-marshallers.h"
#include "glade-accumulators.h"
+#include "glade-composite-template.h"
#include <string.h>
#include <glib.h>
@@ -349,6 +350,8 @@ glade_app_init (GladeApp *app)
/* Load the configuration file */
priv->config = g_key_file_ref (glade_app_get_config ());
+
+ glade_composite_template_load_directory (g_get_user_special_dir (G_USER_DIRECTORY_TEMPLATES));
}
static void
diff --git a/gladeui/glade-composite-template.c b/gladeui/glade-composite-template.c
new file mode 100644
index 00000000..81ede79a
--- /dev/null
+++ b/gladeui/glade-composite-template.c
@@ -0,0 +1,310 @@
+/*
+ * glade-composite-template.c
+ *
+ * Copyright (C) 2012 Juan Pablo Ugarte
+ *
+ * Author: Juan Pablo Ugarte <juanpablougarte@gmail.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <config.h>
+
+#include <glib/gi18n-lib.h>
+#include "glade-composite-template.h"
+#include "glade-app.h"
+#include "glade-utils.h"
+
+typedef struct
+{
+ gboolean right_id;
+ GType parent;
+ const gchar *type_name;
+} ParseData;
+
+static void
+start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error)
+{
+ ParseData *state = user_data;
+
+ if (g_strcmp0 (element_name, "template") == 0)
+ {
+ gint i;
+
+ for (i = 0; attribute_names[i]; i++)
+ {
+ if (!g_strcmp0 (attribute_names[i], "parent"))
+ state->parent = glade_util_get_type_from_name (attribute_values[i], FALSE);
+ else if (!g_strcmp0 (attribute_names[i], "class"))
+ state->type_name = g_intern_string (attribute_values[i]);
+ else if (!g_strcmp0 (attribute_names[i], "id"))
+ state->right_id = (g_strcmp0 (attribute_values[i], "this") == 0);
+ }
+ }
+}
+
+static gboolean
+parse_template (const gchar *template_str, GType *parent, const gchar **type_name)
+{
+ GMarkupParser parser = { start_element };
+ ParseData state = { FALSE, G_TYPE_INVALID, NULL };
+ GMarkupParseContext *context;
+
+ context = g_markup_parse_context_new (&parser,
+ G_MARKUP_TREAT_CDATA_AS_TEXT |
+ G_MARKUP_PREFIX_ERROR_POSITION,
+ &state, NULL);
+
+ g_markup_parse_context_parse (context, template_str, -1, NULL);
+ g_markup_parse_context_end_parse (context, NULL);
+ g_markup_parse_context_free (context);
+
+ if (!g_type_is_a (state.parent, GTK_TYPE_CONTAINER))
+ {
+ g_warning ("Composite templates should derive from GtkContainer");
+ return FALSE;
+ }
+
+ if (parent) *parent = state.parent;
+ if (type_name) *type_name = state.type_name;
+
+ return state.right_id;
+}
+
+static void
+composite_template_derived_init (GTypeInstance *instance, gpointer g_class)
+{
+}
+
+#if !HAVE_GTK_CONTAINER_CLASS_SET_TEMPLATE_FROM_STRING
+static GObject *
+composite_template_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GladeWidgetAdaptor *adaptor;
+ GObjectClass *parent_class;
+ GObject *obj;
+
+ parent_class = g_type_class_peek (g_type_parent (type));
+ obj = parent_class->constructor (type,
+ n_construct_properties,
+ construct_properties);
+/*
+ adaptor = glade_widget_adaptor_get_by_type (type);
+
+
+ glade_widget_adaptor_get_*/
+ return obj;
+}
+#endif
+
+static void
+composite_template_derived_class_init (gpointer g_class, gpointer class_data)
+{
+#if !HAVE_GTK_CONTAINER_CLASS_SET_TEMPLATE_FROM_STRING
+ GObjectClass *object_class = g_class;
+ object_class->constructor = composite_template_constructor;
+#endif
+}
+
+static inline GType
+generate_type (GType parent, const gchar *type_name)
+{
+ GTypeQuery query;
+
+ g_type_query (parent, &query);
+
+ return g_type_register_static_simple (parent, type_name,
+ query.class_size,
+ composite_template_derived_class_init,
+ query.instance_size,
+ composite_template_derived_init,
+ 0);
+}
+
+/* Public API */
+
+/**
+ * glade_composite_template_load_from_string:
+ * @template_xml: a #GtkBuilder UI description string
+ *
+ * This function will create a new GType from the template UI description defined
+ * by @template_xml and its corresponding #GladeWidgetAdator
+ *
+ * Returns: A newlly created and registered #GladeWidgetAdptor or NULL if @template_xml is malformed.
+ */
+GladeWidgetAdaptor *
+glade_composite_template_load_from_string (const gchar *template_xml)
+{
+ const gchar *type_name = NULL;
+ GType parent;
+
+ g_return_val_if_fail (template_xml != NULL, NULL);
+
+ if (parse_template (template_xml, &parent, &type_name))
+ {
+ GladeWidgetAdaptor *adaptor;
+ GType template_type;
+
+ /* Generate dummy template type */
+ template_type = generate_type (parent, type_name);
+
+ /* Create adaptor for template */
+ adaptor = glade_widget_adaptor_from_composite_template (template_type,
+ template_xml,
+ type_name,
+ NULL); /* TODO: generate icon name from parent icon plus some emblem */
+ /* Register adaptor */
+ glade_widget_adaptor_register (adaptor);
+
+ return adaptor;
+ }
+ else
+ g_warning ("Could not parse template");
+
+ return NULL;
+}
+
+/**
+ * glade_composite_template_load_from_file:
+ * @path: a filename to load
+ *
+ * Loads a composite template from a file.
+ * See glade_composite_template_load_from_string() for details.
+ *
+ * Returns: A newlly created and registered #GladeWidgetAdaptor or NULL.
+ */
+GladeWidgetAdaptor *
+glade_composite_template_load_from_file (const gchar *path)
+{
+ GladeWidgetAdaptor *adaptor;
+ GError *error = NULL;
+ gchar *contents;
+
+ g_return_val_if_fail (path != NULL, NULL);
+
+ if (!g_file_get_contents (path, &contents, NULL, &error))
+ {
+ g_warning ("Could not load template `%s` %s", path, error->message);
+ g_error_free (error);
+ return NULL;
+ }
+
+ if ((adaptor = glade_composite_template_load_from_string (contents)))
+ g_object_set (adaptor, "template-path", path, NULL);
+
+ g_free (contents);
+
+ return adaptor;
+}
+
+/**
+ * glade_composite_template_load_directory:
+ * @directory: a directory path.
+ *
+ * Loads every .ui composite template found in @directory
+ */
+void
+glade_composite_template_load_directory (const gchar *directory)
+{
+ GError *error = NULL;
+ const gchar *name;
+ GDir *dir;
+
+ g_return_if_fail (directory != NULL);
+
+ if (!(dir = g_dir_open (directory, 0, &error)))
+ {
+ g_warning ("Could not open directory `%s` %s", directory, error->message);
+ g_error_free (error);
+ return;
+ }
+
+ while ((name = g_dir_read_name (dir)))
+ {
+ if (g_str_has_suffix (name, ".ui"))
+ {
+ gchar *fullname = g_build_filename (directory, name, NULL);
+ glade_composite_template_load_from_file (fullname);
+ g_free (fullname);
+ }
+ }
+
+ g_dir_close (dir);
+}
+
+/**
+ * glade_composite_template_save_from_widget:
+ * @gwidget: a #GladeWidget
+ * @template_class: the name of the new composite template class
+ * @filename: a file name to save the template
+ * @replace: True if you want to replace @gwidget with a new widget of type @template_class
+ *
+ * Saves a copy of @gwidget as a composite template in @filename with @template_class
+ * as the class name
+ */
+void
+glade_composite_template_save_from_widget (GladeWidget *gwidget,
+ const gchar *template_class,
+ const gchar *filename,
+ gboolean replace)
+{
+ GladeProject *project;
+ gchar *template_xml;
+ GladeWidget *dup;
+
+ g_return_if_fail (GLADE_IS_WIDGET (gwidget));
+ g_return_if_fail (template_class && filename);
+ g_return_if_fail (GTK_IS_CONTAINER (glade_widget_get_object (gwidget)));
+
+ project = glade_project_new ();
+ dup = glade_widget_dup (gwidget, TRUE);
+
+ /* make dupped widget a template */
+ glade_widget_set_name (dup, "this");
+ glade_widget_set_template_class (dup, template_class);
+
+ glade_project_add_object (project, glade_widget_get_object (dup));
+ template_xml = glade_project_dump_string (project);
+
+ g_file_set_contents (filename, template_xml, -1, NULL);
+
+ if (replace)
+ {
+ GladeProject *project = glade_widget_get_project (gwidget);
+ GladeWidget *parent = glade_widget_get_parent (gwidget);
+ GladeWidgetAdaptor *new_adaptor;
+ GList widgets = {0, };
+
+ /* Create it at run time */
+ if ((new_adaptor = glade_composite_template_load_from_string (template_xml)))
+ g_object_set (new_adaptor, "template-path", filename, NULL);
+
+ glade_command_push_group (_("Create new composite type %s"), template_class);
+ widgets.data = gwidget;
+ glade_command_cut (&widgets);
+ glade_command_create (new_adaptor, parent, NULL, project);
+ glade_command_pop_group ();
+ }
+
+ g_free (template_xml);
+ g_object_unref (project);
+}
diff --git a/gladeui/glade-composite-template.h b/gladeui/glade-composite-template.h
new file mode 100644
index 00000000..46a2373d
--- /dev/null
+++ b/gladeui/glade-composite-template.h
@@ -0,0 +1,43 @@
+/*
+ * glade-composite-template.h
+ *
+ * Copyright (C) 2012 Juan Pablo Ugarte
+ *
+ * Author: Juan Pablo Ugarte <juanpablougarte@gmail.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GLADE_COMPOSITE_TEMPLATE_H__
+#define __GLADE_COMPOSITE_TEMPLATE_H__
+
+#include <gladeui/glade-widget.h>
+
+G_BEGIN_DECLS
+
+GladeWidgetAdaptor *glade_composite_template_load_from_string (const gchar *template_xml);
+
+GladeWidgetAdaptor *glade_composite_template_load_from_file (const gchar *path);
+
+void glade_composite_template_load_directory (const gchar *directory);
+
+void glade_composite_template_save_from_widget (GladeWidget *gwidget,
+ const gchar *template_class,
+ const gchar *filename,
+ gboolean replace);
+
+G_END_DECLS
+
+#endif /* __GLADE_COMPOSITE_TEMPLATE_H__ */
diff --git a/gladeui/glade-editor-table.c b/gladeui/glade-editor-table.c
index 101bc0a2..a82a29c5 100644
--- a/gladeui/glade-editor-table.c
+++ b/gladeui/glade-editor-table.c
@@ -49,6 +49,8 @@ struct _GladeEditorTablePrivate
* entry which will not be created from a
* GladeProperty but rather from code.
*/
+ GtkWidget *tmpl_label;
+ GtkWidget *tmpl_entry;
GList *properties; /* A list of GladeEditorPropery items.
* For each row in the gtk_table, there is a
@@ -205,58 +207,122 @@ widget_finalized (GladeEditorTable * table, GladeWidget * where_widget_was)
glade_editable_load (GLADE_EDITABLE (table), NULL);
}
+static void
+glade_editor_table_update_show_template (GladeEditable *editable, gboolean load)
+{
+ GladeEditorTable *table = GLADE_EDITOR_TABLE (editable);
+ GladeEditorTablePrivate *priv = table->priv;
+ GladeWidget *widget = priv->loaded_widget;
+ const gchar *tooltip = NULL;
+ GtkEntry *entry;
+
+ if (!priv->name_entry || !priv->tmpl_entry) return;
+
+ entry = GTK_ENTRY (priv->name_entry);
+
+ if (load) gtk_editable_set_editable (GTK_EDITABLE (priv->name_entry), TRUE);
+
+ if (widget)
+ {
+ if (!glade_widget_get_parent (widget))
+ {
+ GladeProject *project;
+ if (glade_widget_get_template_class (widget))
+ {
+ if (load) gtk_editable_set_editable (GTK_EDITABLE (priv->name_entry), FALSE);
+ gtk_entry_set_icon_from_stock (entry, GTK_ENTRY_ICON_SECONDARY, "gtk-delete");
+ tooltip = _("Click to disable template class");
+ }
+ else if (!g_strcmp0 (glade_widget_get_name (widget), "this") ||
+ ((project = glade_widget_get_project (widget)) &&
+ glade_project_available_widget_name (project, widget, "this")))
+ {
+ gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY, "glade");
+ tooltip = _("Click to make this widget a template class (It will be renamed to 'this')");
+ }
+ else
+ gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY, NULL);
+ }
+ else
+ gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY, NULL);
+ }
+ else
+ {
+ gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY, NULL);
+ gtk_widget_hide (priv->tmpl_label);
+ gtk_widget_hide (priv->tmpl_entry);
+ }
+
+ if (gtk_editable_get_editable (GTK_EDITABLE (priv->name_entry)))
+ {
+ gtk_widget_hide (priv->tmpl_label);
+ gtk_widget_hide (priv->tmpl_entry);
+ }
+ else
+ {
+ gtk_widget_show (priv->tmpl_label);
+ gtk_widget_show (priv->tmpl_entry);
+ }
+
+ gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY, tooltip);
+}
static void
glade_editor_table_load (GladeEditable * editable, GladeWidget * widget)
{
GladeEditorTable *table = GLADE_EDITOR_TABLE (editable);
+ GladeEditorTablePrivate *priv = table->priv;
GladeEditorProperty *property;
GList *list;
/* abort mission */
- if (table->priv->loaded_widget == widget)
+ if (priv->loaded_widget == widget)
return;
- if (table->priv->loaded_widget)
+ if (priv->loaded_widget)
{
- g_signal_handlers_disconnect_by_func (G_OBJECT (table->priv->loaded_widget),
+ g_signal_handlers_disconnect_by_func (G_OBJECT (priv->loaded_widget),
G_CALLBACK (widget_name_changed),
table);
/* The widget could die unexpectedly... */
- g_object_weak_unref (G_OBJECT (table->priv->loaded_widget),
+ g_object_weak_unref (G_OBJECT (priv->loaded_widget),
(GWeakNotify) widget_finalized, table);
}
- table->priv->loaded_widget = widget;
+ priv->loaded_widget = widget;
BLOCK_NAME_ENTRY_CB (table);
- if (table->priv->loaded_widget)
+ if (priv->loaded_widget)
{
- g_signal_connect (G_OBJECT (table->priv->loaded_widget), "notify::name",
+ g_signal_connect (G_OBJECT (priv->loaded_widget), "notify::name",
G_CALLBACK (widget_name_changed), table);
/* The widget could die unexpectedly... */
- g_object_weak_ref (G_OBJECT (table->priv->loaded_widget),
+ g_object_weak_ref (G_OBJECT (priv->loaded_widget),
(GWeakNotify) widget_finalized, table);
- if (table->priv->name_entry)
- gtk_entry_set_text (GTK_ENTRY (table->priv->name_entry),
+ if (priv->name_entry)
+ gtk_entry_set_text (GTK_ENTRY (priv->name_entry),
glade_widget_get_name (widget));
}
- else if (table->priv->name_entry)
- gtk_entry_set_text (GTK_ENTRY (table->priv->name_entry), "");
+ else if (priv->name_entry)
+ gtk_entry_set_text (GTK_ENTRY (priv->name_entry), "");
UNBLOCK_NAME_ENTRY_CB (table);
/* Sync up properties, even if widget is NULL */
- for (list = table->priv->properties; list; list = list->next)
+ for (list = priv->properties; list; list = g_list_next (list))
{
property = list->data;
glade_editor_property_load_by_widget (property, widget);
}
+
+ if (priv->tmpl_entry)
+ glade_editor_property_load_by_widget (GLADE_EDITOR_PROPERTY (priv->tmpl_entry), widget);
+ glade_editor_table_update_show_template (editable, TRUE);
}
static void
@@ -403,32 +469,84 @@ append_items (GladeEditorTable * table,
}
static void
-append_name_field (GladeEditorTable * table)
+on_name_icon_press (GtkEntry *entry,
+ GtkEntryIconPosition icon_pos,
+ GdkEvent *event,
+ GladeEditorTable *table)
+{
+ GladeEditorTablePrivate *priv = table->priv;
+ gboolean editable;
+
+ if (!priv->loaded_widget || glade_widget_get_parent (priv->loaded_widget))
+ return;
+
+ if ((editable = gtk_editable_get_editable (GTK_EDITABLE (priv->name_entry))))
+ glade_command_set_name (priv->loaded_widget, "this");
+ else
+ {
+ GladeProperty *property = glade_widget_get_property (priv->loaded_widget, "glade-template-class");
+ glade_command_set_property (property, NULL);
+ }
+
+ gtk_editable_set_editable (GTK_EDITABLE (priv->name_entry), !editable);
+ glade_editor_table_update_show_template (GLADE_EDITABLE (table), FALSE);
+}
+
+static void
+append_name_field (GladeWidgetAdaptor *adaptor, GladeEditorTable *table)
{
+ GladeEditorTablePrivate *priv = table->priv;
gchar *text = _("The Object's name");
/* Name */
- table->priv->name_label = gtk_label_new (_("Name:"));
- gtk_misc_set_alignment (GTK_MISC (table->priv->name_label), 0.0, 0.5);
- gtk_widget_show (table->priv->name_label);
- gtk_widget_set_no_show_all (table->priv->name_label, TRUE);
+ priv->name_label = gtk_label_new (_("Name:"));
+ gtk_misc_set_alignment (GTK_MISC (priv->name_label), 0.0, 0.5);
+ gtk_widget_show (priv->name_label);
+ gtk_widget_set_no_show_all (priv->name_label, TRUE);
- table->priv->name_entry = gtk_entry_new ();
- gtk_widget_show (table->priv->name_entry);
- gtk_widget_set_no_show_all (table->priv->name_entry, TRUE);
+ priv->name_entry = gtk_entry_new ();
+ gtk_widget_show (priv->name_entry);
+ gtk_widget_set_no_show_all (priv->name_entry, TRUE);
- gtk_widget_set_tooltip_text (table->priv->name_label, text);
- gtk_widget_set_tooltip_text (table->priv->name_entry, text);
+ gtk_widget_set_tooltip_text (priv->name_label, text);
+ gtk_widget_set_tooltip_text (priv->name_entry, text);
- g_signal_connect (G_OBJECT (table->priv->name_entry), "activate",
+ g_signal_connect (G_OBJECT (priv->name_entry), "activate",
G_CALLBACK (widget_name_edited), table);
- g_signal_connect (G_OBJECT (table->priv->name_entry), "changed",
+ g_signal_connect (G_OBJECT (priv->name_entry), "changed",
G_CALLBACK (widget_name_edited), table);
- glade_editor_table_attach (table, table->priv->name_label, 0, table->priv->rows);
- glade_editor_table_attach (table, table->priv->name_entry, 1, table->priv->rows);
+ glade_editor_table_attach (table, priv->name_label, 0, priv->rows);
+ glade_editor_table_attach (table, priv->name_entry, 1, priv->rows);
- table->priv->rows++;
+ priv->rows++;
+
+ if (g_type_is_a (glade_widget_adaptor_get_object_type (adaptor), GTK_TYPE_CONTAINER))
+ {
+ gchar *class_text = _("The template class name this widget defines");
+
+ /* Template class */
+ priv->tmpl_label = gtk_label_new (_("Template Class:"));
+ gtk_misc_set_alignment (GTK_MISC (priv->tmpl_label), 0.0, 0.5);
+ gtk_widget_set_no_show_all (priv->tmpl_label, TRUE);
+
+ priv->tmpl_entry = GTK_WIDGET (glade_widget_adaptor_create_eprop_by_name (adaptor, "glade-template-class", FALSE, TRUE));
+ gtk_widget_hide (priv->tmpl_entry);
+ gtk_widget_set_no_show_all (priv->tmpl_entry, TRUE);
+ g_signal_connect (priv->name_entry, "icon-press", G_CALLBACK (on_name_icon_press), table);
+
+ gtk_widget_set_tooltip_text (priv->tmpl_label, class_text);
+ gtk_widget_set_tooltip_text (priv->tmpl_entry, class_text);
+
+ glade_editor_table_attach (table, priv->tmpl_label, 0, priv->rows);
+ glade_editor_table_attach (table, priv->tmpl_entry, 1, priv->rows);
+
+ priv->rows++;
+ }
+ else
+ {
+ priv->tmpl_label = priv->tmpl_entry = NULL;
+ }
}
/**
@@ -453,7 +571,7 @@ glade_editor_table_new (GladeWidgetAdaptor * adaptor, GladeEditorPageType type)
table->priv->type = type;
if (type == GLADE_PAGE_GENERAL)
- append_name_field (table);
+ append_name_field (adaptor, table);
append_items (table, adaptor, type);
diff --git a/gladeui/glade-palette.c b/gladeui/glade-palette.c
index e738a264..0fe5f3ff 100644
--- a/gladeui/glade-palette.c
+++ b/gladeui/glade-palette.c
@@ -69,6 +69,8 @@ struct _GladePalettePrivate
GladeWidgetAdaptor *local_selection;
GHashTable *button_table;
+
+ GtkWidget *composite_templates;
};
enum
@@ -336,13 +338,12 @@ glade_palette_new_item (GladePalette * palette, GladeWidgetAdaptor * adaptor)
}
static GtkWidget *
-glade_palette_new_item_group (GladePalette * palette, GladeWidgetGroup * group)
+tool_item_group_new (const gchar *name)
{
- GtkWidget *item_group, *item, *label;
- GList *l;
+ GtkWidget *item_group, *label;
/* Give the item group a left aligned label */
- label = gtk_label_new (glade_widget_group_get_title (group));
+ label = gtk_label_new (name);
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_widget_show (label);
@@ -354,6 +355,17 @@ glade_palette_new_item_group (GladePalette * palette, GladeWidgetGroup * group)
gtk_tool_item_group_set_ellipsize (GTK_TOOL_ITEM_GROUP (item_group),
PANGO_ELLIPSIZE_END);
+ return item_group;
+}
+
+static GtkWidget *
+glade_palette_new_item_group (GladePalette * palette, GladeWidgetGroup * group)
+{
+ GtkWidget *item_group, *item;
+ GList *l;
+
+ item_group = tool_item_group_new (glade_widget_group_get_title (group));
+
gtk_widget_set_tooltip_text (item_group,
glade_widget_group_get_title (group));
@@ -389,12 +401,53 @@ glade_palette_append_item_group (GladePalette * palette,
}
static void
+glade_palette_update_templates (GladePalette *palette)
+{
+ GList *l, *adaptors = glade_widget_adaptor_list_adaptors ();
+ GladePalettePrivate *priv = palette->priv;
+
+ if (priv->composite_templates == NULL)
+ {
+ priv->composite_templates = tool_item_group_new (_("Composite Templates"));
+ gtk_container_add (GTK_CONTAINER (priv->toolpalette), priv->composite_templates);
+ gtk_widget_show (priv->composite_templates);
+ }
+ else
+ {
+ GtkContainer *container = GTK_CONTAINER (priv->composite_templates);
+ GList *l, *children = gtk_container_get_children (container);
+
+ for (l = children; l; l = g_list_next (l))
+ gtk_container_remove (container, l->data);
+
+ g_list_free (children);
+ }
+
+ for (l = adaptors; l; l = g_list_next (l))
+ {
+ GladeWidgetAdaptor *adaptor = l->data;
+
+ /* Create/append new item */
+ if (glade_widget_adaptor_get_template (adaptor))
+ {
+ GtkWidget *item = glade_palette_new_item (palette, adaptor);
+ gtk_tool_item_group_insert (GTK_TOOL_ITEM_GROUP (priv->composite_templates),
+ GTK_TOOL_ITEM (item), -1);
+ }
+ }
+
+ g_list_free (adaptors);
+}
+
+static void
glade_palette_populate (GladePalette * palette)
{
GList *l;
g_return_if_fail (GLADE_IS_PALETTE (palette));
+ glade_palette_update_templates (palette);
+
for (l = (GList *) glade_app_get_catalogs (); l; l = l->next)
{
GList *groups = glade_catalog_get_widget_groups (GLADE_CATALOG (l->data));
@@ -666,6 +719,10 @@ glade_palette_init (GladePalette * palette)
gtk_widget_set_no_show_all (GTK_WIDGET (palette), TRUE);
glade_palette_populate (palette);
+
+ g_signal_connect_swapped (glade_app_get (), "widget-adaptor-registered",
+ G_CALLBACK (glade_palette_update_templates),
+ palette);
}
diff --git a/gladeui/glade-project.c b/gladeui/glade-project.c
index 7d8bb153..e9aa1813 100644
--- a/gladeui/glade-project.c
+++ b/gladeui/glade-project.c
@@ -1442,7 +1442,8 @@ glade_project_count_xml_objects (GladeProject *project,
for (node = glade_xml_node_get_children (root);
node; node = glade_xml_node_next (node))
{
- if (glade_xml_node_verify_silent (node, GLADE_XML_TAG_WIDGET))
+ if (glade_xml_node_verify_silent (node, GLADE_XML_TAG_WIDGET) ||
+ glade_xml_node_verify_silent (node, GLADE_XML_TAG_TEMPLATE))
count = glade_project_count_xml_objects (project, node, ++count);
else if (glade_xml_node_verify_silent (node, GLADE_XML_TAG_CHILD))
count = glade_project_count_xml_objects (project, node, count);
@@ -1623,7 +1624,8 @@ glade_project_load_internal (GladeProject *project)
node; node = glade_xml_node_next (node))
{
/* Skip "requires" tags */
- if (!glade_xml_node_verify_silent (node, GLADE_XML_TAG_WIDGET))
+ if (!glade_xml_node_verify_silent (node, GLADE_XML_TAG_WIDGET) &&
+ !glade_xml_node_verify_silent (node, GLADE_XML_TAG_TEMPLATE))
continue;
if ((widget = glade_widget_read (project, NULL, node, NULL)) != NULL)
@@ -1992,6 +1994,25 @@ glade_project_save (GladeProject *project, const gchar *path, GError **error)
}
/**
+ * glade_project_dump_string:
+ * @project: a #GladeProject
+ *
+ * Returns: @project as a newlly allocated string
+ */
+gchar *
+glade_project_dump_string (GladeProject *project)
+{
+ GladeXmlContext *context;
+ gchar *retval;
+
+ context = glade_project_write (project);
+ retval = glade_xml_dump_from_context (context);
+ glade_xml_context_destroy (context);
+
+ return retval;
+}
+
+/**
* glade_project_preview:
* @project: a #GladeProject
* @gwidget: a #GladeWidget
@@ -2120,6 +2141,13 @@ glade_project_verify_property_internal (GladeProject *project,
adaptor = glade_widget_adaptor_from_pspec (prop_adaptor, pspec);
g_object_get (adaptor, "catalog", &catalog, NULL);
+
+ /* no need to check if there is no catalog because its a composite widget
+ * automagically loaded by libgladeui
+ */
+ if (catalog == NULL && glade_widget_adaptor_get_template (adaptor))
+ return;
+
glade_project_target_version_for_adaptor (project, adaptor,
&target_major, &target_minor);
@@ -2205,6 +2233,10 @@ glade_project_verify_signal_internal (GladeWidget *widget,
adaptor = glade_signal_class_get_adaptor (signal_class);
g_object_get (adaptor, "catalog", &catalog, NULL);
+
+ if (catalog == NULL && glade_widget_adaptor_get_template (adaptor))
+ return;
+
glade_project_target_version_for_adaptor (glade_widget_get_project (widget),
adaptor,
&target_major, &target_minor);
@@ -2425,8 +2457,11 @@ glade_project_verify_adaptor (GladeProject *project,
for (adaptor_iter = adaptor; adaptor_iter && support_mask == GLADE_SUPPORT_OK;
adaptor_iter = glade_widget_adaptor_get_parent_adaptor (adaptor_iter))
{
-
g_object_get (adaptor_iter, "catalog", &catalog, NULL);
+
+ if (catalog == NULL && glade_widget_adaptor_get_template (adaptor))
+ continue;
+
glade_project_target_version_for_adaptor (project, adaptor_iter,
&target_major, &target_minor);
diff --git a/gladeui/glade-project.h b/gladeui/glade-project.h
index cdde53d5..0910943f 100644
--- a/gladeui/glade-project.h
+++ b/gladeui/glade-project.h
@@ -121,6 +121,7 @@ gboolean glade_project_load_from_file (GladeProject *proj
gboolean glade_project_save (GladeProject *project,
const gchar *path,
GError **error);
+gchar *glade_project_dump_string (GladeProject *project);
void glade_project_push_progress (GladeProject *project);
gboolean glade_project_load_cancelled (GladeProject *project);
void glade_project_cancel_load (GladeProject *project);
diff --git a/gladeui/glade-property.c b/gladeui/glade-property.c
index 08eb6deb..ccdf95f6 100644
--- a/gladeui/glade-property.c
+++ b/gladeui/glade-property.c
@@ -1168,9 +1168,10 @@ glade_property_write (GladeProperty * property,
g_return_if_fail (GLADE_IS_PROPERTY (property));
g_return_if_fail (node != NULL);
- /* This code should work the same for <packing> and <widget> */
+ /* This code should work the same for <packing>, <widget> and <template> */
if (!(glade_xml_node_verify_silent (node, GLADE_XML_TAG_PACKING) ||
- glade_xml_node_verify_silent (node, GLADE_XML_TAG_WIDGET)))
+ glade_xml_node_verify_silent (node, GLADE_XML_TAG_WIDGET) ||
+ glade_xml_node_verify_silent (node, GLADE_XML_TAG_TEMPLATE)))
return;
/* Skip properties that are default by original pspec default
diff --git a/gladeui/glade-widget-adaptor.c b/gladeui/glade-widget-adaptor.c
index 4078dfb1..ccfb61b3 100644
--- a/gladeui/glade-widget-adaptor.c
+++ b/gladeui/glade-widget-adaptor.c
@@ -102,6 +102,8 @@ struct _GladeWidgetAdaptorPrivate
* are special children (like notebook tab
* widgets for example).
*/
+ gchar *template_xml; /* The GtkBuilder template if this is a composite template class */
+ GFileMonitor *template_monitor;
};
struct _GladeChildPacking
@@ -135,7 +137,9 @@ enum
PROP_CATALOG,
PROP_BOOK,
PROP_SPECIAL_TYPE,
- PROP_CURSOR
+ PROP_CURSOR,
+ PROP_TEMPLATE,
+ PROP_TEMPLATE_PATH
};
typedef struct _GladeChildPacking GladeChildPacking;
@@ -380,7 +384,7 @@ gwa_clone_parent_properties (GladeWidgetAdaptor *adaptor, gboolean is_packing)
parent_adaptor->priv->packing_props : parent_adaptor->priv->properties;
/* Reset versioning in derived catalogs just once */
- reset_version = strcmp (adaptor->priv->catalog, parent_adaptor->priv->catalog) != 0;
+ reset_version = g_strcmp0 (adaptor->priv->catalog, parent_adaptor->priv->catalog) != 0;
for (list = proplist; list; list = list->next)
{
@@ -533,8 +537,8 @@ gwa_inherit_signals (GladeWidgetAdaptor *adaptor)
parent_signal = node->data;
/* Reset versioning in derived catalogs just once */
- if (strcmp (adaptor->priv->catalog,
- parent_adaptor->priv->catalog))
+ if (g_strcmp0 (adaptor->priv->catalog,
+ parent_adaptor->priv->catalog))
glade_signal_class_set_since (signal, 0, 0);
else
glade_signal_class_set_since (signal,
@@ -624,7 +628,7 @@ glade_widget_adaptor_constructor (GType type,
/* Reset version numbering if we're in a new catalog just once */
if (parent_adaptor &&
- strcmp (adaptor->priv->catalog, parent_adaptor->priv->catalog))
+ g_strcmp0 (adaptor->priv->catalog, parent_adaptor->priv->catalog))
{
GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->version_since_major =
GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->version_since_minor = 0;
@@ -711,59 +715,48 @@ static void
glade_widget_adaptor_finalize (GObject *object)
{
GladeWidgetAdaptor *adaptor = GLADE_WIDGET_ADAPTOR (object);
-
+ GladeWidgetAdaptorPrivate *priv = adaptor->priv;
+
/* Free properties and signals */
- g_list_foreach (adaptor->priv->properties, (GFunc) glade_property_class_free, NULL);
- g_list_free (adaptor->priv->properties);
+ g_list_foreach (priv->properties, (GFunc) glade_property_class_free, NULL);
+ g_list_free (priv->properties);
- g_list_foreach (adaptor->priv->packing_props, (GFunc) glade_property_class_free,
+ g_list_foreach (priv->packing_props, (GFunc) glade_property_class_free,
NULL);
- g_list_free (adaptor->priv->packing_props);
+ g_list_free (priv->packing_props);
/* Be careful, this list holds GladeSignalClass* not GladeSignal,
* thus g_free is enough as all members are const */
- g_list_foreach (adaptor->priv->signals, (GFunc) g_free, NULL);
- g_list_free (adaptor->priv->signals);
-
+ g_list_foreach (priv->signals, (GFunc) g_free, NULL);
+ g_list_free (priv->signals);
/* Free child packings */
- g_list_foreach (adaptor->priv->child_packings,
- (GFunc) gwa_child_packing_free, NULL);
- g_list_free (adaptor->priv->child_packings);
-
- if (adaptor->priv->book)
- g_free (adaptor->priv->book);
- if (adaptor->priv->catalog)
- g_free (adaptor->priv->catalog);
- if (adaptor->priv->special_child_type)
- g_free (adaptor->priv->special_child_type);
-
- if (adaptor->priv->cursor != NULL)
- g_object_unref (adaptor->priv->cursor);
-
- if (adaptor->priv->name)
- g_free (adaptor->priv->name);
- if (adaptor->priv->generic_name)
- g_free (adaptor->priv->generic_name);
- if (adaptor->priv->title)
- g_free (adaptor->priv->title);
- if (adaptor->priv->icon_name)
- g_free (adaptor->priv->icon_name);
- if (adaptor->priv->missing_icon)
- g_free (adaptor->priv->missing_icon);
-
- if (adaptor->priv->actions)
+ g_list_foreach (priv->child_packings, (GFunc) gwa_child_packing_free, NULL);
+ g_list_free (priv->child_packings);
+
+ g_free (priv->book);
+ g_free (priv->catalog);
+ g_free (priv->special_child_type);
+ g_clear_object (&priv->cursor);
+ g_free (priv->name);
+ g_free (priv->generic_name);
+ g_free (priv->title);
+ g_free (priv->icon_name);
+ g_free (priv->missing_icon);
+ g_free (priv->template_xml);
+
+ if (priv->actions)
{
- g_list_foreach (adaptor->priv->actions,
+ g_list_foreach (priv->actions,
(GFunc) glade_widget_action_class_free, NULL);
- g_list_free (adaptor->priv->actions);
+ g_list_free (priv->actions);
}
- if (adaptor->priv->packing_actions)
+ if (priv->packing_actions)
{
- g_list_foreach (adaptor->priv->packing_actions,
+ g_list_foreach (priv->packing_actions,
(GFunc) glade_widget_action_class_free, NULL);
- g_list_free (adaptor->priv->packing_actions);
+ g_list_free (priv->packing_actions);
}
gwa_internal_children_free (adaptor);
@@ -771,6 +764,105 @@ glade_widget_adaptor_finalize (GObject *object)
G_OBJECT_CLASS (glade_widget_adaptor_parent_class)->finalize (object);
}
+static inline void
+gwa_template_rebuild_objects (GladeWidgetAdaptor *adaptor, GType object_type)
+{
+ GList *l, *rebuild = NULL;
+
+ /* Iterate all projects */
+ for (l = glade_app_get_projects (); l; l = g_list_next (l))
+ {
+ GladeProject *project = l->data;
+ const GList *o;
+
+ /* Iterate all objects in the project */
+ for (o = glade_project_get_objects (project); o; o = g_list_next (o))
+ {
+ GObject *obj = o->data;
+
+ /* And rebuild widget if its template just changed */
+ if (g_type_is_a (G_OBJECT_TYPE (obj), object_type))
+ rebuild = g_list_prepend (rebuild, glade_widget_get_from_gobject (obj));
+ }
+ }
+
+ for (l = rebuild; l; l = g_list_next (l))
+ glade_widget_rebuild (l->data);
+
+ g_list_free (rebuild);
+}
+
+static inline void
+glade_widget_adaptor_set_template (GladeWidgetAdaptor *adaptor,
+ const gchar *template_xml)
+{
+ GladeWidgetAdaptorPrivate *priv = adaptor->priv;
+ GtkContainerClass *klass;
+ GType object_type;
+
+ if (g_strcmp0 (priv->template_xml, template_xml) == 0)
+ return;
+
+ g_free (priv->template_xml);
+ priv->template_xml = g_strdup (template_xml);
+
+ /* Update container class template */
+ object_type = glade_widget_adaptor_get_object_type (adaptor);
+ klass = g_type_class_peek (object_type);
+#if HAVE_GTK_CONTAINER_CLASS_SET_TEMPLATE_FROM_STRING
+ gtk_container_class_set_template_from_string (klass, priv->template_xml, "this");
+#endif
+ gwa_template_rebuild_objects (adaptor, object_type);
+}
+
+static void
+on_template_file_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ GladeWidgetAdaptor *adaptor)
+{
+ gchar *contents = NULL;
+ gsize len;
+
+ if (event_type != G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
+ return;
+
+ if (g_file_load_contents (file, NULL, &contents, &len, NULL, NULL))
+ {
+ g_object_set (adaptor, "template", contents, NULL);
+ g_free (contents);
+ }
+}
+
+static inline void
+glade_widget_adaptor_set_template_path (GladeWidgetAdaptor *adaptor,
+ const gchar *path)
+{
+ GladeWidgetAdaptorPrivate *priv = adaptor->priv;
+ GFile *file = g_file_new_for_path (path);
+ GError *error = NULL;
+
+ g_clear_object (&priv->template_monitor);
+
+ /* Add watch for file */
+ priv->template_monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, &error);
+
+ if (priv->template_monitor)
+ {
+ g_signal_connect (priv->template_monitor, "changed",
+ G_CALLBACK (on_template_file_changed),
+ adaptor);
+ }
+ else
+ {
+ g_warning ("Unable to monitor path `%s` %s", path, error->message);
+ g_error_free (error);
+ }
+
+ g_object_unref (file);
+}
+
static void
glade_widget_adaptor_real_set_property (GObject *object,
guint prop_id,
@@ -820,6 +912,12 @@ glade_widget_adaptor_real_set_property (GObject *object,
g_free (adaptor->priv->special_child_type);
adaptor->priv->special_child_type = g_value_dup_string (value);
break;
+ case PROP_TEMPLATE:
+ glade_widget_adaptor_set_template (adaptor, g_value_get_string (value));
+ break;
+ case PROP_TEMPLATE_PATH:
+ glade_widget_adaptor_set_template_path (adaptor, g_value_get_string (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -866,6 +964,9 @@ glade_widget_adaptor_real_get_property (GObject *object,
case PROP_CURSOR:
g_value_set_pointer (value, adaptor->priv->cursor);
break;
+ case PROP_TEMPLATE:
+ g_value_set_string (value, adaptor->priv->template_xml);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1455,6 +1556,20 @@ glade_widget_adaptor_class_init (GladeWidgetAdaptorClass *adaptor_class)
("cursor", _("Cursor"),
_("A cursor for inserting widgets in the UI"), G_PARAM_READABLE));
+ g_object_class_install_property
+ (object_class, PROP_TEMPLATE,
+ g_param_spec_string
+ ("template", _("Template"),
+ _("Builder template of the class"),
+ NULL, G_PARAM_READWRITE));
+
+ g_object_class_install_property
+ (object_class, PROP_TEMPLATE_PATH,
+ g_param_spec_string
+ ("template-path", _("Template path"),
+ _("Builder template file path of the class, if set it will be used to monitor and update template property automatically"),
+ NULL, G_PARAM_WRITABLE));
+
g_type_class_add_private (adaptor_class, sizeof (GladeWidgetAdaptorPrivate));
}
@@ -1632,9 +1747,14 @@ static void
gwa_derived_class_init (GladeWidgetAdaptorClass *adaptor_class,
GWADerivedClassData *data)
{
- GladeXmlNode *node = data->node;
- GModule *module = data->module;
+ GladeXmlNode *node;
+ GModule *module;
+ if (data == NULL) return;
+
+ node = data->node;
+ module = data->module;
+
/* Load catalog symbols from module */
if (module)
gwa_extend_with_node_load_sym (adaptor_class, node, module);
@@ -1705,7 +1825,6 @@ gwa_derive_adaptor_for_type (GType object_type, GWADerivedClassData *data)
return derived_type;
}
-
/*******************************************************************************
API
*******************************************************************************/
@@ -1781,6 +1900,14 @@ glade_widget_adaptor_get_signals (GladeWidgetAdaptor *adaptor)
return adaptor->priv->signals;
}
+G_CONST_RETURN gchar *
+glade_widget_adaptor_get_template (GladeWidgetAdaptor *adaptor)
+{
+ g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
+
+ return adaptor->priv->template_xml;
+}
+
static void
accum_adaptor (GType *type, GladeWidgetAdaptor *adaptor, GList **list)
{
@@ -1829,6 +1956,8 @@ glade_widget_adaptor_register (GladeWidgetAdaptor *adaptor)
g_hash_table_insert (adaptor_hash,
g_memdup (&adaptor->priv->type, sizeof (GType)), adaptor);
+
+ g_signal_emit_by_name (glade_app_get (), "widget-adaptor-registered", adaptor);
}
static GladePackingDefault *
@@ -2601,6 +2730,54 @@ generate_deprecated_icon (const gchar *icon_name)
}
/**
+ * glade_widget_adaptor_from_composite_template:
+ * @template_type: a #GType
+ * @template_xml: composite template ui description
+ * @generic_name: the genereic name of the adaptor
+ * @icon_name: the icon name for the adaptor or NULL to fallback to the parent
+ *
+ * Dynamicaly creates the corresponding adaptor for the template type.
+ */
+GladeWidgetAdaptor *
+glade_widget_adaptor_from_composite_template (GType template_type,
+ const gchar *template_xml,
+ const gchar *generic_name,
+ const gchar *icon_name)
+{
+ gchar *adaptor_icon_name = NULL;
+ GladeWidgetAdaptor *adaptor;
+ GType adaptor_type;
+ const gchar *name;
+
+ g_return_val_if_fail (g_type_is_a (template_type, GTK_TYPE_CONTAINER), NULL);
+
+ adaptor_type = gwa_derive_adaptor_for_type (template_type, NULL);
+ name = g_type_name (template_type);
+
+ /* Fallback to parent icon */
+ if (!icon_name)
+ {
+ GladeWidgetAdaptor *parent = glade_widget_adaptor_get_parent_adaptor_by_type (template_type);
+ adaptor_icon_name = g_strdup ((parent && parent->priv->icon_name) ?
+ parent->priv->icon_name : DEFAULT_ICON_NAME);
+ }
+
+ adaptor = g_object_new (adaptor_type,
+ "type", template_type,
+ "template", template_xml,
+ "name", name,
+ "catalog", NULL, /* yup NULL, it does not have a catalog */
+ "generic-name", generic_name,
+ "icon-name", icon_name ? icon_name : adaptor_icon_name,
+ "title", name,
+ NULL);
+
+ g_free (adaptor_icon_name);
+
+ return adaptor;
+}
+
+/**
* glade_widget_adaptor_from_catalog:
* @catalog: A #GladeCatalog
* @class_node: the #GladeXmlNode to load
diff --git a/gladeui/glade-widget-adaptor.h b/gladeui/glade-widget-adaptor.h
index ab33a531..6f07a163 100644
--- a/gladeui/glade-widget-adaptor.h
+++ b/gladeui/glade-widget-adaptor.h
@@ -185,8 +185,8 @@ typedef enum
* Returns: A newly created #GladeWidget for the said adaptor.
*/
typedef GladeWidget * (* GladeCreateWidgetFunc) (GladeWidgetAdaptor *adaptor,
- const gchar *first_property_name,
- va_list var_args);
+ const gchar *first_property_name,
+ va_list var_args);
/**
* GladeSetPropertyFunc:
@@ -201,9 +201,9 @@ typedef GladeWidget * (* GladeCreateWidgetFunc) (GladeWidgetAdaptor *adaptor,
* Sets @value on @object for a given #GladePropertyClass
*/
typedef void (* GladeSetPropertyFunc) (GladeWidgetAdaptor *adaptor,
- GObject *object,
- const gchar *property_name,
- const GValue *value);
+ GObject *object,
+ const gchar *property_name,
+ const GValue *value);
/**
* GladeGetPropertyFunc:
@@ -215,7 +215,7 @@ typedef void (* GladeSetPropertyFunc) (GladeWidgetAdaptor *adaptor,
* Gets @value on @object for a given #GladePropertyClass
*/
typedef void (* GladeGetPropertyFunc) (GladeWidgetAdaptor *adaptor,
- GObject *object,
+ GObject *object,
const gchar *property_name,
GValue *value);
@@ -686,12 +686,18 @@ G_CONST_RETURN gchar *glade_widget_adaptor_get_missing_icon (GladeWidgetAdaptor
G_CONST_RETURN GList *glade_widget_adaptor_get_properties (GladeWidgetAdaptor *adaptor);
G_CONST_RETURN GList *glade_widget_adaptor_get_packing_props(GladeWidgetAdaptor *adaptor);
G_CONST_RETURN GList *glade_widget_adaptor_get_signals (GladeWidgetAdaptor *adaptor);
+G_CONST_RETURN gchar *glade_widget_adaptor_get_template (GladeWidgetAdaptor *adaptor);
GList *glade_widget_adaptor_list_adaptors (void);
GladeWidgetAdaptor *glade_widget_adaptor_from_catalog (GladeCatalog *catalog,
- GladeXmlNode *class_node,
- GModule *module);
+ GladeXmlNode *class_node,
+ GModule *module);
+
+GladeWidgetAdaptor *glade_widget_adaptor_from_composite_template (GType template_type,
+ const gchar *template_xml,
+ const gchar *generic_name,
+ const gchar *icon_name);
void glade_widget_adaptor_register (GladeWidgetAdaptor *adaptor);
diff --git a/gladeui/glade-widget.c b/gladeui/glade-widget.c
index ba9c2b37..405856c3 100644
--- a/gladeui/glade-widget.c
+++ b/gladeui/glade-widget.c
@@ -79,6 +79,7 @@ struct _GladeWidgetPrivate {
* button2. This is a unique name and is the one
* used when loading widget with libglade
*/
+ gchar *template_class; /* The name of the composite class this widget defines */
gchar *support_warning; /* A warning message for version incompatabilities
* in this widget
@@ -192,6 +193,7 @@ enum
PROP_TOPLEVEL_HEIGHT,
PROP_SUPPORT_WARNING,
PROP_VISIBLE,
+ PROP_TEMPLATE_CLASS,
N_PROPERTIES
};
@@ -1093,6 +1095,9 @@ glade_widget_set_real_property (GObject * object,
case PROP_TOPLEVEL_HEIGHT:
widget->priv->height = g_value_get_int (value);
break;
+ case PROP_TEMPLATE_CLASS:
+ glade_widget_set_template_class (widget, g_value_get_string (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1149,6 +1154,9 @@ glade_widget_get_real_property (GObject * object,
case PROP_REASON:
g_value_set_int (value, widget->priv->construct_reason);
break;
+ case PROP_TEMPLATE_CLASS:
+ g_value_set_string (value, widget->priv->template_class);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1304,7 +1312,12 @@ glade_widget_class_init (GladeWidgetClass * klass)
g_param_spec_boolean ("visible", _("Visible"),
_("Wether the widget is visible or not"),
FALSE, G_PARAM_READABLE);
-
+
+ properties[PROP_TEMPLATE_CLASS] =
+ g_param_spec_string ("template-class", _("Template Class"),
+ _("The class name this template defines"),
+ NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+
/* Install all properties */
g_object_class_install_properties (object_class, N_PROPERTIES, properties);
@@ -2512,7 +2525,7 @@ void
glade_widget_set_name (GladeWidget * widget, const gchar * name)
{
g_return_if_fail (GLADE_IS_WIDGET (widget));
- if (widget->priv->name != name)
+ if (g_strcmp0 (widget->priv->name, name))
{
if (widget->priv->name)
g_free (widget->priv->name);
@@ -2536,6 +2549,45 @@ glade_widget_get_name (GladeWidget * widget)
}
/**
+ * glade_widget_set_template_class:
+ * @widget: a #GladeWidget
+ * @name: a string
+ *
+ * Sets the template class name this @widget defines.
+ * @widget has to be toplevel.
+ */
+void
+glade_widget_set_template_class (GladeWidget *widget, const gchar *name)
+{
+ g_return_if_fail (GLADE_IS_WIDGET (widget));
+
+ /* Check toplevelness */
+ if (glade_widget_get_parent (widget)) return;
+
+ if (g_strcmp0 (widget->priv->template_class, name))
+ {
+ if (widget->priv->template_class)
+ g_free (widget->priv->template_class);
+
+ widget->priv->template_class = g_strdup (name);
+ g_object_notify_by_pspec (G_OBJECT (widget), properties[PROP_TEMPLATE_CLASS]);
+ }
+}
+
+/**
+ * glade_widget_get_template_class:
+ * @widget: a #GladeWidget
+ *
+ * Returns: a pointer to @widget's template class name.
+ */
+const gchar *
+glade_widget_get_template_class (GladeWidget *widget)
+{
+ g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
+ return widget->priv->template_class;
+}
+
+/**
* glade_widget_set_internal:
* @widget: A #GladeWidget
* @internal: The internal name
@@ -3730,23 +3782,24 @@ glade_widget_read (GladeProject * project,
{
GladeWidgetAdaptor *adaptor;
GladeWidget *widget = NULL;
- gchar *klass, *id;
+ gchar *klass, *id = NULL;
+ gboolean is_tmpl;
if (glade_project_load_cancelled (project))
return NULL;
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
+ is_tmpl = (parent == NULL && glade_xml_node_verify_silent (node, GLADE_XML_TAG_TEMPLATE));
+
+ if (!is_tmpl && !glade_xml_node_verify_silent (node, GLADE_XML_TAG_WIDGET))
return NULL;
glade_widget_push_superuser ();
if ((klass =
glade_xml_get_property_string_required
- (node, GLADE_XML_TAG_CLASS, NULL)) != NULL)
+ (node, is_tmpl ? GLADE_XML_TAG_PARENT : GLADE_XML_TAG_CLASS, NULL)) != NULL)
{
- if ((id =
- glade_xml_get_property_string_required
- (node, GLADE_XML_TAG_ID, NULL)) != NULL)
+ if ((id = glade_xml_get_property_string_required (node, GLADE_XML_TAG_ID, NULL)))
{
GType type;
/*
@@ -3780,11 +3833,15 @@ glade_widget_read (GladeProject * project,
}
else
{
+ gchar *tmpl = (is_tmpl) ? glade_xml_get_property_string (node, GLADE_XML_TAG_CLASS) : NULL;
widget = glade_widget_adaptor_create_widget
(adaptor, FALSE,
"name", id,
"parent", parent,
- "project", project, "reason", GLADE_CREATE_LOAD, NULL);
+ "project", project,
+ "reason", GLADE_CREATE_LOAD,
+ "template-class", tmpl, NULL);
+ g_free (tmpl);
}
glade_widget_adaptor_read_widget (adaptor, widget, node);
@@ -3927,6 +3984,7 @@ void
glade_widget_write (GladeWidget * widget,
GladeXmlContext * context, GladeXmlNode * node)
{
+ const gchar *tmpl = glade_widget_get_template_class (widget);
GObject *object = glade_widget_get_object (widget);
GladeXmlNode *widget_node;
GList *l, *list;
@@ -3939,13 +3997,16 @@ glade_widget_write (GladeWidget * widget,
return;
}
- widget_node = glade_xml_node_new (context, GLADE_XML_TAG_WIDGET);
+ widget_node = glade_xml_node_new (context, (tmpl) ? GLADE_XML_TAG_TEMPLATE : GLADE_XML_TAG_WIDGET);
glade_xml_node_append_child (node, widget_node);
/* Set class and id */
glade_xml_node_set_property_string (widget_node,
- GLADE_XML_TAG_CLASS,
+ (tmpl) ? GLADE_XML_TAG_PARENT : GLADE_XML_TAG_CLASS,
glade_widget_adaptor_get_name (widget->priv->adaptor));
+ if (tmpl)
+ glade_xml_node_set_property_string (widget_node, GLADE_XML_TAG_CLASS, tmpl);
+
glade_xml_node_set_property_string (widget_node,
GLADE_XML_TAG_ID, widget->priv->name);
diff --git a/gladeui/glade-widget.h b/gladeui/glade-widget.h
index 7762cedb..e3983dfd 100644
--- a/gladeui/glade-widget.h
+++ b/gladeui/glade-widget.h
@@ -337,6 +337,11 @@ void glade_widget_set_name (GladeWidget *widget,
G_CONST_RETURN gchar *glade_widget_get_name (GladeWidget *widget);
+void glade_widget_set_template_class (GladeWidget *widget,
+ const gchar *name);
+
+G_CONST_RETURN gchar *glade_widget_get_template_class (GladeWidget *widget);
+
void glade_widget_set_internal (GladeWidget *widget,
const gchar *internal);
diff --git a/gladeui/glade-xml-utils.h b/gladeui/glade-xml-utils.h
index c7b116fa..ff9b6760 100644
--- a/gladeui/glade-xml-utils.h
+++ b/gladeui/glade-xml-utils.h
@@ -36,12 +36,14 @@ typedef struct _GladeProject GladeProject;
/* Used for catalog tags and attributes */
#define GLADE_XML_TAG_PROJECT "interface"
#define GLADE_XML_TAG_WIDGET "object"
+#define GLADE_XML_TAG_TEMPLATE "template"
#define GLADE_XML_TAG_VERSION "version"
#define GLADE_XML_TAG_REQUIRES "requires"
#define GLADE_XML_TAG_LIB "lib"
#define GLADE_XML_TAG_PROPERTY "property"
#define GLADE_XML_TAG_CLASS "class"
+#define GLADE_XML_TAG_PARENT "parent"
#define GLADE_XML_TAG_ID "id"
#define GLADE_XML_TAG_SIGNAL "signal"
#define GLADE_XML_TAG_HANDLER "handler"
diff --git a/gladeui/glade.h b/gladeui/glade.h
index ddfb178d..04dc4063 100644
--- a/gladeui/glade.h
+++ b/gladeui/glade.h
@@ -46,5 +46,6 @@
#include <gladeui/glade-displayable-values.h>
#include <gladeui/glade-cell-renderer-icon.h>
#include <gladeui/glade-cursor.h>
+#include <gladeui/glade-composite-template.h>
#endif /* __GLADE_H__ */
diff --git a/plugins/gtk+/glade-gtk.c b/plugins/gtk+/glade-gtk.c
index c1f787d2..9e147aaa 100644
--- a/plugins/gtk+/glade-gtk.c
+++ b/plugins/gtk+/glade-gtk.c
@@ -410,9 +410,6 @@ void
glade_gtk_widget_read_widget (GladeWidgetAdaptor * adaptor,
GladeWidget * widget, GladeXmlNode * node)
{
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (G_TYPE_OBJECT)->read_widget (adaptor, widget, node);
@@ -506,7 +503,6 @@ glade_gtk_widget_write_atk_properties (GladeWidget * widget,
g_free (atkname);
}
-
}
static void
@@ -686,9 +682,6 @@ glade_gtk_widget_write_widget (GladeWidgetAdaptor * adaptor,
{
GObject *obj;
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* Make sure use-action-appearance and related-action properties are
* ordered in a sane way and are only saved if there is an action */
if ((obj = glade_widget_get_object (widget)) &&
@@ -812,7 +805,6 @@ glade_gtk_widget_set_property (GladeWidgetAdaptor * adaptor,
{
id = "tooltip-text";
}
-
GWA_GET_CLASS (G_TYPE_OBJECT)->set_property (adaptor, object, id, value);
}
@@ -825,7 +817,6 @@ glade_gtk_widget_get_property (GladeWidgetAdaptor * adaptor,
{
id = "tooltip-text";
}
-
GWA_GET_CLASS (G_TYPE_OBJECT)->get_property (adaptor, object, id, value);
}
@@ -1135,6 +1126,18 @@ glade_gtk_widget_action_submenu (GladeWidgetAdaptor * adaptor,
/* ----------------------------- GtkContainer ------------------------------ */
void
+glade_gtk_container_deep_post_create (GladeWidgetAdaptor *adaptor,
+ GObject *container,
+ GladeCreateReason reason)
+{
+ GladeWidget *widget = glade_widget_get_from_gobject (container);
+
+ if (!glade_widget_get_parent (widget) && glade_widget_get_template_class (widget))
+ glade_widget_property_set (widget, "glade-template-class",
+ glade_widget_get_template_class (widget));
+}
+
+void
glade_gtk_container_post_create (GladeWidgetAdaptor * adaptor,
GObject * container, GladeCreateReason reason)
{
@@ -1336,6 +1339,103 @@ glade_gtk_container_create_editable (GladeWidgetAdaptor * adaptor,
return GWA_GET_CLASS (GTK_TYPE_CONTAINER)->create_editable (adaptor, type);
}
+void
+glade_gtk_container_set_property (GladeWidgetAdaptor *adaptor,
+ GObject *object,
+ const gchar *id,
+ const GValue *value)
+{
+ if (!strcmp (id, "glade-template-class"))
+ {
+ GladeWidget *gwidget = glade_widget_get_from_gobject (object);
+ glade_widget_set_template_class (gwidget, g_value_get_string (value));
+ }
+ else GWA_GET_CLASS (G_TYPE_OBJECT)->set_property (adaptor, object, id, value);
+}
+
+void
+glade_gtk_container_get_property (GladeWidgetAdaptor *adaptor,
+ GObject *object,
+ const gchar *id,
+ GValue *value)
+{
+ if (!strcmp (id, "glade-template-class"))
+ {
+ GladeWidget *gwidget = glade_widget_get_from_gobject (object);
+ g_value_set_string (value, glade_widget_get_template_class (gwidget));
+ }
+ else GWA_GET_CLASS (G_TYPE_OBJECT)->get_property (adaptor, object, id, value);
+}
+
+void
+glade_gtk_container_action_activate (GladeWidgetAdaptor *adaptor,
+ GObject *object,
+ const gchar *action_path)
+{
+ GladeWidget *gwidget = glade_widget_get_from_gobject (object);
+
+ if (strcmp (action_path, "template") == 0)
+ {
+ GtkFileFilter *filter = gtk_file_filter_new ();
+ gchar *template_class, *template_file;
+ GtkWidget *dialog, *help_label;
+ GtkFileChooser *chooser;
+
+ gtk_file_filter_add_pattern (filter, "*.ui");
+
+ dialog = gtk_file_chooser_dialog_new (_("Save Template"),
+ GTK_WINDOW (glade_app_get_window ()),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+ NULL);
+ chooser = GTK_FILE_CHOOSER (dialog);
+ gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE);
+ gtk_file_chooser_set_filter (chooser, filter);
+ help_label = gtk_label_new (_("NOTE: the base name of the file will be used"
+ " as the class name so it should be in CamelCase"));
+ gtk_file_chooser_set_extra_widget (chooser, help_label);
+ gtk_widget_show (help_label);
+
+ template_class = g_strconcat ("My", G_OBJECT_TYPE_NAME (object), NULL);
+ template_file = g_strconcat (template_class, ".ui", NULL);
+
+ gtk_file_chooser_set_current_folder (chooser, g_get_user_special_dir (G_USER_DIRECTORY_TEMPLATES));
+ gtk_file_chooser_set_current_name (chooser, template_file);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
+ {
+ gchar *filename = gtk_file_chooser_get_filename (chooser);
+ gchar *basename = g_path_get_basename (filename);
+ gchar *dot = g_strrstr (basename, ".ui");
+
+ /* Strip file extension to get the class name */
+ if (dot)
+ {
+ *dot = '\0';
+ }
+ else
+ {
+ /* Or add it if it is not present */
+ gchar *tmp = g_strconcat (filename, ".ui", NULL);
+ g_free (filename);
+ filename = tmp;
+ }
+
+ glade_composite_template_save_from_widget (gwidget, basename, filename, TRUE);
+
+ g_free (basename);
+ g_free (filename);
+ }
+
+ g_free (template_class);
+ g_free (template_file);
+ gtk_widget_destroy (dialog);
+ }
+ else
+ GWA_GET_CLASS (GTK_TYPE_WIDGET)->action_activate (adaptor, object, action_path);
+}
+
/* ----------------------------- GtkBox ------------------------------ */
GladeWidget *
@@ -3393,9 +3493,6 @@ glade_gtk_entry_read_widget (GladeWidgetAdaptor * adaptor,
{
GladeProperty *property;
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (GTK_TYPE_WIDGET)->read_widget (adaptor, widget, node);
@@ -3631,9 +3728,6 @@ void
glade_gtk_window_read_widget (GladeWidgetAdaptor * adaptor,
GladeWidget * widget, GladeXmlNode * node)
{
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (GTK_TYPE_WIDGET)->read_widget (adaptor, widget, node);
@@ -3677,9 +3771,6 @@ glade_gtk_window_write_widget (GladeWidgetAdaptor * adaptor,
GladeWidget * widget,
GladeXmlContext * context, GladeXmlNode * node)
{
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (GTK_TYPE_WIDGET)->write_widget (adaptor, widget, context,
node);
@@ -4262,9 +4353,6 @@ void
glade_gtk_button_read_widget (GladeWidgetAdaptor * adaptor,
GladeWidget * widget, GladeXmlNode * node)
{
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->read_widget (adaptor, widget, node);
@@ -4280,9 +4368,6 @@ glade_gtk_button_write_widget (GladeWidgetAdaptor * adaptor,
gboolean use_stock;
gchar *stock = NULL;
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* Do not save GtkColorButton GtkFontButton and GtkScaleButton label property */
if (!(GTK_IS_COLOR_BUTTON (glade_widget_get_object (widget)) ||
GTK_IS_FONT_BUTTON (glade_widget_get_object (widget)) ||
@@ -4318,9 +4403,6 @@ glade_gtk_image_read_widget (GladeWidgetAdaptor * adaptor,
{
GladeProperty *property;
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (GTK_TYPE_WIDGET)->read_widget (adaptor, widget, node);
@@ -4356,9 +4438,6 @@ glade_gtk_image_write_widget (GladeWidgetAdaptor * adaptor,
GtkIconSize icon_size;
gchar *value;
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* First chain up and write all the normal properties (including "use-stock")... */
GWA_GET_CLASS (GTK_TYPE_WIDGET)->write_widget (adaptor, widget, context,
node);
@@ -5502,9 +5581,6 @@ glade_gtk_image_menu_item_read_widget (GladeWidgetAdaptor * adaptor,
gboolean use_stock;
gchar *label = NULL;
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (GTK_TYPE_MENU_ITEM)->read_widget (adaptor, widget, node);
@@ -5541,9 +5617,6 @@ glade_gtk_image_menu_item_write_widget (GladeWidgetAdaptor * adaptor,
gboolean use_stock;
gchar *stock;
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* Make a copy of the GladeProperty, override its value if use-stock is TRUE */
label_prop = glade_widget_get_property (widget, "label");
label_prop = glade_property_dup (label_prop, widget);
@@ -6246,8 +6319,6 @@ void
glade_gtk_tool_item_group_read_widget (GladeWidgetAdaptor * adaptor,
GladeWidget * widget, GladeXmlNode * node)
{
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (GTK_TYPE_TOOL_ITEM)->read_widget (adaptor, widget, node);
@@ -6554,9 +6625,6 @@ void
glade_gtk_tool_button_read_widget (GladeWidgetAdaptor * adaptor,
GladeWidget * widget, GladeXmlNode * node)
{
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (GTK_TYPE_TOOL_ITEM)->read_widget (adaptor, widget, node);
@@ -7040,8 +7108,6 @@ glade_gtk_label_read_widget (GladeWidgetAdaptor * adaptor,
GladeWidget * widget, GladeXmlNode * node)
{
GladeProperty *prop;
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (GTK_TYPE_WIDGET)->read_widget (adaptor, widget, node);
@@ -7126,9 +7192,6 @@ glade_gtk_label_write_widget (GladeWidgetAdaptor * adaptor,
{
GladeXmlNode *attrs_node;
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (GTK_TYPE_WIDGET)->write_widget (adaptor, widget, context,
node);
@@ -7567,9 +7630,6 @@ void
glade_gtk_combo_box_text_read_widget (GladeWidgetAdaptor * adaptor,
GladeWidget * widget, GladeXmlNode * node)
{
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (GTK_TYPE_COMBO_BOX)->read_widget (adaptor, widget, node);
@@ -7621,9 +7681,6 @@ glade_gtk_combo_box_text_write_widget (GladeWidgetAdaptor * adaptor,
{
GladeXmlNode *attrs_node;
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (GTK_TYPE_COMBO_BOX)->write_widget (adaptor, widget, context, node);
@@ -8151,9 +8208,6 @@ void
glade_gtk_size_group_read_widget (GladeWidgetAdaptor * adaptor,
GladeWidget * widget, GladeXmlNode * node)
{
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (G_TYPE_OBJECT)->read_widget (adaptor, widget, node);
@@ -8199,9 +8253,6 @@ glade_gtk_size_group_write_widget (GladeWidgetAdaptor * adaptor,
GladeXmlContext * context,
GladeXmlNode * node)
{
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (G_TYPE_OBJECT)->write_widget (adaptor, widget, context, node);
@@ -8390,9 +8441,6 @@ void
glade_gtk_icon_factory_read_widget (GladeWidgetAdaptor * adaptor,
GladeWidget * widget, GladeXmlNode * node)
{
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* First chain up and read in any normal properties.. */
GWA_GET_CLASS (G_TYPE_OBJECT)->read_widget (adaptor, widget, node);
@@ -8498,9 +8546,6 @@ glade_gtk_icon_factory_write_widget (GladeWidgetAdaptor * adaptor,
GladeXmlContext * context,
GladeXmlNode * node)
{
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* First chain up and write all the normal properties.. */
GWA_GET_CLASS (G_TYPE_OBJECT)->write_widget (adaptor, widget, context, node);
@@ -9178,9 +9223,6 @@ glade_gtk_store_write_widget (GladeWidgetAdaptor * adaptor,
GladeWidget * widget,
GladeXmlContext * context, GladeXmlNode * node)
{
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* First chain up and write all the normal properties.. */
GWA_GET_CLASS (G_TYPE_OBJECT)->write_widget (adaptor, widget, context, node);
@@ -9384,9 +9426,6 @@ void
glade_gtk_store_read_widget (GladeWidgetAdaptor * adaptor,
GladeWidget * widget, GladeXmlNode * node)
{
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (G_TYPE_OBJECT)->read_widget (adaptor, widget, node);
@@ -9618,9 +9657,6 @@ glade_gtk_cell_renderer_write_widget (GladeWidgetAdaptor * adaptor,
GladeXmlContext * context,
GladeXmlNode * node)
{
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* Write our normal properties, then chain up to write any other normal properties,
* then attributes
*/
@@ -9674,9 +9710,6 @@ void
glade_gtk_cell_renderer_read_widget (GladeWidgetAdaptor * adaptor,
GladeWidget * widget, GladeXmlNode * node)
{
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* First chain up and read in all the properties... */
GWA_GET_CLASS (G_TYPE_OBJECT)->read_widget (adaptor, widget, node);
@@ -10401,9 +10434,6 @@ glade_gtk_adjustment_write_widget (GladeWidgetAdaptor * adaptor,
{
GladeProperty *prop;
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* Ensure proper order of adjustment properties by writing them here. */
prop = glade_widget_get_property (widget, "lower");
glade_property_write (prop, context, node);
@@ -10941,9 +10971,6 @@ glade_gtk_recent_filter_read_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlNode *node)
{
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (G_TYPE_OBJECT)->read_widget (adaptor, widget, node);
@@ -10960,9 +10987,6 @@ glade_gtk_recent_filter_write_widget (GladeWidgetAdaptor *adaptor,
{
GladeXmlNode *strings_node;
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (G_TYPE_OBJECT)->write_widget (adaptor, widget, context, node);
@@ -10999,9 +11023,6 @@ glade_gtk_file_filter_read_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlNode *node)
{
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (G_TYPE_OBJECT)->read_widget (adaptor, widget, node);
@@ -11017,9 +11038,6 @@ glade_gtk_file_filter_write_widget (GladeWidgetAdaptor *adaptor,
{
GladeXmlNode *strings_node;
- if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
- return;
-
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (G_TYPE_OBJECT)->write_widget (adaptor, widget, context, node);
diff --git a/plugins/gtk+/gtk+.xml.in b/plugins/gtk+/gtk+.xml.in
index df4af2a6..f6d20cf1 100644
--- a/plugins/gtk+/gtk+.xml.in
+++ b/plugins/gtk+/gtk+.xml.in
@@ -6,7 +6,6 @@
domain="glade3"
book="gtk3">
<glade-widget-classes>
-
<glade-widget-class name="GtkWidget" _title="Widget" default-width="100" default-height="60">
<deep-post-create-function>glade_gtk_widget_deep_post_create</deep-post-create-function>
@@ -289,6 +288,7 @@ embedded in another object</_tooltip>
<glade-widget-class name="GtkContainer" _title="Container" use-placeholders="True">
<post-create-function>glade_gtk_container_post_create</post-create-function>
+ <deep-post-create-function>glade_gtk_container_deep_post_create</deep-post-create-function>
<add-child-verify-function>glade_gtk_container_add_verify</add-child-verify-function>
<add-child-function>glade_gtk_container_add_child</add-child-function>
<remove-child-function>glade_gtk_container_remove_child</remove-child-function>
@@ -296,8 +296,18 @@ embedded in another object</_tooltip>
<child-set-property-function>glade_gtk_container_set_child_property</child-set-property-function>
<child-get-property-function>glade_gtk_container_get_child_property</child-get-property-function>
<get-children-function>glade_gtk_container_get_children</get-children-function>
-
+ <set-property-function>glade_gtk_container_set_property</set-property-function>
+ <get-property-function>glade_gtk_container_get_property</get-property-function>
+ <action-activate-function>glade_gtk_container_action_activate</action-activate-function>
+ <actions>
+ <action id="template" _name="Export as template" stock="gtk-convert" important="True"/>
+ </actions>
<properties>
+ <property id="glade-template-class" _name="Template Class" save="False" custom-layout="True">
+ <parameter-spec>
+ <type>GParamString</type>
+ </parameter-spec>
+ </property>
<property id="border-width" common="True" weight="2.5"/>
<property id="resize-mode" ignore="True" common="True" weight="4.7">
<displayable-values>