diff options
author | Juan Pablo Ugarte <juanpablougarte@gmai.com> | 2013-01-31 17:15:01 +0100 |
---|---|---|
committer | Juan Pablo Ugarte <juanpablougarte@gmai.com> | 2013-01-31 17:15:01 +0100 |
commit | 6552f5f48d02bfab7e7624970c3dd623511dabea (patch) | |
tree | 6ef498b7c26dc43d2fd494b5f3e85bc010cc72c3 | |
parent | e12f3a4ad551591e7de6805c2da13eb7088bc2f3 (diff) | |
download | glade-6552f5f48d02bfab7e7624970c3dd623511dabea.tar.gz |
Revert "Reverting all composite templates support until it lands on GTK"
This reverts commit e12f3a4ad551591e7de6805c2da13eb7088bc2f3.
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | gladeui/Makefile.am | 2 | ||||
-rw-r--r-- | gladeui/glade-app.c | 3 | ||||
-rw-r--r-- | gladeui/glade-composite-template.c | 310 | ||||
-rw-r--r-- | gladeui/glade-composite-template.h | 43 | ||||
-rw-r--r-- | gladeui/glade-editor-table.c | 176 | ||||
-rw-r--r-- | gladeui/glade-palette.c | 65 | ||||
-rw-r--r-- | gladeui/glade-project.c | 41 | ||||
-rw-r--r-- | gladeui/glade-project.h | 1 | ||||
-rw-r--r-- | gladeui/glade-property.c | 5 | ||||
-rw-r--r-- | gladeui/glade-widget-adaptor.c | 271 | ||||
-rw-r--r-- | gladeui/glade-widget-adaptor.h | 22 | ||||
-rw-r--r-- | gladeui/glade-widget.c | 83 | ||||
-rw-r--r-- | gladeui/glade-widget.h | 5 | ||||
-rw-r--r-- | gladeui/glade-xml-utils.h | 2 | ||||
-rw-r--r-- | gladeui/glade.h | 1 | ||||
-rw-r--r-- | plugins/gtk+/glade-gtk.c | 200 | ||||
-rw-r--r-- | plugins/gtk+/gtk+.xml.in | 14 |
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> |