Commit 64cea184 authored by Juan Pablo Ugarte's avatar Juan Pablo Ugarte
Browse files

Implemented template loading and saving

Added GladeWidget:template-class property with setter and getter functions.
Removed if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET)) check from every GWA read_widget()
parent bc083e09
......@@ -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);
......
......@@ -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)
......
......@@ -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);
......@@ -2535,6 +2548,45 @@ glade_widget_get_name (GladeWidget * widget)
return widget->priv->name;
}
/**
* 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
......@@ -3730,31 +3782,33 @@ 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)))
{
/*
* Create GladeWidget instance based on type.
*/
if ((adaptor = glade_widget_adaptor_get_by_name (klass)) != NULL)
{
// Internal children !!!
/* Internal children !!! */
if (internal)
{
GObject *child_object =
......@@ -3777,11 +3831,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);
......@@ -3924,6 +3982,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;
......@@ -3936,13 +3995,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);
......
......@@ -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);
......
......@@ -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"
......
......@@ -378,9 +378,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);
......@@ -472,7 +469,6 @@ glade_gtk_widget_write_atk_properties (GladeWidget * widget,
g_free (atkname);
}
}
static void
......@@ -620,9 +616,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)) &&
......@@ -736,7 +729,6 @@ glade_gtk_widget_set_property (GladeWidgetAdaptor * adaptor,
{
id = "tooltip-text";
}
GWA_GET_CLASS (G_TYPE_OBJECT)->set_property (adaptor, object, id, value);
}
......@@ -749,7 +741,6 @@ glade_gtk_widget_get_property (GladeWidgetAdaptor * adaptor,
{
id = "tooltip-text";
}
GWA_GET_CLASS (G_TYPE_OBJECT)->get_property (adaptor, object, id, value);
}
......@@ -1058,6 +1049,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)
......@@ -1260,6 +1263,34 @@ 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);
}
/* ----------------------------- GtkBox ------------------------------ */
GladeWidget *
......@@ -3541,9 +3572,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);
......@@ -3776,9 +3804,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);
......@@ -3822,9 +3847,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);
......@@ -4403,9 +4425,6 @@ void
glade_gtk_button_read_widget (GladeWidgetAdaptor * adaptor,
GladeWidget * widget, GladeXmlNode * node)
{
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;