summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTristan Van Berkom <tvb@src.gnome.org>2008-10-16 14:31:42 +0000
committerTristan Van Berkom <tvb@src.gnome.org>2008-10-16 14:31:42 +0000
commit4f1e473e0809ddd33e7e58de401f56b8b27516b1 (patch)
treeedf270fdac8f422c05042a5b2fcf243113210b53
parent9c7ab5ccecad6a33be739241f8d77a6fcf820f97 (diff)
downloadglade-4f1e473e0809ddd33e7e58de401f56b8b27516b1.tar.gz
Encapsulated name tracking mechanism
* gladeui/Makefile.am, gladeui/glade-name-context.[ch]: Encapsulated name tracking mechanism * gladeui/glade-project.c, gladeui/glade-command.c: Now added a naming policy to the project with prefs and load/save support + a glade command to set it - also revamped the prefs dialog, it also pops up automatically for new projects. * gladeui/glade-editor.c, gladeui/glade-editor-property.c, gladeui/glade-property-class.c, gladeui/glade-property.c, gladeui/glade-widget.c: All effected since now glade_property_class_make_gvalue_from_string () needs a GladeWidget argument to do hierachic context sensitive searches... that and naming is much cleaner now. * src/glade-window.c: remember to pass ownership of the project to the app. * plugins/gtk+/glade-gtk.c, plugins/gtk+/glade-column-types.c, plugins/gtk+/glade-model-data.c: BEWARE: Dangerous and still a work in progress. svn path=/trunk/; revision=1972
-rw-r--r--ChangeLog28
-rw-r--r--gladeui/Makefile.am8
-rw-r--r--gladeui/glade-app.c13
-rw-r--r--gladeui/glade-command.c153
-rw-r--r--gladeui/glade-command.h3
-rw-r--r--gladeui/glade-editor-property.c20
-rw-r--r--gladeui/glade-editor.c4
-rw-r--r--gladeui/glade-name-context.c241
-rw-r--r--gladeui/glade-name-context.h34
-rw-r--r--gladeui/glade-project.c2579
-rw-r--r--gladeui/glade-project.h39
-rw-r--r--gladeui/glade-property-class.c31
-rw-r--r--gladeui/glade-property-class.h9
-rw-r--r--gladeui/glade-property.c5
-rw-r--r--gladeui/glade-utils.c9
-rw-r--r--gladeui/glade-utils.h6
-rw-r--r--gladeui/glade-widget.c19
-rw-r--r--gladeui/glade-xml-utils.h7
-rw-r--r--plugins/gnome/glade-gnome.c2
-rw-r--r--plugins/gtk+/glade-column-types.c166
-rw-r--r--plugins/gtk+/glade-gtk.c14
-rw-r--r--plugins/gtk+/glade-model-data.c84
-rw-r--r--plugins/gtk+/gtk+.xml.in6
-rw-r--r--src/glade-window.c10
24 files changed, 2254 insertions, 1236 deletions
diff --git a/ChangeLog b/ChangeLog
index 88fca9c5..e6aa841a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+2008-10-16 Tristan Van Berkom <tvb@gnome.org>
+
+ * gladeui/Makefile.am, gladeui/glade-name-context.[ch]: Encapsulated name tracking mechanism
+
+ * gladeui/glade-project.c, gladeui/glade-command.c: Now added a naming policy to the project
+ with prefs and load/save support + a glade command to set it - also revamped the prefs dialog,
+ it also pops up automatically for new projects.
+
+ * gladeui/glade-editor.c, gladeui/glade-editor-property.c, gladeui/glade-property-class.c,
+ gladeui/glade-property.c, gladeui/glade-widget.c: All effected since now
+ glade_property_class_make_gvalue_from_string () needs a GladeWidget argument to do
+ hierachic context sensitive searches... that and naming is much cleaner now.
+
+ * src/glade-window.c: remember to pass ownership of the project to the app.
+
+ * plugins/gtk+/glade-gtk.c, plugins/gtk+/glade-column-types.c, plugins/gtk+/glade-model-data.c:
+ BEWARE: Dangerous and still a work in progress.
+
+2008-10-10 Tristan Van Berkom <tvb@gnome.org>
+
+ * gladeui/glade-xml-utils.c, gladeui/glade-property-class.[ch]: Added
+ new "needs-sync" property
+
+ * gladeui/glade-widget.c: glade_widget_sync_custom_props(): also sync
+ props marked as needs-sync.
+
+ * plugins/gtk+/gtk+.xml.in: GtkTable:n-rows/n-columns marked as "needs-sync"
+
2008-09-30 Tristan Van Berkom <tvb@gnome.org>
* gladeui/glade-property.[ch], gladeui/glade-command.[ch],
diff --git a/gladeui/Makefile.am b/gladeui/Makefile.am
index cd53741d..0e96567c 100644
--- a/gladeui/Makefile.am
+++ b/gladeui/Makefile.am
@@ -62,7 +62,8 @@ libgladeui_1_la_SOURCES = \
glade-catalog.h \
glade-marshallers.h \
glade-accumulators.h \
- glade-widget-action.c
+ glade-widget-action.c \
+ glade-name-context.c
libgladeui_1_la_CPPFLAGS = \
$(common_defines) \
@@ -110,8 +111,9 @@ libgladeuiinclude_HEADERS = \
glade-xml-utils.h \
glade-signal.h \
glade-cursor.h \
- glade-catalog.h \
- glade-widget-action.h
+ glade-catalog.h \
+ glade-widget-action.h \
+ glade-name-context.h
if PLATFORM_WIN32
diff --git a/gladeui/glade-app.c b/gladeui/glade-app.c
index ae342bb9..78c283dc 100644
--- a/gladeui/glade-app.c
+++ b/gladeui/glade-app.c
@@ -936,19 +936,19 @@ glade_app_add_project (GladeProject *project)
g_return_if_fail (GLADE_IS_PROJECT (project));
+ app = glade_app_get ();
+
/* If the project was previously loaded, don't re-load */
- if (glade_app_is_project_loaded (glade_project_get_path (project)))
+ if (g_list_find (app->priv->projects, project) != NULL)
{
glade_app_set_project (project);
return;
}
glade_app_update_instance_count (project);
-
- app = glade_app_get ();
-
- g_object_ref (project);
- app->priv->projects = g_list_append (app->priv->projects, project);
+ /* Take a reference for GladeApp here... */
+ app->priv->projects = g_list_append (app->priv->projects,
+ g_object_ref (project));
/* connect to the project signals so that the editor can be updated */
g_signal_connect (G_OBJECT (project), "selection_changed",
@@ -1022,7 +1022,6 @@ glade_app_remove_project (GladeProject *project)
* that point.
*/
g_object_unref (project);
-
}
diff --git a/gladeui/glade-command.c b/gladeui/glade-command.c
index 880244b2..8d085000 100644
--- a/gladeui/glade-command.c
+++ b/gladeui/glade-command.c
@@ -49,6 +49,7 @@
#include "glade-signal.h"
#include "glade-app.h"
#include "glade-fixed.h"
+#include "glade-name-context.h"
/* Concerning placeholders: we do not hold any reference to placeholders,
* placeholders that are supplied by the backend are not reffed, placeholders
@@ -771,7 +772,8 @@ glade_command_set_name_execute (GladeCommand *cmd)
g_return_val_if_fail (me->widget != NULL, TRUE);
g_return_val_if_fail (me->name != NULL, TRUE);
- glade_widget_set_name (me->widget, me->name);
+ glade_project_set_widget_name (me->widget->project,
+ me->widget, me->name);
tmp = me->old_name;
me->old_name = me->name;
@@ -1621,7 +1623,10 @@ glade_command_create(GladeWidgetAdaptor *adaptor, GladeWidget *parent, GladePlac
g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
/* attempt to create the widget -- widget may be null, e.g. the user clicked cancel on a query */
- widget = glade_widget_adaptor_create_widget(adaptor, TRUE, "parent", parent, "project", project, NULL);
+ widget = glade_widget_adaptor_create_widget(adaptor, TRUE,
+ "parent", parent,
+ "project", project,
+ NULL);
if (widget == NULL)
{
return NULL;
@@ -2354,3 +2359,147 @@ glade_command_set_project_format (GladeProject *project,
}
+
+/******************************************************************************
+ *
+ * set project naming policy
+ *
+ * This command sets the naming policy on the project.
+ *
+ *****************************************************************************/
+
+typedef struct {
+ GladeCommand parent;
+ GladeProject *project;
+ GladeNamingPolicy policy;
+ GladeNamingPolicy old_policy;
+ gboolean run_once;
+} GladeCommandSetPolicy;
+
+
+GLADE_MAKE_COMMAND (GladeCommandSetPolicy, glade_command_set_policy);
+#define GLADE_COMMAND_SET_POLICY_TYPE (glade_command_set_policy_get_type ())
+#define GLADE_COMMAND_SET_POLICY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GLADE_COMMAND_SET_POLICY_TYPE, GladeCommandSetPolicy))
+#define GLADE_COMMAND_SET_POLICY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GLADE_COMMAND_SET_POLICY_TYPE, GladeCommandSetPolicyClass))
+#define GLADE_IS_COMMAND_SET_POLICY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GLADE_COMMAND_SET_POLICY_TYPE))
+#define GLADE_IS_COMMAND_SET_POLICY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GLADE_COMMAND_SET_POLICY_TYPE))
+
+static gboolean
+glade_command_set_policy_execute(GladeCommand *cmd)
+{
+ GladeCommandSetPolicy *me = (GladeCommandSetPolicy *)cmd;
+ GladeNamingPolicy policy;
+
+ /* sanity check */
+ g_return_val_if_fail (me != NULL, TRUE);
+ g_return_val_if_fail (me->project != NULL, TRUE);
+
+ /* set the new policy */
+ glade_project_set_naming_policy (me->project, me->policy, me->run_once == FALSE);
+
+ /* swap the current values with the old values to prepare for undo */
+ policy = me->policy;
+ me->policy = me->old_policy;
+ me->old_policy = policy;
+
+ me->run_once = TRUE;
+
+ return TRUE;
+}
+
+static gboolean
+glade_command_set_policy_undo(GladeCommand *cmd)
+{
+ return glade_command_set_policy_execute(cmd);
+}
+
+static void
+glade_command_set_policy_finalize(GObject *obj)
+{
+/* GladeCommandSetPolicy *me; */
+
+ g_return_if_fail(GLADE_IS_COMMAND_SET_POLICY(obj));
+
+ glade_command_finalize(obj);
+}
+
+static gboolean
+glade_command_set_policy_unifies (GladeCommand *this_cmd, GladeCommand *other_cmd)
+{
+/* GladeCommandSetPolicy *cmd1; */
+/* GladeCommandSetPolicy *cmd2; */
+
+ return FALSE;
+}
+
+static void
+glade_command_set_policy_collapse (GladeCommand *this_cmd, GladeCommand *other_cmd)
+{
+ /* this command is the one that will be used for an undo of the sequence of like commands */
+ //GladeCommandSetPolicy *this = GLADE_COMMAND_SET_POLICY (this_cmd);
+
+ /* the other command contains the values that will be used for a redo */
+ //GladeCommandSetPolicy *other = GLADE_COMMAND_SET_POLICY (other_cmd);
+
+ g_return_if_fail (GLADE_IS_COMMAND_SET_POLICY (this_cmd) && GLADE_IS_COMMAND_SET_POLICY (other_cmd));
+
+ /* no unify/collapse */
+}
+
+/**
+ * glade_command_set_project_naming_policy:
+ * @project: a #GladeProject
+ * @policy: the #GladeNamingPolicy
+ *
+ * Sets the naming policy of a project
+ */
+void
+glade_command_set_project_naming_policy (GladeProject *project,
+ GladeNamingPolicy policy)
+
+{
+ GladeCommandSetPolicy *me;
+
+ g_return_if_fail (GLADE_IS_PROJECT (project));
+
+ if (glade_project_get_naming_policy (project) != policy)
+ {
+ gchar *prj_name = glade_project_get_name (project);
+ glade_command_push_group (_("Setting %s to use a %s naming policy"),
+ prj_name,
+ policy == GLADE_POLICY_PROJECT_WIDE ?
+ "project wide" : "toplevel contextual");
+ g_free (prj_name);
+
+ /* load up the command */
+ me = g_object_new(GLADE_COMMAND_SET_POLICY_TYPE, NULL);
+ me->project = project;
+ me->policy = policy;
+ me->old_policy = glade_project_get_naming_policy (project);
+
+ me->run_once = FALSE;
+
+ GLADE_COMMAND(me)->description = g_strdup_printf("dummy string");
+
+ glade_command_check_group(GLADE_COMMAND(me));
+
+ /* execute the command and push it on the stack if successful
+ * this sets the actual policy
+ */
+ if (glade_command_set_policy_execute(GLADE_COMMAND(me)))
+ {
+ glade_project_push_undo(glade_app_get_project(), GLADE_COMMAND(me));
+ }
+ else
+ {
+ g_object_unref(G_OBJECT(me));
+ }
+
+ glade_command_pop_group ();
+
+ glade_editor_refresh (glade_app_get_editor ());
+ }
+}
+
+
+
diff --git a/gladeui/glade-command.h b/gladeui/glade-command.h
index b4d3cf06..51948024 100644
--- a/gladeui/glade-command.h
+++ b/gladeui/glade-command.h
@@ -90,6 +90,9 @@ void glade_command_collapse (GladeCommand *command,
void glade_command_set_project_format (GladeProject *project,
GladeProjectFormat fmt);
+void glade_command_set_project_naming_policy (GladeProject *project,
+ GladeNamingPolicy policy);
+
/************************** properties *********************************/
void glade_command_set_property (GladeProperty *property,
diff --git a/gladeui/glade-editor-property.c b/gladeui/glade-editor-property.c
index 71f55ae5..a1ad9723 100644
--- a/gladeui/glade-editor-property.c
+++ b/gladeui/glade-editor-property.c
@@ -113,8 +113,9 @@ glade_editor_property_commit (GladeEditorProperty *eprop,
}
-void glade_editor_property_commit_no_callback (GladeEditorProperty *eprop,
- GValue *value)
+void
+glade_editor_property_commit_no_callback (GladeEditorProperty *eprop,
+ GValue *value)
{
g_return_if_fail (GLADE_IS_EDITOR_PROPERTY (eprop));
@@ -1601,7 +1602,7 @@ glade_eprop_text_changed_common (GladeEditorProperty *eprop,
eprop->property->klass->pspec->value_type == G_TYPE_VALUE_ARRAY)
{
val = glade_property_class_make_gvalue_from_string
- (eprop->property->klass, text, NULL);
+ (eprop->property->klass, text, NULL, NULL);
}
else
{
@@ -2228,7 +2229,7 @@ glade_eprop_resource_entry_activate (GtkEntry *entry, GladeEditorProperty *eprop
{
GladeProject *project = glade_widget_get_project (eprop->property->widget);
GValue *value = glade_property_class_make_gvalue_from_string
- (eprop->klass, gtk_entry_get_text(entry), project);
+ (eprop->klass, gtk_entry_get_text(entry), project, eprop->property->widget);
/* Set project resource here where we still have the fullpath.
*/
@@ -2287,7 +2288,7 @@ glade_eprop_resource_select_file (GtkButton *button, GladeEditorProperty *eprop)
basename = g_path_get_basename (file);
value = glade_property_class_make_gvalue_from_string
- (eprop->klass, basename, project);
+ (eprop->klass, basename, project, eprop->property->widget);
glade_editor_property_commit (eprop, value);
@@ -2824,7 +2825,7 @@ glade_eprop_object_show_dialog (GtkWidget *dialog_button,
if (selected)
{
GValue *value = glade_property_class_make_gvalue_from_string
- (eprop->klass, selected->name, project);
+ (eprop->klass, selected->name, project, eprop->property->widget);
/* Unparent the widget so we can reuse it for this property */
if (eprop->klass->parentless_widget)
@@ -2880,9 +2881,12 @@ glade_eprop_object_show_dialog (GtkWidget *dialog_button,
if ((new_widget = glade_command_create (create_adaptor, NULL, NULL, project)) != NULL)
{
value = glade_property_class_make_gvalue_from_string
- (eprop->klass, new_widget->name, project);
+ (eprop->klass, new_widget->name, project, NULL);
glade_editor_property_commit (eprop, value);
+
+ g_value_unset (value);
+ g_free (value);
}
glade_command_pop_group ();
@@ -2890,7 +2894,7 @@ glade_eprop_object_show_dialog (GtkWidget *dialog_button,
else if (res == GLADE_RESPONSE_CLEAR)
{
GValue *value = glade_property_class_make_gvalue_from_string
- (eprop->klass, NULL, project);
+ (eprop->klass, NULL, project, eprop->property->widget);
glade_editor_property_commit (eprop, value);
diff --git a/gladeui/glade-editor.c b/gladeui/glade-editor.c
index ed7f3aa3..4c2713c5 100644
--- a/gladeui/glade-editor.c
+++ b/gladeui/glade-editor.c
@@ -18,6 +18,7 @@
*
* Authors:
* Chema Celorio <chema@celorio.com>
+ * Tristan Van Berkom <tvb@gnome.org>
*/
@@ -503,7 +504,8 @@ glade_editor_widget_name_changed (GtkWidget *editable, GladeEditor *editor)
widget = editor->loaded_widget;
new_name = gtk_editable_get_chars (GTK_EDITABLE (editable), 0, -1);
- if (!glade_project_get_widget_by_name (widget->project, new_name))
+
+ if (glade_project_available_widget_name (widget->project, widget, new_name))
glade_command_set_name (widget, new_name);
g_free (new_name);
}
diff --git a/gladeui/glade-name-context.c b/gladeui/glade-name-context.c
new file mode 100644
index 00000000..d4b52918
--- /dev/null
+++ b/gladeui/glade-name-context.c
@@ -0,0 +1,241 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * glade-name-context.c
+ *
+ * Copyright (C) 2008 Tristan Van Berkom.
+ *
+ * Authors:
+ * Tristan Van Berkom <tvb@gnome.org>
+ *
+ * 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.
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "glade-id-allocator.h"
+#include "glade-name-context.h"
+
+struct _GladeNameContext {
+ GHashTable *name_allocators;
+
+ GHashTable *names;
+};
+
+
+
+GladeNameContext *
+glade_name_context_new (void)
+{
+ GladeNameContext *context = g_new0 (GladeNameContext, 1);
+
+ context->name_allocators = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify) glade_id_allocator_destroy);
+
+ context->names = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ NULL);
+
+ return context;
+}
+
+void
+glade_name_context_destroy (GladeNameContext *context)
+{
+ g_return_if_fail (context != NULL);
+
+ g_hash_table_destroy (context->name_allocators);
+ g_hash_table_destroy (context->names);
+ g_free (context);
+}
+
+gchar *
+glade_name_context_new_name (GladeNameContext *context,
+ const gchar *base_name)
+{
+ GladeIDAllocator *id_allocator;
+ const gchar *number;
+ gchar *name = NULL, *freeme = NULL;
+ guint i = 1;
+
+ g_return_val_if_fail (context != NULL, NULL);
+ g_return_val_if_fail (base_name && base_name[0], NULL);
+
+ number = base_name + strlen (base_name);
+ while (number > base_name && g_ascii_isdigit (number[-1]))
+ --number;
+
+ if (*number)
+ {
+ freeme = g_strndup (base_name, number - base_name);
+ base_name = freeme;
+ }
+
+ id_allocator = g_hash_table_lookup (context->name_allocators, base_name);
+
+ if (id_allocator == NULL)
+ {
+ id_allocator = glade_id_allocator_new ();
+ g_hash_table_insert (context->name_allocators,
+ g_strdup (base_name), id_allocator);
+ }
+
+ do
+ {
+ g_free (name);
+ i = glade_id_allocator_allocate (id_allocator);
+ name = g_strdup_printf ("%s%u", base_name, i);
+ }
+ while (glade_name_context_has_name (context, name));
+
+ g_free (freeme);
+ return name;
+}
+
+gchar *
+glade_name_context_dual_new_name (GladeNameContext *context,
+ GladeNameContext *another_context,
+ const gchar *base_name)
+{
+ GladeIDAllocator *id_allocator;
+ const gchar *number;
+ gchar *name = NULL, *freeme = NULL;
+ guint i = 1;
+
+ g_return_val_if_fail (context != NULL, NULL);
+ g_return_val_if_fail (another_context != NULL, NULL);
+ g_return_val_if_fail (base_name && base_name[0], NULL);
+
+ number = base_name + strlen (base_name);
+ while (number > base_name && g_ascii_isdigit (number[-1]))
+ --number;
+
+ if (*number)
+ {
+ freeme = g_strndup (base_name, number - base_name);
+ base_name = freeme;
+ }
+
+ id_allocator = g_hash_table_lookup (context->name_allocators, base_name);
+
+ if (id_allocator == NULL)
+ {
+ id_allocator = glade_id_allocator_new ();
+ g_hash_table_insert (context->name_allocators,
+ g_strdup (base_name), id_allocator);
+ }
+
+ do
+ {
+ g_free (name);
+ i = glade_id_allocator_allocate (id_allocator);
+ name = g_strdup_printf ("%s%u", base_name, i);
+ }
+ while (glade_name_context_has_name (context, name) ||
+ glade_name_context_has_name (another_context, name));
+
+ g_free (freeme);
+ return name;
+}
+
+guint
+glade_name_context_n_names (GladeNameContext *context)
+{
+ g_return_val_if_fail (context != NULL, FALSE);
+
+ return g_hash_table_size (context->names);
+}
+
+gboolean
+glade_name_context_has_name (GladeNameContext *context,
+ const gchar *name)
+{
+ g_return_val_if_fail (context != NULL, FALSE);
+ g_return_val_if_fail (name && name[0], FALSE);
+
+ return (g_hash_table_lookup (context->names, name) != NULL);
+}
+
+gboolean
+glade_name_context_add_name (GladeNameContext *context,
+ const gchar *name)
+{
+ gboolean ret = FALSE;
+
+ g_return_val_if_fail (context != NULL, FALSE);
+ g_return_val_if_fail (name && name[0], FALSE);
+
+ if (!glade_name_context_has_name (context, name))
+ {
+ g_hash_table_insert (context->names, g_strdup (name), GINT_TO_POINTER (TRUE));
+ ret = TRUE;
+ }
+
+ return ret;
+}
+
+void
+glade_name_context_release_name (GladeNameContext *context,
+ const gchar *name)
+{
+
+ const gchar *first_number = name;
+ gchar *end_number, *base_name;
+ GladeIDAllocator *id_allocator;
+ gunichar ch;
+ gint id;
+
+ g_return_if_fail (context != NULL);
+ g_return_if_fail (name && name[0]);
+
+ /* Remove from name hash first... */
+ g_hash_table_remove (context->names, name);
+
+ do
+ {
+ ch = g_utf8_get_char (first_number);
+
+ if (ch == 0 || g_unichar_isdigit (ch))
+ break;
+
+ first_number = g_utf8_next_char (first_number);
+ }
+ while (TRUE);
+
+ /* if there is a number - then we have to unallocate it... */
+ if (ch == 0) return;
+
+
+ base_name = g_strdup (name);
+ *(base_name + (first_number - name)) = 0;
+
+ if ((id_allocator =
+ g_hash_table_lookup (context->name_allocators, base_name)) != NULL)
+ {
+
+ id = (int) strtol (first_number, &end_number, 10);
+ if (*end_number == 0)
+ glade_id_allocator_release (id_allocator, id);
+ }
+
+ g_free (base_name);
+}
diff --git a/gladeui/glade-name-context.h b/gladeui/glade-name-context.h
new file mode 100644
index 00000000..088e5023
--- /dev/null
+++ b/gladeui/glade-name-context.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+#ifndef __GLADE_NAME_CONTEXT_H__
+#define __GLADE_NAME_CONTEXT_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GladeNameContext GladeNameContext;
+
+GladeNameContext *glade_name_context_new (void);
+void glade_name_context_destroy (GladeNameContext *context);
+
+gchar *glade_name_context_new_name (GladeNameContext *context,
+ const gchar *base_name);
+
+gchar *glade_name_context_dual_new_name (GladeNameContext *context,
+ GladeNameContext *another_context,
+ const gchar *base_name);
+
+guint glade_name_context_n_names (GladeNameContext *context);
+
+gboolean glade_name_context_has_name (GladeNameContext *context,
+ const gchar *name);
+
+gboolean glade_name_context_add_name (GladeNameContext *context,
+ const gchar *name);
+
+void glade_name_context_release_name (GladeNameContext *context,
+ const gchar *name);
+
+G_END_DECLS
+
+#endif /* __GLADE_NAME_CONTEXT_H__ */
diff --git a/gladeui/glade-project.c b/gladeui/glade-project.c
index c2c9ed4c..fd94cc7f 100644
--- a/gladeui/glade-project.c
+++ b/gladeui/glade-project.c
@@ -48,6 +48,7 @@
#include "glade-project.h"
#include "glade-command.h"
+#include "glade-name-context.h"
#define GLADE_PROJECT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GLADE_TYPE_PROJECT, GladeProjectPrivate))
@@ -105,12 +106,14 @@ struct _GladeProjectPrivate
* of #GtkWidget items.
*/
+ GladeNameContext *toplevel_names; /* Context for uniqueness of names at the toplevel */
+ GList *toplevels; /* List of toplevels with thier own naming contexts */
+
+
gboolean has_selection; /* Whether the project has a selection */
GList *undo_stack; /* A stack with the last executed commands */
GList *prev_redo_item; /* Points to the item previous to the redo items */
- GHashTable *widget_names_allocator; /* hash table with the used widget names */
- GHashTable *widget_old_names; /* widget -> old name of the widget */
gboolean first_modification_is_na; /* the flag indicates that the first_modification item has been lost */
@@ -135,14 +138,83 @@ struct _GladeProjectPrivate
GHashTable *target_versions_minor; /* target versions by catalog */
GList *loaded_factory_files;
+
+ GladeNamingPolicy naming_policy; /* What rules apply to widget names */
+/* Control on the preferences dialog to update buttons etc when properties change */
+ GtkWidget *prefs_dialog;
+ GtkWidget *glade_radio;
+ GtkWidget *builder_radio;
+ GtkWidget *project_wide_radio;
+ GtkWidget *toplevel_contextual_radio;
+ GHashTable *target_radios;
+
};
typedef struct {
+ GladeWidget *toplevel;
+ GladeNameContext *names;
+} TopLevelInfo;
+
+typedef struct {
gchar *stock;
gchar *filename;
} StockFilePair;
+static void glade_project_set_target_version (GladeProject *project,
+ const gchar *catalog,
+ gint major,
+ gint minor);
+static void glade_project_get_target_version (GladeProject *project,
+ const gchar *catalog,
+ gint *major,
+ gint *minor);
+
+static void glade_project_target_version_for_adaptor (GladeProject *project,
+ GladeWidgetAdaptor *adaptor,
+ gint *major,
+ gint *minor);
+
+static void glade_project_set_readonly (GladeProject *project,
+ gboolean readonly);
+
+
+static gboolean glade_project_verify (GladeProject *project,
+ gboolean saving);
+
+static void glade_project_verify_adaptor (GladeProject *project,
+ GladeWidgetAdaptor *adaptor,
+ const gchar *path_name,
+ GString *string,
+ gboolean saving,
+ gboolean forwidget,
+ GladeSupportMask *mask);
+
+static void glade_project_move_resources (GladeProject *project,
+ const gchar *old_dir,
+ const gchar *new_dir);
+
+static void glade_project_sync_resources_for_widget (GladeProject *project,
+ GladeProject *prev_project,
+ GladeWidget *gwidget,
+ gboolean remove);
+
+GladeWidget *search_ancestry_by_name (GladeWidget *toplevel,
+ const gchar *name);
+
+static GtkWidget *glade_project_build_prefs_dialog (GladeProject *project);
+
+static void format_libglade_button_clicked (GtkWidget *widget,
+ GladeProject *project);
+static void format_builder_button_clicked (GtkWidget *widget,
+ GladeProject *project);
+static void policy_project_wide_button_clicked (GtkWidget *widget,
+ GladeProject *project);
+static void policy_toplevel_contextual_button_clicked (GtkWidget *widget,
+ GladeProject *project);
+static void target_button_clicked (GtkWidget *widget,
+ GladeProject *project);
+
static guint glade_project_signals[LAST_SIGNAL] = {0};
static GladeIDAllocator *unsaved_number_allocator = NULL;
@@ -228,6 +300,10 @@ static void
glade_project_finalize (GObject *object)
{
GladeProject *project = GLADE_PROJECT (object);
+ GList *list;
+ TopLevelInfo *tinfo;
+
+ gtk_widget_destroy (project->priv->prefs_dialog);
g_free (project->priv->path);
g_free (project->priv->comment);
@@ -235,11 +311,20 @@ glade_project_finalize (GObject *object)
if (project->priv->unsaved_number > 0)
glade_id_allocator_release (get_unsaved_number_allocator (), project->priv->unsaved_number);
- g_hash_table_destroy (project->priv->widget_names_allocator);
- g_hash_table_destroy (project->priv->widget_old_names);
g_hash_table_destroy (project->priv->resources);
g_hash_table_destroy (project->priv->target_versions_major);
g_hash_table_destroy (project->priv->target_versions_minor);
+ g_hash_table_destroy (project->priv->target_radios);
+
+ glade_name_context_destroy (project->priv->toplevel_names);
+
+ for (list = project->priv->toplevels; list; list = list->next)
+ {
+ tinfo = list->data;
+ glade_name_context_destroy (tinfo->names);
+ g_free (tinfo);
+ }
+ g_list_free (project->priv->toplevels);
G_OBJECT_CLASS (glade_project_parent_class)->finalize (object);
}
@@ -500,251 +585,10 @@ glade_project_changed_impl (GladeProject *project,
glade_app_update_ui ();
}
+
/*******************************************************************
- Initializers
+ Class Initializers
*******************************************************************/
-
-static void
-glade_project_get_target_version (GladeProject *project,
- const gchar *catalog,
- gint *major,
- gint *minor)
-{
- *major = GPOINTER_TO_INT
- (g_hash_table_lookup (project->priv->target_versions_major,
- catalog));
- *minor = GPOINTER_TO_INT
- (g_hash_table_lookup (project->priv->target_versions_minor,
- catalog));
-}
-
-static void
-glade_project_target_version_for_adaptor (GladeProject *project,
- GladeWidgetAdaptor *adaptor,
- gint *major,
- gint *minor)
-{
- gchar *catalog = NULL;
-
- g_object_get (adaptor, "catalog", &catalog, NULL);
- glade_project_get_target_version (project, catalog, major, minor);
- g_free (catalog);
-}
-
-static void
-glade_project_verify_adaptor (GladeProject *project,
- GladeWidgetAdaptor *adaptor,
- const gchar *path_name,
- GString *string,
- gboolean saving,
- gboolean forwidget,
- GladeSupportMask *mask)
-{
- GladeSupportMask support_mask = GLADE_SUPPORT_OK;
- GladeWidgetAdaptor *adaptor_iter;
- gint target_major, target_minor;
- gchar *catalog = NULL;
-
- for (adaptor_iter = adaptor; adaptor_iter;
- adaptor_iter = glade_widget_adaptor_get_parent_adaptor (adaptor_iter))
- {
-
- g_object_get (adaptor_iter, "catalog", &catalog, NULL);
- glade_project_target_version_for_adaptor (project, adaptor_iter,
- &target_major,
- &target_minor);
-
- if (target_major < GWA_VERSION_SINCE_MAJOR (adaptor_iter) ||
- (target_major == GWA_VERSION_SINCE_MAJOR (adaptor_iter) &&
- target_minor < GWA_VERSION_SINCE_MINOR (adaptor_iter)))
- {
- if (forwidget)
- {
- /* translators: reffers to a widget
- * introduced in toolkit version '%s %d.%d',
- * and a project targeting toolkit verion '%s %d.%d' */
- g_string_append_printf
- (string,
- _("This widget was introduced in %s %d.%d "
- "project targets %s %d.%d"),
- catalog,
- GWA_VERSION_SINCE_MAJOR (adaptor_iter),
- GWA_VERSION_SINCE_MINOR (adaptor_iter),
- catalog, target_major, target_minor);
- }
- else
- /* translators: reffers to a widget '[%s]'
- * introduced in toolkit version '%s %d.%d' */
- g_string_append_printf
- (string,
- _("[%s] Object class '%s' was introduced in %s %d.%d\n"),
- path_name, adaptor_iter->title, catalog,
- GWA_VERSION_SINCE_MAJOR (adaptor_iter),
- GWA_VERSION_SINCE_MINOR (adaptor_iter));
-
- support_mask |= GLADE_SUPPORT_MISMATCH;
- }
-
- if (project->priv->format == GLADE_PROJECT_FORMAT_GTKBUILDER &&
- GWA_LIBGLADE_ONLY (adaptor_iter))
- {
- if (forwidget)
- {
- if (string->len)
- g_string_append (string, "\n");
- g_string_append_printf
- (string,
- _("This widget is only supported in libglade format"));
- }
- else
- /* translators: reffers to a widget '[%s]'
- * loaded from toolkit version '%s %d.%d' */
- g_string_append_printf
- (string,
- _("[%s] Object class '%s' from %s %d.%d "
- "is only supported in libglade format\n"),
- path_name, adaptor_iter->title, catalog,
- target_major, target_minor);
-
- support_mask |= GLADE_SUPPORT_LIBGLADE_ONLY;
- }
- else if (project->priv->format == GLADE_PROJECT_FORMAT_LIBGLADE &&
- GWA_LIBGLADE_UNSUPPORTED (adaptor_iter))
- {
- if (forwidget)
- {
- if (string->len)
- g_string_append (string, "\n");
- g_string_append_printf
- (string,
- _("This widget is not supported in libglade format"));
- }
- else
- /* translators: reffers to a widget '[%s]'
- * loaded from toolkit version '%s %d.%d' */
- g_string_append_printf
- (string,
- _("[%s] Object class '%s' from %s %d.%d "
- "is not supported in libglade format\n"),
- path_name, adaptor_iter->title, catalog,
- target_major, target_minor);
-
- support_mask |= GLADE_SUPPORT_LIBGLADE_UNSUPPORTED;
- }
-
- if (!saving && GWA_DEPRECATED (adaptor_iter))
- {
- if (forwidget)
- {
- if (string->len)
- g_string_append (string, "\n");
- g_string_append_printf
- (string, _("This widget is deprecated"));
- }
- else
- /* translators: reffers to a widget '[%s]'
- * loaded from toolkit version '%s %d.%d' */
- g_string_append_printf
- (string,
- _("[%s] Object class '%s' from %s %d.%d "
- "is deprecated\n"),
- path_name, adaptor_iter->title, catalog,
- target_major, target_minor);
-
- support_mask |= GLADE_SUPPORT_DEPRECATED;
- }
- g_free (catalog);
- }
- if (mask)
- *mask = support_mask;
-}
-
-/**
- * glade_project_verify_widget_adaptor:
- * @project: A #GladeProject
- * @adaptor: the #GladeWidgetAdaptor to verify
- * @mask: a return location for a #GladeSupportMask
- *
- * Checks the supported state of this widget adaptor
- * and generates a string to show in the UI describing why.
- *
- * Returns: A newly allocated string
- */
-gchar *
-glade_project_verify_widget_adaptor (GladeProject *project,
- GladeWidgetAdaptor *adaptor,
- GladeSupportMask *mask)
-{
- GString *string = g_string_new (NULL);
- gchar *ret = NULL;
-
- glade_project_verify_adaptor (project, adaptor, NULL,
- string, FALSE, TRUE, mask);
-
- /* there was a '\0' byte... */
- if (string->len > 0)
- {
- ret = string->str;
- g_string_free (string, FALSE);
- }
- else
- g_string_free (string, TRUE);
-
-
- return ret;
-}
-
-
-/**
- * glade_project_verify_project_for_ui:
- * @project: A #GladeProject
- *
- * Checks the project and updates warning strings in the UI
- */
-void
-glade_project_verify_project_for_ui (GladeProject *project)
-{
- GList *list;
- GladeWidget *widget;
- gchar *warning;
-
- /* Sync displayable info here */
- for (list = project->priv->objects; list; list = list->next)
- {
- widget = glade_widget_get_from_gobject (list->data);
-
- warning = glade_project_verify_widget_adaptor (project, widget->adaptor, NULL);
- glade_widget_set_support_warning (widget, warning);
-
- if (warning)
- g_free (warning);
-
- glade_project_verify_properties (widget);
- }
-
- /* refresh palette if this is the active project */
- if (project == glade_app_get_project ())
- glade_palette_refresh (glade_app_get_palette ());
-}
-
-static void
-glade_project_set_target_version (GladeProject *project,
- const gchar *catalog,
- gint major,
- gint minor)
-{
-
- g_hash_table_insert (project->priv->target_versions_major,
- g_strdup (catalog),
- GINT_TO_POINTER (major));
- g_hash_table_insert (project->priv->target_versions_minor,
- g_strdup (catalog),
- GINT_TO_POINTER (minor));
-
- glade_project_verify_project_for_ui (project);
-
-}
-
static void
glade_project_init (GladeProject *project)
{
@@ -764,12 +608,8 @@ glade_project_init (GladeProject *project)
priv->first_modification = NULL;
priv->first_modification_is_na = FALSE;
- priv->widget_names_allocator = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- (GDestroyNotify) glade_id_allocator_destroy);
-
- priv->widget_old_names = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_free);
+ priv->toplevel_names = glade_name_context_new ();
+ priv->naming_policy = GLADE_POLICY_PROJECT_WIDE;
priv->accel_group = NULL;
@@ -801,6 +641,11 @@ glade_project_init (GladeProject *project)
glade_catalog_get_major_version (catalog),
glade_catalog_get_minor_version (catalog));
}
+
+ priv->target_radios = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+ priv->prefs_dialog = glade_project_build_prefs_dialog (project);
+
}
static void
@@ -1060,37 +905,9 @@ glade_project_class_init (GladeProjectClass *klass)
}
/*******************************************************************
- API
+ Loading project code here
*******************************************************************/
-static void
-glade_project_set_readonly (GladeProject *project, gboolean readonly)
-{
- g_assert (GLADE_IS_PROJECT (project));
-
- if (project->priv->readonly != readonly)
- {
- project->priv->readonly = readonly;
- g_object_notify (G_OBJECT (project), "read-only");
- }
-}
-
-/**
- * glade_project_get_readonly:
- * @project: a #GladeProject
- *
- * Gets whether the project is read only or not
- *
- * Returns: TRUE if project is read only
- */
-gboolean
-glade_project_get_readonly (GladeProject *project)
-{
- g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
-
- return project->priv->readonly;
-}
-
/**
* glade_project_new:
*
@@ -1101,145 +918,9 @@ glade_project_get_readonly (GladeProject *project)
GladeProject *
glade_project_new (void)
{
- return g_object_new (GLADE_TYPE_PROJECT, NULL);
-}
-
-
-static void
-glade_project_fix_object_props (GladeProject *project)
-{
- GList *l, *ll;
- GValue *value;
- GladeWidget *gwidget;
- GladeProperty *property;
- gchar *txt;
-
- for (l = project->priv->objects; l; l = l->next)
- {
- gwidget = glade_widget_get_from_gobject (l->data);
-
- for (ll = gwidget->properties; ll; ll = ll->next)
- {
- property = GLADE_PROPERTY (ll->data);
-
- if (glade_property_class_is_object (property->klass,
- project->priv->format) &&
- (txt = g_object_get_data (G_OBJECT (property),
- "glade-loaded-object")) != NULL)
- {
- /* Parse the object list and set the property to it
- * (this magicly works for both objects & object lists)
- */
- value = glade_property_class_make_gvalue_from_string
- (property->klass, txt, project);
-
- glade_property_set_value (property, value);
-
- g_value_unset (value);
- g_free (value);
-
- g_object_set_data (G_OBJECT (property),
- "glade-loaded-object", NULL);
- }
- }
- }
-}
-
-
-static gchar *
-glade_project_read_requires_from_comment (GladeXmlNode *comment,
- gint *major,
- gint *minor)
-{
- gint maj, min;
- gchar *value, buffer[256];
- gchar *required_lib = NULL;
-
- if (!glade_xml_node_is_comment (comment))
- return FALSE;
-
- value = glade_xml_get_content (comment);
- if (value && !strncmp ("interface-requires", value, strlen ("interface-requires")))
- {
- if (sscanf (value, "interface-requires %s %d.%d", buffer, &maj, &min) == 3)
- {
- if (major) *major = maj;
- if (minor) *minor = min;
- required_lib = g_strdup (buffer);
- }
- }
- g_free (value);
-
- return required_lib;
-}
-
-
-static gboolean
-glade_project_read_requires (GladeProject *project,
- GladeXmlNode *root_node,
- const gchar *path)
-{
-
- GString *string = g_string_new (NULL);
- GladeXmlNode *node;
- gchar *required_lib = NULL;
- gboolean loadable = TRUE;
- gint major, minor;
-
- for (node = glade_xml_node_get_children_with_comments (root_node);
- node; node = glade_xml_node_next_with_comments (node))
- {
- /* Skip non "requires" tags */
- if (!(glade_xml_node_verify_silent (node, GLADE_XML_TAG_REQUIRES) ||
- (required_lib =
- glade_project_read_requires_from_comment (node, &major, &minor))))
- continue;
-
- if (!required_lib)
- {
- required_lib =
- glade_xml_get_property_string_required (node, GLADE_XML_TAG_LIB,
- NULL);
- glade_xml_get_property_version (node, GLADE_XML_TAG_VERSION,
- &major, &minor);
- }
-
- if (!required_lib) continue;
-
- /* Dont mention gtk+ as a required lib in
- * the generated glade file
- */
- if (!glade_catalog_is_loaded (required_lib))
- {
- if (!loadable)
- g_string_append (string, ", ");
-
- g_string_append (string, required_lib);
- loadable = FALSE;
- }
- else
- glade_project_set_target_version
- (project, required_lib, major, minor);
-
- g_free (required_lib);
- }
-
- if (!loadable)
- glade_util_ui_message (glade_app_get_window(),
- GLADE_UI_ERROR, NULL,
- _("Failed to load %s.\n"
- "The following required catalogs are unavailable: %s"),
- path, string->str);
- g_string_free (string, TRUE);
- return loadable;
-}
-
-static void
-glade_project_read_comment (GladeProject *project, GladeXmlDoc *doc)
-{
- /* TODO Write me !! Find out how to extract root level comments
- * with libxml2 !!!
- */
+ GladeProject *project = g_object_new (GLADE_TYPE_PROJECT, NULL);
+ glade_project_preferences (project);
+ return project;
}
static GList *
@@ -1444,6 +1125,198 @@ glade_project_is_generated_node (GladeProject *project,
return generated;
}
+
+/* Called when finishing loading a glade file to resolve object type properties
+ */
+static void
+glade_project_fix_object_props (GladeProject *project)
+{
+ GList *l, *ll;
+ GValue *value;
+ GladeWidget *gwidget;
+ GladeProperty *property;
+ gchar *txt;
+
+ for (l = project->priv->objects; l; l = l->next)
+ {
+ gwidget = glade_widget_get_from_gobject (l->data);
+
+ for (ll = gwidget->properties; ll; ll = ll->next)
+ {
+ property = GLADE_PROPERTY (ll->data);
+
+ if (glade_property_class_is_object (property->klass,
+ project->priv->format) &&
+ (txt = g_object_get_data (G_OBJECT (property),
+ "glade-loaded-object")) != NULL)
+ {
+ /* Parse the object list and set the property to it
+ * (this magicly works for both objects & object lists)
+ */
+ value = glade_property_class_make_gvalue_from_string
+ (property->klass, txt, gwidget->project, gwidget);
+
+ glade_property_set_value (property, value);
+
+ g_value_unset (value);
+ g_free (value);
+
+ g_object_set_data (G_OBJECT (property),
+ "glade-loaded-object", NULL);
+ }
+ }
+ }
+}
+
+static gchar *
+glade_project_read_requires_from_comment (GladeXmlNode *comment,
+ gint *major,
+ gint *minor)
+{
+ gint maj, min;
+ gchar *value, buffer[256];
+ gchar *required_lib = NULL;
+
+ if (!glade_xml_node_is_comment (comment))
+ return NULL;
+
+ value = glade_xml_get_content (comment);
+
+ if (value && !strncmp (" interface-requires", value, strlen (" interface-requires")))
+ {
+ if (sscanf (value, " interface-requires %s %d.%d", buffer, &maj, &min) == 3)
+ {
+ if (major) *major = maj;
+ if (minor) *minor = min;
+ required_lib = g_strdup (buffer);
+ }
+ }
+ g_free (value);
+
+ return required_lib;
+}
+
+
+static gboolean
+glade_project_read_requires (GladeProject *project,
+ GladeXmlNode *root_node,
+ const gchar *path)
+{
+
+ GString *string = g_string_new (NULL);
+ GladeXmlNode *node;
+ gchar *required_lib = NULL;
+ gboolean loadable = TRUE;
+ gint major, minor;
+
+ for (node = glade_xml_node_get_children_with_comments (root_node);
+ node; node = glade_xml_node_next_with_comments (node))
+ {
+ /* Skip non "requires" tags */
+ if (!(glade_xml_node_verify_silent (node, GLADE_XML_TAG_REQUIRES) ||
+ (required_lib =
+ glade_project_read_requires_from_comment (node, &major, &minor))))
+ continue;
+
+ if (!required_lib)
+ {
+ required_lib =
+ glade_xml_get_property_string_required (node, GLADE_XML_TAG_LIB,
+ NULL);
+ glade_xml_get_property_version (node, GLADE_XML_TAG_VERSION,
+ &major, &minor);
+ }
+
+ if (!required_lib) continue;
+
+ /* Dont mention gtk+ as a required lib in
+ * the generated glade file
+ */
+ if (!glade_catalog_is_loaded (required_lib))
+ {
+ if (!loadable)
+ g_string_append (string, ", ");
+
+ g_string_append (string, required_lib);
+ loadable = FALSE;
+ }
+ else
+ glade_project_set_target_version
+ (project, required_lib, major, minor);
+
+ g_free (required_lib);
+ }
+
+ if (!loadable)
+ glade_util_ui_message (glade_app_get_window(),
+ GLADE_UI_ERROR, NULL,
+ _("Failed to load %s.\n"
+ "The following required catalogs are unavailable: %s"),
+ path, string->str);
+ g_string_free (string, TRUE);
+ return loadable;
+}
+
+
+static gboolean
+glade_project_read_policy_from_comment (GladeXmlNode *comment,
+ GladeNamingPolicy *policy)
+{
+ gchar *value, buffer[256];
+ gboolean loaded = FALSE;
+
+ if (!glade_xml_node_is_comment (comment))
+ return FALSE;
+
+ value = glade_xml_get_content (comment);
+ if (value && !strncmp (" interface-naming-policy", value, strlen (" interface-naming-policy")))
+ {
+ if (sscanf (value, " interface-naming-policy %s", buffer) == 1)
+ {
+ if (strcmp (buffer, "project-wide") == 0)
+ *policy = GLADE_POLICY_PROJECT_WIDE;
+ else
+ *policy = GLADE_POLICY_TOPLEVEL_CONTEXTUAL;
+
+ loaded = TRUE;
+ }
+ }
+ g_free (value);
+
+ return loaded;
+}
+
+
+static void
+glade_project_read_naming_policy (GladeProject *project,
+ GladeXmlNode *root_node)
+{
+ /* A project file with no mention of a policy needs more lax rules
+ * (a new project has a project wide policy by default)
+ */
+ GladeNamingPolicy policy = GLADE_POLICY_TOPLEVEL_CONTEXTUAL;
+ GladeXmlNode *node;
+
+ for (node = glade_xml_node_get_children_with_comments (root_node);
+ node; node = glade_xml_node_next_with_comments (node))
+ {
+ /* Skip non "requires" tags */
+ if (!glade_project_read_policy_from_comment (node, &policy))
+ continue;
+ }
+
+ glade_project_set_naming_policy (project, policy, FALSE);
+}
+
+
+static void
+glade_project_read_comment (GladeProject *project, GladeXmlDoc *doc)
+{
+ /* TODO Write me !! Find out how to extract root level comments
+ * with libxml2 !!!
+ */
+}
+
gboolean
glade_project_load_from_file (GladeProject *project, const gchar *path)
{
@@ -1486,12 +1359,15 @@ glade_project_load_from_file (GladeProject *project, const gchar *path)
/* XXX Need to load project->priv->comment ! */
glade_project_read_comment (project, doc);
+
if (glade_project_read_requires (project, root, path) == FALSE)
{
glade_xml_context_free (context);
return FALSE;
}
+ glade_project_read_naming_policy (project, root);
+
for (node = glade_xml_node_get_children (root);
node; node = glade_xml_node_next (node))
{
@@ -1541,9 +1417,305 @@ glade_project_load_from_file (GladeProject *project, const gchar *path)
}
+/**
+ * glade_project_load:
+ * @path:
+ *
+ * Opens a project at the given path.
+ *
+ * Returns: a new #GladeProject for the opened project on success, %NULL on
+ * failure
+ */
+GladeProject *
+glade_project_load (const gchar *path)
+{
+ GladeProject *project;
+ gboolean retval;
+
+ g_return_val_if_fail (path != NULL, NULL);
+
+ project = g_object_new (GLADE_TYPE_PROJECT, NULL);
+
+ retval = glade_project_load_from_file (project, path);
+
+ if (retval)
+ {
+ gchar *name, *title;
+
+ /* Update prefs dialogs here... */
+ name = glade_project_get_name (project);
+ title = g_strdup_printf (_("%s preferences"), name);
+ gtk_window_set_title (GTK_WINDOW (project->priv->prefs_dialog), title);
+ g_free (title);
+ g_free (name);
+
+ return project;
+ }
+ else
+ {
+ g_object_unref (project);
+ return NULL;
+ }
+}
+
+/*******************************************************************
+ Writing project code here
+ *******************************************************************/
+
+#define GLADE_XML_COMMENT "Generated with "PACKAGE_NAME
+
+static gchar *
+glade_project_make_comment ()
+{
+ time_t now = time (NULL);
+ gchar *comment;
+ comment = g_strdup_printf (GLADE_XML_COMMENT" "PACKAGE_VERSION" on %s",
+ ctime (&now));
+ glade_util_replace (comment, '\n', ' ');
+
+ return comment;
+}
+
+static void
+glade_project_update_comment (GladeProject *project)
+{
+ gchar **lines, **l, *comment = NULL;
+
+ /* If project has no comment -> add the new one */
+ if (project->priv->comment == NULL)
+ {
+ project->priv->comment = glade_project_make_comment ();
+ return;
+ }
+
+ for (lines = l = g_strsplit (project->priv->comment, "\n", 0); *l; l++)
+ {
+ gchar *start;
+
+ /* Ignore leading spaces */
+ for (start = *l; *start && g_ascii_isspace (*start); start++);
+
+ if (g_str_has_prefix (start, GLADE_XML_COMMENT))
+ {
+ /* This line was generated by glade -> updating... */
+ g_free (*l);
+ *l = comment = glade_project_make_comment ();
+ }
+ }
+
+ if (comment)
+ {
+ g_free (project->priv->comment);
+ project->priv->comment = g_strjoinv ("\n", lines);
+ }
+
+ g_strfreev (lines);
+}
+static void
+glade_project_write_required_libs (GladeProject *project,
+ GladeXmlContext *context,
+ GladeXmlNode *root)
+{
+ GladeProjectFormat fmt;
+ GladeXmlNode *req_node;
+ GList *required, *list;
+ gint major, minor;
+ gchar *version;
+
+ fmt = glade_project_get_format (project);
+
+ if ((required = glade_project_required_libs (project)) != NULL)
+ {
+ for (list = required; list; list = list->next)
+ {
+ glade_project_get_target_version (project, (gchar *)list->data,
+ &major, &minor);
+
+ version = g_strdup_printf ("%d.%d", major, minor);
+
+ /* Write the standard requires tag */
+ if (fmt == GLADE_PROJECT_FORMAT_GTKBUILDER ||
+ (fmt == GLADE_PROJECT_FORMAT_LIBGLADE &&
+ strcmp ("gtk+", (gchar *)list->data)))
+ {
+ if (GLADE_GTKBUILDER_HAS_VERSIONING (major, minor))
+ {
+ req_node = glade_xml_node_new (context, GLADE_XML_TAG_REQUIRES);
+ glade_xml_node_append_child (root, req_node);
+ glade_xml_node_set_property_string (req_node,
+ GLADE_XML_TAG_LIB,
+ (gchar *)list->data);
+ }
+ else
+ {
+ gchar *comment =
+ g_strdup_printf (" interface-requires %s %s ",
+ (gchar *)list->data, version);
+ req_node = glade_xml_node_new_comment (context, comment);
+ glade_xml_node_append_child (root, req_node);
+ g_free (comment);
+ }
+
+ if (fmt != GLADE_PROJECT_FORMAT_LIBGLADE)
+ glade_xml_node_set_property_string
+ (req_node, GLADE_XML_TAG_VERSION, version);
+ }
+
+ /* Add extra metadata for libglade */
+ if (fmt == GLADE_PROJECT_FORMAT_LIBGLADE)
+ {
+ gchar *comment = g_strdup_printf (" interface-requires %s %s ",
+ (gchar *)list->data, version);
+ req_node = glade_xml_node_new_comment (context, comment);
+ glade_xml_node_append_child (root, req_node);
+ g_free (comment);
+ }
+ g_free (version);
+
+ }
+ g_list_foreach (required, (GFunc)g_free, NULL);
+ g_list_free (required);
+ }
+
+}
static void
+glade_project_write_naming_policy (GladeProject *project,
+ GladeXmlContext *context,
+ GladeXmlNode *root)
+{
+ GladeXmlNode *policy_node;
+ gchar *comment = g_strdup_printf (" interface-naming-policy %s ",
+ project->priv->naming_policy == GLADE_POLICY_PROJECT_WIDE ?
+ "project-wide" : "toplevel-contextual");
+
+ policy_node = glade_xml_node_new_comment (context, comment);
+ glade_xml_node_append_child (root, policy_node);
+ g_free (comment);
+}
+
+static GladeXmlContext *
+glade_project_write (GladeProject *project)
+{
+ GladeXmlContext *context;
+ GladeXmlDoc *doc;
+ GladeXmlNode *root, *comment_node;
+ GList *list;
+
+ doc = glade_xml_doc_new ();
+ context = glade_xml_context_new (doc, NULL);
+ root = glade_xml_node_new (context, GLADE_XML_TAG_PROJECT (project->priv->format));
+ glade_xml_doc_set_root (doc, root);
+
+ glade_project_update_comment (project);
+/* comment_node = glade_xml_node_new_comment (context, project->priv->comment); */
+
+ /* XXX Need to append this to the doc ! not the ROOT !
+ glade_xml_node_append_child (root, comment_node); */
+
+ glade_project_write_required_libs (project, context, root);
+
+ glade_project_write_naming_policy (project, context, root);
+
+ /* Any automatically generated stuff goes here */
+ glade_project_generate_nodes (project, context, root);
+
+ for (list = project->priv->objects; list; list = list->next)
+ {
+ GladeWidget *widget;
+
+ widget = glade_widget_get_from_gobject (list->data);
+
+ /*
+ * Append toplevel widgets. Each widget then takes
+ * care of appending its children.
+ */
+ if (widget->parent == NULL)
+ glade_widget_write (widget, context, root);
+ }
+
+ return context;
+}
+
+/**
+ * glade_project_save:
+ * @project: a #GladeProject
+ * @path: location to save glade file
+ * @error: an error from the G_FILE_ERROR domain.
+ *
+ * Saves @project to the given path.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ */
+gboolean
+glade_project_save (GladeProject *project, const gchar *path, GError **error)
+{
+ GladeXmlContext *context;
+ GladeXmlDoc *doc;
+ gchar *canonical_path;
+ gint ret;
+
+ if (!glade_project_verify (project, TRUE))
+ return FALSE;
+
+ context = glade_project_write (project);
+ doc = glade_xml_context_get_doc (context);
+ ret = glade_xml_doc_save (doc, path);
+ glade_xml_context_destroy (context);
+
+ canonical_path = glade_util_canonical_path (path);
+ g_assert (canonical_path);
+
+ if (project->priv->path == NULL ||
+ strcmp (canonical_path, project->priv->path))
+ {
+ gchar *old_dir, *new_dir, *name, *title;
+
+ if (project->priv->path)
+ {
+ old_dir = g_path_get_dirname (project->priv->path);
+ new_dir = g_path_get_dirname (canonical_path);
+
+ glade_project_move_resources (project,
+ old_dir,
+ new_dir);
+ g_free (old_dir);
+ g_free (new_dir);
+ }
+ project->priv->path = (g_free (project->priv->path),
+ g_strdup (canonical_path));
+
+ /* Update prefs dialogs here... */
+ name = glade_project_get_name (project);
+ title = g_strdup_printf (_("%s preferences"), name);
+ gtk_window_set_title (GTK_WINDOW (project->priv->prefs_dialog), title);
+ g_free (title);
+ g_free (name);
+ }
+
+ glade_project_set_readonly (project,
+ !glade_util_file_is_writeable (project->priv->path));
+
+ project->priv->mtime = glade_util_get_file_mtime (project->priv->path, NULL);
+
+ glade_project_set_modified (project, FALSE);
+
+ if (project->priv->unsaved_number > 0)
+ {
+ glade_id_allocator_release (get_unsaved_number_allocator (), project->priv->unsaved_number);
+ project->priv->unsaved_number = 0;
+ }
+
+ g_free (canonical_path);
+
+ return ret > 0;
+}
+
+/*******************************************************************
+ Verify code here (versioning, incompatability checks)
+ *******************************************************************/
+static void
glade_project_verify_property (GladeProject *project,
GladeProperty *property,
const gchar *path_name,
@@ -1829,121 +2001,472 @@ glade_project_verify (GladeProject *project,
return ret;
}
+static void
+glade_project_target_version_for_adaptor (GladeProject *project,
+ GladeWidgetAdaptor *adaptor,
+ gint *major,
+ gint *minor)
+{
+ gchar *catalog = NULL;
+
+ g_object_get (adaptor, "catalog", &catalog, NULL);
+ glade_project_get_target_version (project, catalog, major, minor);
+ g_free (catalog);
+}
+
+static void
+glade_project_verify_adaptor (GladeProject *project,
+ GladeWidgetAdaptor *adaptor,
+ const gchar *path_name,
+ GString *string,
+ gboolean saving,
+ gboolean forwidget,
+ GladeSupportMask *mask)
+{
+ GladeSupportMask support_mask = GLADE_SUPPORT_OK;
+ GladeWidgetAdaptor *adaptor_iter;
+ gint target_major, target_minor;
+ gchar *catalog = NULL;
+
+ for (adaptor_iter = adaptor; adaptor_iter;
+ adaptor_iter = glade_widget_adaptor_get_parent_adaptor (adaptor_iter))
+ {
+
+ g_object_get (adaptor_iter, "catalog", &catalog, NULL);
+ glade_project_target_version_for_adaptor (project, adaptor_iter,
+ &target_major,
+ &target_minor);
+
+ if (target_major < GWA_VERSION_SINCE_MAJOR (adaptor_iter) ||
+ (target_major == GWA_VERSION_SINCE_MAJOR (adaptor_iter) &&
+ target_minor < GWA_VERSION_SINCE_MINOR (adaptor_iter)))
+ {
+ if (forwidget)
+ {
+ /* translators: reffers to a widget
+ * introduced in toolkit version '%s %d.%d',
+ * and a project targeting toolkit verion '%s %d.%d' */
+ g_string_append_printf
+ (string,
+ _("This widget was introduced in %s %d.%d "
+ "project targets %s %d.%d"),
+ catalog,
+ GWA_VERSION_SINCE_MAJOR (adaptor_iter),
+ GWA_VERSION_SINCE_MINOR (adaptor_iter),
+ catalog, target_major, target_minor);
+ }
+ else
+ /* translators: reffers to a widget '[%s]'
+ * introduced in toolkit version '%s %d.%d' */
+ g_string_append_printf
+ (string,
+ _("[%s] Object class '%s' was introduced in %s %d.%d\n"),
+ path_name, adaptor_iter->title, catalog,
+ GWA_VERSION_SINCE_MAJOR (adaptor_iter),
+ GWA_VERSION_SINCE_MINOR (adaptor_iter));
+
+ support_mask |= GLADE_SUPPORT_MISMATCH;
+ }
+
+ if (project->priv->format == GLADE_PROJECT_FORMAT_GTKBUILDER &&
+ GWA_LIBGLADE_ONLY (adaptor_iter))
+ {
+ if (forwidget)
+ {
+ if (string->len)
+ g_string_append (string, "\n");
+ g_string_append_printf
+ (string,
+ _("This widget is only supported in libglade format"));
+ }
+ else
+ /* translators: reffers to a widget '[%s]'
+ * loaded from toolkit version '%s %d.%d' */
+ g_string_append_printf
+ (string,
+ _("[%s] Object class '%s' from %s %d.%d "
+ "is only supported in libglade format\n"),
+ path_name, adaptor_iter->title, catalog,
+ target_major, target_minor);
+
+ support_mask |= GLADE_SUPPORT_LIBGLADE_ONLY;
+ }
+ else if (project->priv->format == GLADE_PROJECT_FORMAT_LIBGLADE &&
+ GWA_LIBGLADE_UNSUPPORTED (adaptor_iter))
+ {
+ if (forwidget)
+ {
+ if (string->len)
+ g_string_append (string, "\n");
+ g_string_append_printf
+ (string,
+ _("This widget is not supported in libglade format"));
+ }
+ else
+ /* translators: reffers to a widget '[%s]'
+ * loaded from toolkit version '%s %d.%d' */
+ g_string_append_printf
+ (string,
+ _("[%s] Object class '%s' from %s %d.%d "
+ "is not supported in libglade format\n"),
+ path_name, adaptor_iter->title, catalog,
+ target_major, target_minor);
+
+ support_mask |= GLADE_SUPPORT_LIBGLADE_UNSUPPORTED;
+ }
+
+ if (!saving && GWA_DEPRECATED (adaptor_iter))
+ {
+ if (forwidget)
+ {
+ if (string->len)
+ g_string_append (string, "\n");
+ g_string_append_printf
+ (string, _("This widget is deprecated"));
+ }
+ else
+ /* translators: reffers to a widget '[%s]'
+ * loaded from toolkit version '%s %d.%d' */
+ g_string_append_printf
+ (string,
+ _("[%s] Object class '%s' from %s %d.%d "
+ "is deprecated\n"),
+ path_name, adaptor_iter->title, catalog,
+ target_major, target_minor);
+
+ support_mask |= GLADE_SUPPORT_DEPRECATED;
+ }
+ g_free (catalog);
+ }
+ if (mask)
+ *mask = support_mask;
+}
/**
- * glade_project_selection_changed:
- * @project: a #GladeProject
+ * glade_project_verify_widget_adaptor:
+ * @project: A #GladeProject
+ * @adaptor: the #GladeWidgetAdaptor to verify
+ * @mask: a return location for a #GladeSupportMask
+ *
+ * Checks the supported state of this widget adaptor
+ * and generates a string to show in the UI describing why.
*
- * Causes @project to emit a "selection_changed" signal.
+ * Returns: A newly allocated string
+ */
+gchar *
+glade_project_verify_widget_adaptor (GladeProject *project,
+ GladeWidgetAdaptor *adaptor,
+ GladeSupportMask *mask)
+{
+ GString *string = g_string_new (NULL);
+ gchar *ret = NULL;
+
+ glade_project_verify_adaptor (project, adaptor, NULL,
+ string, FALSE, TRUE, mask);
+
+ /* there was a '\0' byte... */
+ if (string->len > 0)
+ {
+ ret = string->str;
+ g_string_free (string, FALSE);
+ }
+ else
+ g_string_free (string, TRUE);
+
+
+ return ret;
+}
+
+
+/**
+ * glade_project_verify_project_for_ui:
+ * @project: A #GladeProject
+ *
+ * Checks the project and updates warning strings in the UI
*/
void
-glade_project_selection_changed (GladeProject *project)
+glade_project_verify_project_for_ui (GladeProject *project)
{
- g_return_if_fail (GLADE_IS_PROJECT (project));
- g_signal_emit (G_OBJECT (project),
- glade_project_signals [SELECTION_CHANGED],
- 0);
+ GList *list;
+ GladeWidget *widget;
+ gchar *warning;
+
+ /* Sync displayable info here */
+ for (list = project->priv->objects; list; list = list->next)
+ {
+ widget = glade_widget_get_from_gobject (list->data);
+
+ warning = glade_project_verify_widget_adaptor (project, widget->adaptor, NULL);
+ glade_widget_set_support_warning (widget, warning);
+
+ if (warning)
+ g_free (warning);
+
+ glade_project_verify_properties (widget);
+ }
+
+ /* refresh palette if this is the active project */
+ if (project == glade_app_get_project ())
+ glade_palette_refresh (glade_app_get_palette ());
}
-static void
-glade_project_on_widget_notify (GladeWidget *widget, GParamSpec *arg, GladeProject *project)
+/*******************************************************************
+ Project object tracking code, name exclusivity, resources etc...
+ *******************************************************************/
+static GladeNameContext *
+name_context_by_widget (GladeProject *project,
+ GladeWidget *gwidget)
{
- g_return_if_fail (GLADE_IS_WIDGET (widget));
- g_return_if_fail (GLADE_IS_PROJECT (project));
+ TopLevelInfo *tinfo;
+ GladeWidget *iter;
+ GList *list;
- switch (arg->name[0])
+ iter = gwidget;
+ while (iter->parent) iter = iter->parent;
+
+ for (list = project->priv->toplevels; list; list = list->next)
{
- case 'n':
- if (strcmp (arg->name, "name") == 0)
- {
- const char *old_name = g_hash_table_lookup (project->priv->widget_old_names, widget);
- glade_project_widget_name_changed (project, widget, old_name);
- g_hash_table_insert (project->priv->widget_old_names, widget, g_strdup (glade_widget_get_name (widget)));
- }
+ tinfo = list->data;
+ if (tinfo->toplevel == iter)
+ return tinfo->names;
+ }
+ return NULL;
+}
+
+GladeWidget *
+search_ancestry_by_name (GladeWidget *toplevel, const gchar *name)
+{
+ GladeWidget *widget = NULL, *iter;
+ GList *list, *children;
+
+ if ((children = glade_widget_adaptor_get_children (toplevel->adaptor,
+ toplevel->object)) != NULL)
+ {
+ for (list = children; list; list = list->next)
+ if ((iter = glade_widget_get_from_gobject (list->data)) != NULL)
+ {
+ if (iter->name && strcmp (iter->name, name) == 0)
+ {
+ widget = iter;
+ break;
+ }
+ else if ((widget = search_ancestry_by_name (iter, name)) != NULL)
+ break;
+ }
- case 'p':
- if (strcmp (arg->name, "project") == 0)
- glade_project_remove_object (project, glade_widget_get_object (widget));
+ g_list_free (children);
}
+ return widget;
}
+/**
+ * glade_project_get_widget_by_name:
+ * @project: a #GladeProject
+ * @ancestor: The toplevel project object to search under
+ * @name: The user visible name of the widget we are looking for
+ *
+ * Searches under @ancestor in @project looking for a #GladeWidget named @name.
+ *
+ * Returns: a pointer to the widget, %NULL if the widget does not exist
+ */
+GladeWidget *
+glade_project_get_widget_by_name (GladeProject *project, GladeWidget *ancestor, const gchar *name)
+{
+ GladeWidget *toplevel, *widget = NULL;
+ GList *list;
+
+ g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ if (ancestor)
+ {
+ toplevel = glade_widget_get_toplevel (ancestor);
+ if ((widget = search_ancestry_by_name (toplevel, name)) != NULL)
+ return widget;
+ }
+
+ /* Now try searching in only toplevel objects... */
+ for (list = project->priv->objects; list; list = list->next) {
+ GladeWidget *widget;
+
+ widget = glade_widget_get_from_gobject (list->data);
+ g_assert (widget->name);
+ if (widget->parent == NULL && strcmp (widget->name, name) == 0)
+ return widget;
+ }
+
+ /* Finally resort to a project wide search. */
+ for (list = project->priv->objects; list; list = list->next) {
+ GladeWidget *widget;
+
+ widget = glade_widget_get_from_gobject (list->data);
+ g_return_val_if_fail (widget->name != NULL, NULL);
+ if (strcmp (widget->name, name) == 0)
+ return widget;
+ }
+
+ return NULL;
+}
static void
-gp_sync_resources (GladeProject *project,
- GladeProject *prev_project,
- GladeWidget *gwidget,
- gboolean remove)
+glade_project_release_widget_name (GladeProject *project, GladeWidget *gwidget, const char *widget_name)
{
- GList *prop_list, *l;
- GladeProperty *property;
- gchar *resource, *full_resource;
+ GladeNameContext *context = NULL;
+ TopLevelInfo *tinfo = NULL;
+ GladeWidget *iter;
+ GList *list;
- prop_list = g_list_copy (gwidget->properties);
- prop_list = g_list_concat
- (prop_list, g_list_copy (gwidget->packing_properties));
+ /* Search by hand here since we need the tinfo to free... */
+ iter = gwidget;
+ while (iter->parent) iter = iter->parent;
- for (l = prop_list; l; l = l->next)
+ for (list = project->priv->toplevels; list; list = list->next)
{
- property = l->data;
- if (property->klass->resource)
+ tinfo = list->data;
+ if (tinfo->toplevel == iter)
{
- GValue value = { 0, };
+ context = tinfo->names;
+ break;
+ }
+ }
- if (remove)
- {
- glade_project_set_resource (project, property, NULL);
- continue;
- }
+ if (context)
+ glade_name_context_release_name (context, widget_name);
- glade_property_get_value (property, &value);
-
- if ((resource = glade_widget_adaptor_string_from_value
- (GLADE_WIDGET_ADAPTOR (property->klass->handle),
- property->klass, &value, project->priv->format)) != NULL)
- {
- full_resource = glade_project_resource_fullpath
- (prev_project ? prev_project : project, resource);
-
- /* Use a full path here so that the current
- * working directory isnt used.
- */
- glade_project_set_resource (project,
- property,
- full_resource);
-
- g_free (full_resource);
- g_free (resource);
- }
- g_value_unset (&value);
+ if (!gwidget->parent)
+ {
+ glade_name_context_release_name (project->priv->toplevel_names, widget_name);
+
+ if (context && glade_name_context_n_names (context) == 0)
+ {
+ glade_name_context_destroy (context);
+ g_free (tinfo);
+ project->priv->toplevels = g_list_remove (project->priv->toplevels, tinfo);
}
}
- g_list_free (prop_list);
}
-static void
-glade_project_sync_resources_for_widget (GladeProject *project,
- GladeProject *prev_project,
- GladeWidget *gwidget,
- gboolean remove)
+/**
+ * glade_project_available_widget_name:
+ * @project: a #GladeProject
+ * @widget: the #GladeWidget intended to recieve a new name
+ * @name: base name of the widget to create
+ *
+ * Checks whether @name is an appropriate name for @widget.
+ *
+ * Returns: whether the name is available or not.
+ */
+gboolean
+glade_project_available_widget_name (GladeProject *project,
+ GladeWidget *widget,
+ const gchar *name)
{
- GList *children, *l;
- GladeWidget *gchild;
+ GladeNameContext *context;
- children = glade_widget_adaptor_get_children
- (gwidget->adaptor, gwidget->object);
+ g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
+ g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
+ g_return_val_if_fail (widget->project == project, FALSE);
- for (l = children; l; l = l->next)
- if ((gchild =
- glade_widget_get_from_gobject (l->data)) != NULL)
- glade_project_sync_resources_for_widget
- (project, prev_project, gchild, remove);
- if (children)
- g_list_free (children);
+ if (!name || !name[0])
+ return FALSE;
- gp_sync_resources (project, prev_project, gwidget, remove);
+ context = name_context_by_widget (project, widget);
+ g_assert (context);
+
+ if (!widget->parent)
+ return (!glade_name_context_has_name (context, name) &&
+ !glade_name_context_has_name (project->priv->toplevel_names, name));
+
+ return !glade_name_context_has_name (context, name);
+}
+
+/**
+ * glade_project_new_widget_name:
+ * @project: a #GladeProject
+ * @widget: the #GladeWidget intended to recieve a new name
+ * @base_name: base name of the widget to create
+ *
+ * Creates a new name for a widget that doesn't collide with any of the names
+ * already in @project. This name will start with @base_name.
+ *
+ * Returns: a string containing the new name, %NULL if there is not enough
+ * memory for this string
+ */
+gchar *
+glade_project_new_widget_name (GladeProject *project,
+ GladeWidget *widget,
+ const gchar *base_name)
+{
+ GladeNameContext *context;
+ gchar *name;
+
+ g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
+ g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
+ g_return_val_if_fail (widget->project == project, NULL);
+ g_return_val_if_fail (base_name && base_name[0], NULL);
+
+ context = name_context_by_widget (project, widget);
+
+ /* should use dual here to encourage unique names across the file... */
+ if (context && widget->parent)
+ name = glade_name_context_new_name (context, base_name);
+ else if (context)
+ name = glade_name_context_dual_new_name (context, project->priv->toplevel_names, base_name);
+ else
+ name = glade_name_context_new_name (project->priv->toplevel_names, base_name);
+
+ return name;
}
/**
+ * glade_project_set_widget_name:
+ * @project: a #GladeProject
+ * @widget: the #GladeWidget to set a name on
+ * @name: the name to set.
+ *
+ * Sets @name on @widget in @project, if @name is not
+ * available then a new name will be used.
+ */
+void
+glade_project_set_widget_name (GladeProject *project,
+ GladeWidget *widget,
+ const gchar *name)
+{
+ GladeNameContext *context = NULL;
+ gchar *new_name;
+
+ g_return_if_fail (GLADE_IS_PROJECT (project));
+ g_return_if_fail (GLADE_IS_WIDGET (widget));
+ g_return_if_fail (widget->project == project);
+ g_return_if_fail (name && name[0]);
+
+ if (strcmp (name, widget->name) == 0)
+ return;
+
+ /* Police the widget name */
+ if (!glade_project_available_widget_name (project, widget, name))
+ new_name = glade_project_new_widget_name (project, widget, name);
+ else
+ new_name = g_strdup (name);
+
+
+ /* Add to name context(s) */
+ context = name_context_by_widget (project, widget);
+ g_assert (context);
+ glade_name_context_add_name (context, new_name);
+ if (!widget->parent)
+ glade_name_context_add_name (project->priv->toplevel_names, new_name);
+
+ /* Release old name and set new widget name */
+ glade_project_release_widget_name (project, widget, widget->name);
+ glade_widget_set_name (widget, new_name);
+
+ g_free (new_name);
+}
+
+
+
+/**
* glade_project_add_object:
* @project: the #GladeProject the widget is added to
* @old_project: the #GladeProject the widget was previously in
@@ -1957,9 +2480,11 @@ glade_project_add_object (GladeProject *project,
GladeProject *old_project,
GObject *object)
{
- GladeWidget *gwidget;
- GList *list, *children;
- static gint reentrancy_count = 0;
+ GladeNameContext *context;
+ GladeWidget *gwidget;
+ GList *list, *children;
+ static gint reentrancy_count = 0;
+ gchar *name;
g_return_if_fail (GLADE_IS_PROJECT (project));
g_return_if_fail (G_IS_OBJECT (object));
@@ -1979,14 +2504,29 @@ glade_project_add_object (GladeProject *project,
if (glade_project_has_object (project, object))
return;
- /* Police widget names here (just rename them on the way in the project)
- */
- if (glade_project_get_widget_by_name (project, gwidget->name) != NULL)
- {
- gchar *name = glade_project_new_widget_name (project, gwidget->name);
+ /* Create a name context for newly added toplevels... */
+ if (!gwidget->parent)
+ {
+ TopLevelInfo *tinfo = g_new0 (TopLevelInfo, 1);
+ tinfo->toplevel = gwidget;
+ tinfo->names = glade_name_context_new ();
+ project->priv->toplevels = g_list_prepend (project->priv->toplevels, tinfo);
+ }
+
+ /* Make sure we have an exclusive name first... */
+ if (!glade_project_available_widget_name (project, gwidget, gwidget->name))
+ {
+ name = glade_project_new_widget_name (project, gwidget, gwidget->name);
glade_widget_set_name (gwidget, name);
g_free (name);
}
+
+ /* Now lock down the widget name. */
+ context = name_context_by_widget (project, gwidget);
+ g_assert (context);
+ glade_name_context_add_name (context, gwidget->name);
+ if (!gwidget->parent)
+ glade_name_context_add_name (project->priv->toplevel_names, gwidget->name);
/* Code body starts here */
reentrancy_count++;
@@ -2001,11 +2541,6 @@ glade_project_add_object (GladeProject *project,
}
glade_widget_set_project (gwidget, (gpointer)project);
- g_hash_table_insert (project->priv->widget_old_names,
- gwidget, g_strdup (glade_widget_get_name (gwidget)));
-
- g_signal_connect (G_OBJECT (gwidget), "notify",
- (GCallback) glade_project_on_widget_notify, project);
project->priv->objects = g_list_append (project->priv->objects, g_object_ref (object));
@@ -2039,58 +2574,6 @@ glade_project_has_object (GladeProject *project, GObject *object)
return (g_list_find (project->priv->objects, object)) != NULL;
}
-/**
- * glade_project_release_widget_name:
- * @project: a #GladeProject
- * @glade_widget:
- * @widget_name:
- *
- * TODO: Write me
- */
-static void
-glade_project_release_widget_name (GladeProject *project, GladeWidget *glade_widget, const char *widget_name)
-{
- const char *first_number = widget_name;
- char *end_number;
- char *base_widget_name;
- GladeIDAllocator *id_allocator;
- gunichar ch;
- int id;
-
- g_return_if_fail (GLADE_IS_PROJECT (project));
- g_return_if_fail (GLADE_IS_WIDGET (glade_widget));
-
- do
- {
- ch = g_utf8_get_char (first_number);
-
- if (ch == 0 || g_unichar_isdigit (ch))
- break;
-
- first_number = g_utf8_next_char (first_number);
- }
- while (TRUE);
-
- if (ch == 0)
- return;
-
- base_widget_name = g_strdup (widget_name);
- *(base_widget_name + (first_number - widget_name)) = 0;
-
- id_allocator = g_hash_table_lookup (project->priv->widget_names_allocator, base_widget_name);
- if (id_allocator == NULL)
- goto lblend;
-
- id = (int) strtol (first_number, &end_number, 10);
- if (*end_number != 0)
- goto lblend;
-
- glade_id_allocator_release (id_allocator, id);
-
- lblend:
- g_hash_table_remove (project->priv->widget_old_names, glade_widget);
- g_free (base_widget_name);
-}
/**
* glade_project_remove_object:
@@ -2151,133 +2634,192 @@ glade_project_remove_object (GladeProject *project, GObject *object)
glade_project_sync_resources_for_widget (project, NULL, gwidget, TRUE);
}
-/**
- * glade_project_widget_name_changed:
- * @project: a #GladeProject
- * @widget: a #GladeWidget
- * @old_name:
- *
- * TODO: write me
- */
-void
-glade_project_widget_name_changed (GladeProject *project, GladeWidget *widget, const char *old_name)
+static void
+adjust_naming_policy (GladeProject *project, gboolean use_command)
{
- GladeWidget *iter;
- GList *l;
- g_return_if_fail (GLADE_IS_PROJECT (project));
- g_return_if_fail (GLADE_IS_WIDGET (widget));
-
- glade_project_release_widget_name (project, widget, old_name);
+ GList *list;
+ GladeWidget *widget;
+ TopLevelInfo *tinfo;
+ GladeNameContext *context;
- /* Police widget names here (just rename them on the way in the project)
- */
- for (l = project->priv->objects; l; l = l->next)
+ if (project->priv->naming_policy == GLADE_POLICY_PROJECT_WIDE)
{
- iter = glade_widget_get_from_gobject (l->data);
-
- if (widget != iter &&
- !strcmp (widget->name, iter->name))
- {
- gchar *name = glade_project_new_widget_name (project, widget->name);
- glade_widget_set_name (widget, name);
- g_free (name);
+ for (list = project->priv->objects; list; list = list->next)
+ {
+ widget = glade_widget_get_from_gobject (list->data);
+
+ if (!widget->parent)
+ continue;
+
+ if (!glade_name_context_has_name (project->priv->toplevel_names, widget->name))
+ glade_name_context_add_name (project->priv->toplevel_names, widget->name);
+ else
+ {
+ gchar *new_name = glade_name_context_new_name (project->priv->toplevel_names,
+ widget->name);
+
+ if (use_command)
+ glade_command_set_name (widget, new_name);
+ else
+ glade_widget_set_name (widget, new_name);
+
+ glade_name_context_add_name (project->priv->toplevel_names, new_name);
+ g_free (new_name);
+ }
}
-
+
+ for (list = project->priv->toplevels; list; list = list->next)
+ {
+ tinfo = list->data;
+ glade_name_context_destroy (tinfo->names);
+ g_free (tinfo);
+ }
+ project->priv->toplevels =
+ (g_list_free (project->priv->toplevels), NULL);
}
-
- g_signal_emit (G_OBJECT (project),
- glade_project_signals [WIDGET_NAME_CHANGED],
- 0,
- widget);
-}
+ else
+ {
+ /* First add toplevel names */
+ for (list = project->priv->objects; list; list = list->next)
+ {
+ widget = glade_widget_get_from_gobject (list->data);
-/**
- * glade_project_get_widget_by_name:
- * @project: a #GladeProject
- * @name: The user visible name of the widget we are looking for
- *
- * Searches through @project looking for a #GladeWidget named @name.
- *
- * Returns: a pointer to the widget, %NULL if the widget does not exist
- */
-GladeWidget *
-glade_project_get_widget_by_name (GladeProject *project, const gchar *name)
-{
- GList *list;
+ if (!widget->parent)
+ {
+ TopLevelInfo *tinfo = g_new0 (TopLevelInfo, 1);
+ tinfo->toplevel = widget;
+ tinfo->names = glade_name_context_new ();
+ project->priv->toplevels = g_list_prepend (project->priv->toplevels, tinfo);
- g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
- g_return_val_if_fail (name != NULL, NULL);
+ glade_name_context_add_name (tinfo->names, widget->name);
+ }
+ }
- for (list = project->priv->objects; list; list = list->next) {
- GladeWidget *widget;
+ /* Now add child names */
+ for (list = project->priv->objects; list; list = list->next)
+ {
+ widget = glade_widget_get_from_gobject (list->data);
- widget = glade_widget_get_from_gobject (list->data);
- g_return_val_if_fail (widget->name != NULL, NULL);
- if (strcmp (widget->name, name) == 0)
- return widget;
+ if (widget->parent)
+ {
+ context = name_context_by_widget (project, widget);
+ glade_name_context_add_name (context, widget->name);
+ glade_name_context_release_name (project->priv->toplevel_names, widget->name);
+ }
+ }
}
- return NULL;
}
-/**
- * glade_project_new_widget_name:
- * @project: a #GladeProject
- * @base_name: base name of the widget to create
- *
- * Creates a new name for a widget that doesn't collide with any of the names
- * already in @project. This name will start with @base_name.
- *
- * Returns: a string containing the new name, %NULL if there is not enough
- * memory for this string
- */
-char *
-glade_project_new_widget_name (GladeProject *project, const char *base_name)
+
+/*******************************************************************
+ Remaining stubs and api
+ *******************************************************************/
+static void
+glade_project_get_target_version (GladeProject *project,
+ const gchar *catalog,
+ gint *major,
+ gint *minor)
{
- GladeIDAllocator *id_allocator;
- const gchar *number;
- gchar *name = NULL, *freeme = NULL;
- guint i = 1;
-
- g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
+ *major = GPOINTER_TO_INT
+ (g_hash_table_lookup (project->priv->target_versions_major,
+ catalog));
+ *minor = GPOINTER_TO_INT
+ (g_hash_table_lookup (project->priv->target_versions_minor,
+ catalog));
+}
- number = base_name + strlen (base_name);
+static void
+glade_project_set_target_version (GladeProject *project,
+ const gchar *catalog,
+ gint major,
+ gint minor)
+{
+ GladeTargetableVersion *version;
+ GSList *radios, *list;
+ GtkWidget *radio;
- while (number > base_name && g_ascii_isdigit (number[-1]))
- --number;
+ g_hash_table_insert (project->priv->target_versions_major,
+ g_strdup (catalog),
+ GINT_TO_POINTER (major));
+ g_hash_table_insert (project->priv->target_versions_minor,
+ g_strdup (catalog),
+ GINT_TO_POINTER (minor));
- if (*number)
- {
- freeme = g_strndup (base_name, number - base_name);
- base_name = freeme;
- }
-
- id_allocator = g_hash_table_lookup (project->priv->widget_names_allocator, base_name);
- if (id_allocator == NULL)
+ /* Update prefs dialog from here... */
+ if (project->priv->target_radios &&
+ (radios = g_hash_table_lookup (project->priv->target_radios, catalog)) != NULL)
{
- id_allocator = glade_id_allocator_new ();
- g_hash_table_insert (project->priv->widget_names_allocator,
- g_strdup (base_name), id_allocator);
+ for (list = radios; list; list = list->next)
+ g_signal_handlers_block_by_func (G_OBJECT (list->data),
+ G_CALLBACK (target_button_clicked),
+ project);
+
+ for (list = radios; list; list = list->next)
+ {
+ radio = list->data;
+
+ version = g_object_get_data (G_OBJECT (radio), "version");
+ if (version->major == major &&
+ version->minor == minor)
+ {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio), TRUE);
+ break;
+ }
+ }
+
+ for (list = radios; list; list = list->next)
+ g_signal_handlers_unblock_by_func (G_OBJECT (list->data),
+ G_CALLBACK (target_button_clicked),
+ project);
}
- while (TRUE)
+ glade_project_verify_project_for_ui (project);
+}
+
+static void
+glade_project_set_readonly (GladeProject *project, gboolean readonly)
+{
+ g_assert (GLADE_IS_PROJECT (project));
+
+ if (project->priv->readonly != readonly)
{
- i = glade_id_allocator_allocate (id_allocator);
- name = g_strdup_printf ("%s%u", base_name, i);
+ project->priv->readonly = readonly;
+ g_object_notify (G_OBJECT (project), "read-only");
+ }
+}
- /* ok, there is no widget with this name, so return the name */
- if (glade_project_get_widget_by_name (project, name) == NULL)
- return name;
+/**
+ * glade_project_get_readonly:
+ * @project: a #GladeProject
+ *
+ * Gets whether the project is read only or not
+ *
+ * Returns: TRUE if project is read only
+ */
+gboolean
+glade_project_get_readonly (GladeProject *project)
+{
+ g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
- /* we already have a widget with this name, so free the name and
- * try again with another number */
- g_free (name);
- i++;
- }
+ return project->priv->readonly;
+}
- g_free (freeme);
- return name;
+
+/**
+ * glade_project_selection_changed:
+ * @project: a #GladeProject
+ *
+ * Causes @project to emit a "selection_changed" signal.
+ */
+void
+glade_project_selection_changed (GladeProject *project)
+{
+ g_return_if_fail (GLADE_IS_PROJECT (project));
+ g_signal_emit (G_OBJECT (project),
+ glade_project_signals [SELECTION_CHANGED],
+ 0);
}
static void
@@ -2498,294 +3040,6 @@ glade_project_required_libs (GladeProject *project)
return g_list_reverse (required);
}
-#define GLADE_XML_COMMENT "Generated with "PACKAGE_NAME
-
-static gchar *
-glade_project_make_comment ()
-{
- time_t now = time (NULL);
- gchar *comment;
- comment = g_strdup_printf (GLADE_XML_COMMENT" "PACKAGE_VERSION" on %s",
- ctime (&now));
- glade_util_replace (comment, '\n', ' ');
-
- return comment;
-}
-
-static void
-glade_project_update_comment (GladeProject *project)
-{
- gchar **lines, **l, *comment = NULL;
-
- /* If project has no comment -> add the new one */
- if (project->priv->comment == NULL)
- {
- project->priv->comment = glade_project_make_comment ();
- return;
- }
-
- for (lines = l = g_strsplit (project->priv->comment, "\n", 0); *l; l++)
- {
- gchar *start;
-
- /* Ignore leading spaces */
- for (start = *l; *start && g_ascii_isspace (*start); start++);
-
- if (g_str_has_prefix (start, GLADE_XML_COMMENT))
- {
- /* This line was generated by glade -> updating... */
- g_free (*l);
- *l = comment = glade_project_make_comment ();
- }
- }
-
- if (comment)
- {
- g_free (project->priv->comment);
- project->priv->comment = g_strjoinv ("\n", lines);
- }
-
- g_strfreev (lines);
-}
-
-static void
-glade_project_write_required_libs (GladeProject *project,
- GladeXmlContext *context,
- GladeXmlNode *root)
-{
- GladeProjectFormat fmt;
- GladeXmlNode *req_node;
- GList *required, *list;
- gint major, minor;
- gchar *version;
-
- fmt = glade_project_get_format (project);
-
- if ((required = glade_project_required_libs (project)) != NULL)
- {
- for (list = required; list; list = list->next)
- {
- glade_project_get_target_version (project, (gchar *)list->data,
- &major, &minor);
-
- version = g_strdup_printf ("%d.%d", major, minor);
-
- /* Write the standard requires tag */
- if (fmt == GLADE_PROJECT_FORMAT_GTKBUILDER ||
- (fmt == GLADE_PROJECT_FORMAT_LIBGLADE &&
- strcmp ("gtk+", (gchar *)list->data)))
- {
- if (GLADE_GTKBUILDER_HAS_VERSIONING (major, minor))
- {
- req_node = glade_xml_node_new (context, GLADE_XML_TAG_REQUIRES);
- glade_xml_node_append_child (root, req_node);
- glade_xml_node_set_property_string (req_node,
- GLADE_XML_TAG_LIB,
- (gchar *)list->data);
- }
- else
- {
- gchar *comment =
- g_strdup_printf ("interface-requires %s %s",
- (gchar *)list->data, version);
- req_node = glade_xml_node_new_comment (context, comment);
- glade_xml_node_append_child (root, req_node);
- g_free (comment);
- }
-
- if (fmt != GLADE_PROJECT_FORMAT_LIBGLADE)
- glade_xml_node_set_property_string
- (req_node, GLADE_XML_TAG_VERSION, version);
- }
-
- /* Add extra metadata for libglade */
- if (fmt == GLADE_PROJECT_FORMAT_LIBGLADE)
- {
- gchar *comment = g_strdup_printf ("interface-requires %s %s",
- (gchar *)list->data, version);
- req_node = glade_xml_node_new_comment (context, comment);
- glade_xml_node_append_child (root, req_node);
- g_free (comment);
- }
- g_free (version);
-
- }
- g_list_foreach (required, (GFunc)g_free, NULL);
- g_list_free (required);
- }
-
-}
-
-static GladeXmlContext *
-glade_project_write (GladeProject *project)
-{
- GladeXmlContext *context;
- GladeXmlDoc *doc;
- GladeXmlNode *root, *comment_node;
- GList *list;
-
- doc = glade_xml_doc_new ();
- context = glade_xml_context_new (doc, NULL);
- root = glade_xml_node_new (context, GLADE_XML_TAG_PROJECT (project->priv->format));
- glade_xml_doc_set_root (doc, root);
-
- glade_project_update_comment (project);
-/* comment_node = glade_xml_node_new_comment (context, project->priv->comment); */
-
- /* XXX Need to append this to the doc ! not the ROOT !
- glade_xml_node_append_child (root, comment_node); */
-
- glade_project_write_required_libs (project, context, root);
-
- /* Any automatically generated stuff goes here */
- glade_project_generate_nodes (project, context, root);
-
- for (list = project->priv->objects; list; list = list->next)
- {
- GladeWidget *widget;
-
- widget = glade_widget_get_from_gobject (list->data);
-
- /*
- * Append toplevel widgets. Each widget then takes
- * care of appending its children.
- */
- if (widget->parent == NULL)
- glade_widget_write (widget, context, root);
- }
-
- return context;
-}
-
-/**
- * glade_project_load:
- * @path:
- *
- * Opens a project at the given path.
- *
- * Returns: a new #GladeProject for the opened project on success, %NULL on
- * failure
- */
-GladeProject *
-glade_project_load (const gchar *path)
-{
- GladeProject *project;
- gboolean retval;
-
- g_return_val_if_fail (path != NULL, NULL);
-
- project = glade_project_new ();
-
- retval = glade_project_load_from_file (project, path);
-
- if (retval)
- {
- return project;
- }
- else
- {
- g_object_unref (project);
- return NULL;
- }
-}
-
-static void
-glade_project_move_resources (GladeProject *project,
- const gchar *old_dir,
- const gchar *new_dir)
-{
- GList *list, *resources;
- gchar *old_name, *new_name;
-
- if (old_dir == NULL || /* <-- Cant help you :( */
- new_dir == NULL) /* <-- Unlikely */
- return;
-
- if ((resources = /* Nothing to do here */
- glade_project_list_resources (project)) == NULL)
- return;
-
- for (list = resources; list; list = list->next)
- {
- old_name = g_build_filename
- (old_dir, (gchar *)list->data, NULL);
- new_name = g_build_filename
- (new_dir, (gchar *)list->data, NULL);
- glade_util_copy_file (old_name, new_name);
- g_free (old_name);
- g_free (new_name);
- }
- g_list_free (resources);
-}
-
-/**
- * glade_project_save:
- * @project: a #GladeProject
- * @path: location to save glade file
- * @error: an error from the G_FILE_ERROR domain.
- *
- * Saves @project to the given path.
- *
- * Returns: %TRUE on success, %FALSE on failure
- */
-gboolean
-glade_project_save (GladeProject *project, const gchar *path, GError **error)
-{
- GladeXmlContext *context;
- GladeXmlDoc *doc;
- gchar *canonical_path;
- gint ret;
-
- if (!glade_project_verify (project, TRUE))
- return FALSE;
-
- context = glade_project_write (project);
- doc = glade_xml_context_get_doc (context);
- ret = glade_xml_doc_save (doc, path);
- glade_xml_context_destroy (context);
-
- canonical_path = glade_util_canonical_path (path);
- g_assert (canonical_path);
-
- if (project->priv->path == NULL ||
- strcmp (canonical_path, project->priv->path))
- {
- gchar *old_dir, *new_dir;
-
- if (project->priv->path)
- {
- old_dir = g_path_get_dirname (project->priv->path);
- new_dir = g_path_get_dirname (canonical_path);
-
- glade_project_move_resources (project,
- old_dir,
- new_dir);
- g_free (old_dir);
- g_free (new_dir);
- }
- project->priv->path = (g_free (project->priv->path),
- g_strdup (canonical_path));
- }
-
- glade_project_set_readonly (project,
- !glade_util_file_is_writeable (project->priv->path));
-
- project->priv->mtime = glade_util_get_file_mtime (project->priv->path, NULL);
-
- glade_project_set_modified (project, FALSE);
-
- if (project->priv->unsaved_number > 0)
- {
- glade_id_allocator_release (get_unsaved_number_allocator (), project->priv->unsaved_number);
- project->priv->unsaved_number = 0;
- }
-
- g_free (canonical_path);
-
- return ret > 0;
-}
-
-
/**
* glade_project_undo:
* @project: a #GladeProject
@@ -3048,6 +3302,113 @@ glade_project_set_accel_group (GladeProject *project, GtkAccelGroup *accel_group
project->priv->accel_group = accel_group;
}
+
+
+
+static void
+gp_sync_resources (GladeProject *project,
+ GladeProject *prev_project,
+ GladeWidget *gwidget,
+ gboolean remove)
+{
+ GList *prop_list, *l;
+ GladeProperty *property;
+ gchar *resource, *full_resource;
+
+ prop_list = g_list_copy (gwidget->properties);
+ prop_list = g_list_concat
+ (prop_list, g_list_copy (gwidget->packing_properties));
+
+ for (l = prop_list; l; l = l->next)
+ {
+ property = l->data;
+ if (property->klass->resource)
+ {
+ GValue value = { 0, };
+
+ if (remove)
+ {
+ glade_project_set_resource (project, property, NULL);
+ continue;
+ }
+
+ glade_property_get_value (property, &value);
+
+ if ((resource = glade_widget_adaptor_string_from_value
+ (GLADE_WIDGET_ADAPTOR (property->klass->handle),
+ property->klass, &value, project->priv->format)) != NULL)
+ {
+ full_resource = glade_project_resource_fullpath
+ (prev_project ? prev_project : project, resource);
+
+ /* Use a full path here so that the current
+ * working directory isnt used.
+ */
+ glade_project_set_resource (project,
+ property,
+ full_resource);
+
+ g_free (full_resource);
+ g_free (resource);
+ }
+ g_value_unset (&value);
+ }
+ }
+ g_list_free (prop_list);
+}
+
+static void
+glade_project_sync_resources_for_widget (GladeProject *project,
+ GladeProject *prev_project,
+ GladeWidget *gwidget,
+ gboolean remove)
+{
+ GList *children, *l;
+ GladeWidget *gchild;
+
+ children = glade_widget_adaptor_get_children
+ (gwidget->adaptor, gwidget->object);
+
+ for (l = children; l; l = l->next)
+ if ((gchild =
+ glade_widget_get_from_gobject (l->data)) != NULL)
+ glade_project_sync_resources_for_widget
+ (project, prev_project, gchild, remove);
+ if (children)
+ g_list_free (children);
+
+ gp_sync_resources (project, prev_project, gwidget, remove);
+}
+
+static void
+glade_project_move_resources (GladeProject *project,
+ const gchar *old_dir,
+ const gchar *new_dir)
+{
+ GList *list, *resources;
+ gchar *old_name, *new_name;
+
+ if (old_dir == NULL || /* <-- Cant help you :( */
+ new_dir == NULL) /* <-- Unlikely */
+ return;
+
+ if ((resources = /* Nothing to do here */
+ glade_project_list_resources (project)) == NULL)
+ return;
+
+ for (list = resources; list; list = list->next)
+ {
+ old_name = g_build_filename
+ (old_dir, (gchar *)list->data, NULL);
+ new_name = g_build_filename
+ (new_dir, (gchar *)list->data, NULL);
+ glade_util_copy_file (old_name, new_name);
+ g_free (old_name);
+ g_free (new_name);
+ }
+ g_list_free (resources);
+}
+
/**
* glade_project_resource_fullpath:
* @project: The #GladeProject.
@@ -3288,6 +3649,48 @@ glade_project_get_modified (GladeProject *project)
return project->priv->modified;
}
+void
+glade_project_set_naming_policy (GladeProject *project,
+ GladeNamingPolicy policy,
+ gboolean use_command)
+{
+ g_return_if_fail (GLADE_IS_PROJECT (project));
+
+ if (project->priv->naming_policy != policy)
+ {
+ project->priv->naming_policy = policy;
+
+ adjust_naming_policy (project, use_command);
+
+ /* Update the toggle button in the prefs dialog here: */
+ g_signal_handlers_block_by_func (project->priv->project_wide_radio,
+ G_CALLBACK (policy_project_wide_button_clicked), project);
+ g_signal_handlers_block_by_func (project->priv->toplevel_contextual_radio,
+ G_CALLBACK (policy_toplevel_contextual_button_clicked), project);
+
+ if (policy == GLADE_POLICY_PROJECT_WIDE)
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (project->priv->project_wide_radio), TRUE);
+ else
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (project->priv->toplevel_contextual_radio), TRUE);
+
+ g_signal_handlers_unblock_by_func (project->priv->project_wide_radio,
+ G_CALLBACK (policy_project_wide_button_clicked), project);
+ g_signal_handlers_unblock_by_func (project->priv->toplevel_contextual_radio,
+ G_CALLBACK (policy_toplevel_contextual_button_clicked), project);
+
+ }
+
+
+}
+
+GladeNamingPolicy
+glade_project_get_naming_policy (GladeProject *project)
+{
+ g_return_val_if_fail (GLADE_IS_PROJECT (project), -1);
+
+ return project->priv->naming_policy;
+}
+
/**
* glade_project_set_format:
@@ -3307,6 +3710,23 @@ glade_project_set_format (GladeProject *project, GladeProjectFormat format)
project->priv->format = format;
g_object_notify (G_OBJECT (project), "format");
glade_project_verify_project_for_ui (project);
+
+ /* Update the toggle button in the prefs dialog here: */
+ g_signal_handlers_block_by_func (project->priv->glade_radio,
+ G_CALLBACK (format_libglade_button_clicked), project);
+ g_signal_handlers_block_by_func (project->priv->builder_radio,
+ G_CALLBACK (format_builder_button_clicked), project);
+
+ if (format == GLADE_PROJECT_FORMAT_GTKBUILDER)
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (project->priv->builder_radio), TRUE);
+ else
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (project->priv->glade_radio), TRUE);
+
+ g_signal_handlers_unblock_by_func (project->priv->glade_radio,
+ G_CALLBACK (format_libglade_button_clicked), project);
+ g_signal_handlers_unblock_by_func (project->priv->builder_radio,
+ G_CALLBACK (format_builder_button_clicked), project);
+
}
}
@@ -3334,6 +3754,20 @@ format_builder_button_clicked (GtkWidget *widget,
}
static void
+policy_project_wide_button_clicked (GtkWidget *widget,
+ GladeProject *project)
+{
+ glade_command_set_project_naming_policy (project, GLADE_POLICY_PROJECT_WIDE);
+}
+
+static void
+policy_toplevel_contextual_button_clicked (GtkWidget *widget,
+ GladeProject *project)
+{
+ glade_command_set_project_naming_policy (project, GLADE_POLICY_TOPLEVEL_CONTEXTUAL);
+}
+
+static void
target_button_clicked (GtkWidget *widget,
GladeProject *project)
{
@@ -3369,20 +3803,123 @@ glade_project_build_prefs_box (GladeProject *project)
{
GtkWidget *main_box, *button;
GtkWidget *vbox, *hbox, *frame;
- GtkWidget *glade_radio, *builder_radio, *target_radio, *active_radio;
+ GtkWidget *target_radio, *active_radio;
GtkWidget *label, *alignment;
GList *list, *targets;
- gchar *string = g_strdup_printf ("<b>%s</b>", _("File format"));
+ gchar *string;
+ GtkWidget *main_frame, *main_alignment;
+ GtkSizeGroup *sizegroup1 = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL),
+ *sizegroup2 = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+
+ string = g_strdup_printf ("<big><b>%s</b></big>", _("Set options in your project"));
+ main_frame = gtk_frame_new (NULL);
+ main_alignment = gtk_alignment_new (0.5F, 0.5F, 0.8F, 0.8F);
main_box = gtk_vbox_new (FALSE, 0);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (main_alignment), 12, 0, 4, 0);
+
+ label = gtk_label_new (string);
+ g_free (string);
+ gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+
+ gtk_frame_set_label_widget (GTK_FRAME (main_frame), label);
+ gtk_container_add (GTK_CONTAINER (main_alignment), main_box);
+ gtk_container_add (GTK_CONTAINER (main_frame), main_alignment);
+
+
+ /* Project format */
+ string = g_strdup_printf ("<b>%s</b>", _("File format"));
+ frame = gtk_frame_new (NULL);
+ hbox = gtk_hbox_new (FALSE, 0);
+ alignment = gtk_alignment_new (0.5F, 0.5F, 0.8F, 0.8F);
+
+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 8, 0, 12, 0);
+
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
+
+ label = gtk_label_new (string);
+ g_free (string);
+ gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+
+ project->priv->glade_radio = gtk_radio_button_new_with_label (NULL, "Libglade");
+ project->priv->builder_radio = gtk_radio_button_new_with_label_from_widget
+ (GTK_RADIO_BUTTON (project->priv->glade_radio), "GtkBuilder");
+
+ gtk_size_group_add_widget (sizegroup1, project->priv->builder_radio);
+ gtk_size_group_add_widget (sizegroup2, project->priv->glade_radio);
+
+ gtk_frame_set_label_widget (GTK_FRAME (frame), label);
+ gtk_container_add (GTK_CONTAINER (alignment), hbox);
+ gtk_container_add (GTK_CONTAINER (frame), alignment);
+
+ gtk_box_pack_start (GTK_BOX (hbox), project->priv->builder_radio, TRUE, TRUE, 2);
+ gtk_box_pack_start (GTK_BOX (hbox), project->priv->glade_radio, TRUE, TRUE, 2);
+
+ gtk_box_pack_start (GTK_BOX (main_box), frame, TRUE, TRUE, 2);
+
+
+ if (glade_project_get_format (project) == GLADE_PROJECT_FORMAT_GTKBUILDER)
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (project->priv->builder_radio), TRUE);
+ else
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (project->priv->glade_radio), TRUE);
+
+ g_signal_connect (G_OBJECT (project->priv->glade_radio), "clicked",
+ G_CALLBACK (format_libglade_button_clicked), project);
+
+ g_signal_connect (G_OBJECT (project->priv->builder_radio), "clicked",
+ G_CALLBACK (format_builder_button_clicked), project);
+
+
+ /* Naming policy format */
+ string = g_strdup_printf ("<b>%s</b>", _("Object names are unique:"));
+ frame = gtk_frame_new (NULL);
+ hbox = gtk_hbox_new (FALSE, 0);
+ alignment = gtk_alignment_new (0.5F, 0.5F, 0.8F, 0.8F);
+
+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 8, 0, 12, 0);
+
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
+
+ label = gtk_label_new (string);
+ g_free (string);
+ gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+
+ project->priv->project_wide_radio = gtk_radio_button_new_with_label (NULL, _("within the project"));
+ project->priv->toplevel_contextual_radio = gtk_radio_button_new_with_label_from_widget
+ (GTK_RADIO_BUTTON (project->priv->project_wide_radio), _("inside toplevels"));
+
+ gtk_size_group_add_widget (sizegroup1, project->priv->project_wide_radio);
+ gtk_size_group_add_widget (sizegroup2, project->priv->toplevel_contextual_radio);
+
+ gtk_box_pack_start (GTK_BOX (hbox), project->priv->project_wide_radio, TRUE, TRUE, 2);
+ gtk_box_pack_start (GTK_BOX (hbox), project->priv->toplevel_contextual_radio, TRUE, TRUE, 2);
+
+ gtk_frame_set_label_widget (GTK_FRAME (frame), label);
+ gtk_container_add (GTK_CONTAINER (alignment), hbox);
+ gtk_container_add (GTK_CONTAINER (frame), alignment);
+
+ gtk_box_pack_start (GTK_BOX (main_box), frame, TRUE, TRUE, 6);
+
+ if (project->priv->naming_policy == GLADE_POLICY_PROJECT_WIDE)
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (project->priv->project_wide_radio), TRUE);
+ else
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (project->priv->toplevel_contextual_radio), TRUE);
+
+ g_signal_connect (G_OBJECT (project->priv->project_wide_radio), "clicked",
+ G_CALLBACK (policy_project_wide_button_clicked), project);
+
+ g_signal_connect (G_OBJECT (project->priv->toplevel_contextual_radio), "clicked",
+ G_CALLBACK (policy_toplevel_contextual_button_clicked), project);
+
+
/* Target versions */
- string = g_strdup_printf ("<b>%s</b>", _("Target Versions:"));
+ string = g_strdup_printf ("<b>%s</b>", _("Target versions:"));
frame = gtk_frame_new (NULL);
vbox = gtk_vbox_new (FALSE, 0);
alignment = gtk_alignment_new (0.5F, 0.5F, 1.0F, 1.0F);
- gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 2, 0, 12, 0);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 8, 0, 12, 0);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
@@ -3394,7 +3931,7 @@ glade_project_build_prefs_box (GladeProject *project)
gtk_container_add (GTK_CONTAINER (alignment), vbox);
gtk_container_add (GTK_CONTAINER (frame), alignment);
- gtk_box_pack_start (GTK_BOX (main_box), frame, TRUE, TRUE, 2);
+ gtk_box_pack_start (GTK_BOX (main_box), frame, TRUE, TRUE, 6);
/* Add stuff to vbox */
for (list = glade_app_get_catalogs (); list; list = list->next)
@@ -3455,105 +3992,50 @@ glade_project_build_prefs_box (GladeProject *project)
}
if (active_radio)
+ {
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (active_radio), TRUE);
+ g_hash_table_insert (project->priv->target_radios,
+ g_strdup (glade_catalog_get_name (catalog)),
+ gtk_radio_button_get_group (GTK_RADIO_BUTTON (active_radio)));
+ }
else
g_warning ("Corrupt catalog versions");
- gtk_box_pack_end (GTK_BOX (vbox), hbox, TRUE, TRUE, 2);
-
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 2);
}
- /* Project format */
- string = g_strdup_printf ("<b>%s</b>", _("File format"));
- frame = gtk_frame_new (NULL);
- hbox = gtk_hbox_new (FALSE, 0);
- alignment = gtk_alignment_new (0.5F, 0.5F, 0.8F, 0.8F);
-
- gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 2, 0, 12, 0);
-
- gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
-
- label = gtk_label_new (string);
- g_free (string);
- gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
-
- glade_radio = gtk_radio_button_new_with_label (NULL, "Libglade");
- builder_radio = gtk_radio_button_new_with_label_from_widget
- (GTK_RADIO_BUTTON (glade_radio), "GtkBuilder");
-
- if (glade_project_get_format (project) == GLADE_PROJECT_FORMAT_GTKBUILDER)
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (builder_radio), TRUE);
- else
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (glade_radio), TRUE);
-
- g_signal_connect (G_OBJECT (glade_radio), "clicked",
- G_CALLBACK (format_libglade_button_clicked), project);
-
- g_signal_connect (G_OBJECT (builder_radio), "clicked",
- G_CALLBACK (format_builder_button_clicked), project);
-
- gtk_box_pack_start (GTK_BOX (hbox), builder_radio, TRUE, TRUE, 2);
- gtk_box_pack_start (GTK_BOX (hbox), glade_radio, TRUE, TRUE, 2);
-
- gtk_frame_set_label_widget (GTK_FRAME (frame), label);
- gtk_container_add (GTK_CONTAINER (alignment), hbox);
- gtk_container_add (GTK_CONTAINER (frame), alignment);
-
- gtk_box_pack_start (GTK_BOX (main_box), frame, TRUE, TRUE, 2);
-
-
/* Run verify */
- string = g_strdup_printf ("<b>%s</b>", _("Verify versions and deprecations:"));
- frame = gtk_frame_new (NULL);
- alignment = gtk_alignment_new (0.0F, 0.5F, 0.0F, 0.0F);
- gtk_container_set_border_width (GTK_CONTAINER (alignment), 4);
-
+ hbox = gtk_hbox_new (FALSE, 2);
button = gtk_button_new_from_stock (GTK_STOCK_EXECUTE);
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (verify_clicked), project);
- gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 2, 4, 12, 0);
-
- gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
+ label = gtk_label_new (_("Verify versions and deprecations:"));
- label = gtk_label_new (string);
- g_free (string);
- gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+ gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 4);
+ gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 4);
- gtk_frame_set_label_widget (GTK_FRAME (frame), label);
- gtk_container_add (GTK_CONTAINER (alignment), button);
- gtk_container_add (GTK_CONTAINER (frame), alignment);
-
- gtk_box_pack_start (GTK_BOX (main_box), frame, FALSE, FALSE, 4);
-
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 4);
- gtk_widget_show_all (main_box);
+ gtk_widget_show_all (main_frame);
- return main_box;
+ return main_frame;
}
-/**
- * glade_project_preferences:
- * @project: A #GladeProject
- *
- * Runs a preferences dialog for @project.
- */
-void
-glade_project_preferences (GladeProject *project)
+static GtkWidget *
+glade_project_build_prefs_dialog (GladeProject *project)
{
- GtkWidget *dialog = NULL;
- GtkWidget *widget;
+ GtkWidget *widget, *dialog;
gchar *title, *name;
-
- g_return_if_fail (GLADE_IS_PROJECT (project));
-
name = glade_project_get_name (project);
- title = g_strdup_printf ("%s preferences", name);
+ title = g_strdup_printf (_("%s preferences"), name);
dialog = gtk_dialog_new_with_buttons (title,
GTK_WINDOW (glade_app_get_window ()),
GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_CLOSE,
+ GTK_RESPONSE_ACCEPT,
NULL);
g_free (title);
g_free (name);
@@ -3567,13 +4049,34 @@ glade_project_preferences (GladeProject *project)
gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+ /* HIG spacings */
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 2); /* 2 * 5 + 2 = 12 */
+ gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area), 5);
+ gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->action_area), 6);
+
/* Were explicitly destroying it anyway */
g_signal_connect (G_OBJECT (dialog), "delete-event",
G_CALLBACK (gtk_widget_hide_on_delete), NULL);
- gtk_window_present (GTK_WINDOW (dialog));
+ /* Only one action, used to "close" the dialog */
+ g_signal_connect (G_OBJECT (dialog), "response",
+ G_CALLBACK (gtk_widget_hide), NULL);
+
+ return dialog;
+}
+
+/**
+ * glade_project_preferences:
+ * @project: A #GladeProject
+ *
+ * Runs a preferences dialog for @project.
+ */
+void
+glade_project_preferences (GladeProject *project)
+{
+ g_return_if_fail (GLADE_IS_PROJECT (project));
- gtk_dialog_run (GTK_DIALOG (dialog));
- gtk_widget_destroy (dialog);
+ gtk_window_present (GTK_WINDOW (project->priv->prefs_dialog));
}
diff --git a/gladeui/glade-project.h b/gladeui/glade-project.h
index afbffd36..904d1562 100644
--- a/gladeui/glade-project.h
+++ b/gladeui/glade-project.h
@@ -22,11 +22,11 @@ typedef struct _GladeProjectClass GladeProjectClass;
typedef enum
{
- GLADE_SUPPORT_OK = 0x00,
- GLADE_SUPPORT_DEPRECATED = 0x01,
- GLADE_SUPPORT_MISMATCH = 0x02,
- GLADE_SUPPORT_LIBGLADE_UNSUPPORTED = 0x04,
- GLADE_SUPPORT_LIBGLADE_ONLY = 0x08
+ GLADE_SUPPORT_OK = 0,
+ GLADE_SUPPORT_DEPRECATED = (0x01 << 0),
+ GLADE_SUPPORT_MISMATCH = (0x01 << 1),
+ GLADE_SUPPORT_LIBGLADE_UNSUPPORTED = (0x01 << 2),
+ GLADE_SUPPORT_LIBGLADE_ONLY = (0x01 << 3)
} GladeSupportMask;
struct _GladeProject
@@ -111,16 +111,26 @@ void glade_project_add_object (GladeProject *project,
GladeProject *old_project,
GObject *object);
-void glade_project_remove_object (GladeProject *project, GObject *object);
+void glade_project_remove_object (GladeProject *project,
+ GObject *object);
+
+gboolean glade_project_has_object (GladeProject *project,
+ GObject *object);
-gboolean glade_project_has_object (GladeProject *project, GObject *object);
+GladeWidget *glade_project_get_widget_by_name (GladeProject *project,
+ GladeWidget *ancestor,
+ const gchar *name);
-GladeWidget *glade_project_get_widget_by_name (GladeProject *project, const char *name);
+void glade_project_set_widget_name (GladeProject *project,
+ GladeWidget *widget,
+ const gchar *name);
-char *glade_project_new_widget_name (GladeProject *project, const char *base_name);
+gchar *glade_project_new_widget_name (GladeProject *project,
+ GladeWidget *widget,
+ const gchar *base_name);
-void glade_project_widget_name_changed (GladeProject *project, GladeWidget *widget,
- const char *old_name);
+gboolean glade_project_available_widget_name (GladeProject *project, GladeWidget *widget,
+ const gchar *name);
/* Selection */
@@ -187,8 +197,13 @@ void glade_project_verify_project_for_ui (GladeProject *project);
gboolean glade_project_is_loaded_factory_file (GladeProject *project,
const gchar *stock_id);
-GList *glade_project_required_libs (GladeProject *project);
+GList *glade_project_required_libs (GladeProject *project);
+
+void glade_project_set_naming_policy (GladeProject *project,
+ GladeNamingPolicy policy,
+ gboolean use_command);
+GladeNamingPolicy glade_project_get_naming_policy (GladeProject *project);
G_END_DECLS
diff --git a/gladeui/glade-property-class.c b/gladeui/glade-property-class.c
index 2463ebbe..90002370 100644
--- a/gladeui/glade-property-class.c
+++ b/gladeui/glade-property-class.c
@@ -85,6 +85,7 @@ glade_property_class_new (gpointer handle)
property_class->save = TRUE;
property_class->save_always = FALSE;
property_class->ignore = FALSE;
+ property_class->needs_sync = FALSE;
property_class->resource = FALSE;
property_class->themed_icon = FALSE;
property_class->translatable = FALSE;
@@ -628,7 +629,8 @@ glade_property_class_make_enum_from_string (GType type, const char *string)
static GObject *
glade_property_class_make_object_from_string (GladePropertyClass *property_class,
const gchar *string,
- GladeProject *project)
+ GladeProject *project,
+ GladeWidget *widget)
{
GObject *object = NULL;
gchar *fullpath;
@@ -668,7 +670,7 @@ glade_property_class_make_object_from_string (GladePropertyClass *property_class
g_free (fullpath);
}
- if (glade_project_get_format (project) == GLADE_PROJECT_FORMAT_LIBGLADE &&
+ if (project && glade_project_get_format (project) == GLADE_PROJECT_FORMAT_LIBGLADE &&
property_class->pspec->value_type == GTK_TYPE_ADJUSTMENT)
{
gdouble value, lower, upper, step_increment, page_increment, page_size;
@@ -687,7 +689,7 @@ glade_property_class_make_object_from_string (GladePropertyClass *property_class
{
GladeWidget *gwidget;
if ((gwidget = glade_project_get_widget_by_name
- (project, string)) != NULL)
+ (project, widget, string)) != NULL)
object = gwidget->object;
}
@@ -697,7 +699,8 @@ glade_property_class_make_object_from_string (GladePropertyClass *property_class
static GList *
glade_property_class_make_objects_from_string (GladePropertyClass *property_class,
const gchar *string,
- GladeProject *project)
+ GladeProject *project,
+ GladeWidget *widget)
{
GList *objects = NULL;
GObject *object;
@@ -709,7 +712,7 @@ glade_property_class_make_objects_from_string (GladePropertyClass *property_clas
for (i = 0; split[i]; i++)
{
if ((object = glade_property_class_make_object_from_string
- (property_class, split[i], project)) != NULL)
+ (property_class, split[i], project, widget)) != NULL)
objects = g_list_prepend (objects, object);
}
g_strfreev (split);
@@ -721,8 +724,7 @@ glade_property_class_make_objects_from_string (GladePropertyClass *property_clas
* glade_property_class_make_gvalue_from_string:
* @property_class: A #GladePropertyClass
* @string: a string representation of this property
- * @project: the glade project that the associated property
- * belongs to.
+ * @widget: the #GladeWidget that the associated property belongs to.
*
* Returns: A #GValue created based on the @property_class
* and @string criteria.
@@ -730,7 +732,8 @@ glade_property_class_make_objects_from_string (GladePropertyClass *property_clas
GValue *
glade_property_class_make_gvalue_from_string (GladePropertyClass *property_class,
const gchar *string,
- GladeProject *project)
+ GladeProject *project,
+ GladeWidget *widget)
{
GValue *value = g_new0 (GValue, 1);
gchar **strv, *fullpath;
@@ -831,13 +834,13 @@ glade_property_class_make_gvalue_from_string (GladePropertyClass *property_class
else if (G_IS_PARAM_SPEC_OBJECT(property_class->pspec))
{
GObject *object = glade_property_class_make_object_from_string
- (property_class, string, project);
+ (property_class, string, project, widget);
g_value_set_object (value, object);
}
else if (GLADE_IS_PARAM_SPEC_OBJECTS (property_class->pspec))
{
GList *objects = glade_property_class_make_objects_from_string
- (property_class, string, project);
+ (property_class, string, project, widget);
g_value_set_boxed (value, objects);
}
else
@@ -1459,7 +1462,7 @@ glade_property_class_update_from_node (GladeXmlNode *node,
g_value_unset (klass->def);
g_free (klass->def);
}
- klass->def = glade_property_class_make_gvalue_from_string (klass, buf, NULL);
+ klass->def = glade_property_class_make_gvalue_from_string (klass, buf, NULL, NULL);
g_free (buf);
}
@@ -1519,6 +1522,7 @@ glade_property_class_update_from_node (GladeXmlNode *node,
klass->save = glade_xml_get_property_boolean (node, GLADE_TAG_SAVE, klass->save);
klass->visible = glade_xml_get_property_boolean (node, GLADE_TAG_VISIBLE, klass->visible);
klass->ignore = glade_xml_get_property_boolean (node, GLADE_TAG_IGNORE, klass->ignore);
+ klass->needs_sync = glade_xml_get_property_boolean (node, GLADE_TAG_NEEDS_SYNC, klass->needs_sync);
klass->resource = glade_xml_get_property_boolean (node, GLADE_TAG_RESOURCE, klass->resource);
klass->themed_icon = glade_xml_get_property_boolean (node, GLADE_TAG_THEMED_ICON, klass->themed_icon);
klass->weight = glade_xml_get_property_double (node, GLADE_TAG_WEIGHT, klass->weight);
@@ -1651,6 +1655,8 @@ glade_property_class_compare (GladePropertyClass *klass,
if (G_VALUE_HOLDS_BOXED (value1))
{
gchar *val1, *val2;
+
+ /* This has got to change... */
val1 = glade_widget_adaptor_string_from_value (klass->handle, klass, value1, fmt);
val2 = glade_widget_adaptor_string_from_value (klass->handle, klass, value2, fmt);
@@ -1662,6 +1668,9 @@ glade_property_class_compare (GladePropertyClass *klass,
g_free (val1);
g_free (val2);
+
+ /* boxed always changed... XXX */
+ return -1;
}
else
{
diff --git a/gladeui/glade-property-class.h b/gladeui/glade-property-class.h
index fd3c6a06..73903a52 100644
--- a/gladeui/glade-property-class.h
+++ b/gladeui/glade-property-class.h
@@ -133,6 +133,12 @@ struct _GladePropertyClass
* changes, or load values from the object.
*/
+ gboolean needs_sync; /* Virtual properties need to be synchronized after object
+ * creation, some properties that are not virtual also need
+ * handling from the backend, if "needs-sync" is true then
+ * this property will by synced with virtual properties.
+ */
+
gboolean is_modified; /* If true, this property_class has been "modified" from the
* the standard property by a xml file. */
@@ -197,7 +203,8 @@ gboolean glade_property_class_is_object (GladePropertyC
GValue *glade_property_class_make_gvalue_from_string (GladePropertyClass *property_class,
const gchar *string,
- GladeProject *project);
+ GladeProject *project,
+ GladeWidget *widget);
gchar *glade_property_class_make_string_from_gvalue (GladePropertyClass *property_class,
const GValue *value,
diff --git a/gladeui/glade-property.c b/gladeui/glade-property.c
index be24fc52..ec4a4467 100644
--- a/gladeui/glade-property.c
+++ b/gladeui/glade-property.c
@@ -1038,8 +1038,7 @@ glade_property_read (GladeProperty *property,
if (fmt == GLADE_PROJECT_FORMAT_GTKBUILDER)
{
gboolean is_loaded_value =
- glade_project_is_loaded_factory_file
- (property->widget->project, value);
+ glade_project_is_loaded_factory_file (project, value);
if (property->klass->factory_stock_id && is_loaded_value)
search_name = property->klass->factory_stock_id;
@@ -1085,7 +1084,7 @@ glade_property_read (GladeProperty *property,
}
gvalue = glade_property_class_make_gvalue_from_string
- (property->klass, value, project);
+ (property->klass, value, project, property->widget);
if (property)
{
diff --git a/gladeui/glade-utils.c b/gladeui/glade-utils.c
index f67e14e2..e82461c0 100644
--- a/gladeui/glade-utils.c
+++ b/gladeui/glade-utils.c
@@ -1943,7 +1943,7 @@ glade_utils_enum_value_from_string (GType enum_type, const gchar *strval)
gint value = 0;
GValue *gvalue;
- if ((gvalue = glade_utils_value_from_string (enum_type, strval, NULL)) != NULL)
+ if ((gvalue = glade_utils_value_from_string (enum_type, strval, NULL, NULL)) != NULL)
{
value = g_value_get_enum (gvalue);
g_value_unset (gvalue);
@@ -2075,6 +2075,8 @@ pclass_from_gtype (GType type)
* @type: a #GType to convert with
* @string: the string to convert
* @project: the #GladeProject to look for formats of object names when needed
+ * @widget: if the value is a gobject, this #GladeWidget will be used to look
+ * for an object in the same widget tree.
*
* Allocates and sets a #GValue of type @type
* set to @string (using glade conversion routines)
@@ -2084,7 +2086,8 @@ pclass_from_gtype (GType type)
GValue *
glade_utils_value_from_string (GType type,
const gchar *string,
- GladeProject *project)
+ GladeProject *project,
+ GladeWidget *widget)
{
GladePropertyClass *pclass;
@@ -2092,7 +2095,7 @@ glade_utils_value_from_string (GType type,
g_return_val_if_fail (string != NULL, NULL);
if ((pclass = pclass_from_gtype (type)) != NULL)
- return glade_property_class_make_gvalue_from_string (pclass, string, project);
+ return glade_property_class_make_gvalue_from_string (pclass, string, project, widget);
return NULL;
}
diff --git a/gladeui/glade-utils.h b/gladeui/glade-utils.h
index cf47bd85..fe05abd3 100644
--- a/gladeui/glade-utils.h
+++ b/gladeui/glade-utils.h
@@ -139,12 +139,16 @@ gchar *glade_utils_enum_string_from_value (GType enum_type, gint valu
GValue *glade_utils_value_from_string (GType type,
const gchar *string,
- GladeProject *project);
+ GladeProject *project,
+ GladeWidget *widget);
+
gchar *glade_utils_string_from_value (const GValue *value,
GladeProject *project);
GtkListStore *glade_utils_liststore_from_enum_type (GType enum_type, gboolean include_empty);
+
+
G_END_DECLS
#endif /* __GLADE_UTILS_H__ */
diff --git a/gladeui/glade-widget.c b/gladeui/glade-widget.c
index 84b8c820..dead8c2a 100644
--- a/gladeui/glade-widget.c
+++ b/gladeui/glade-widget.c
@@ -619,7 +619,7 @@ glade_widget_sync_custom_props (GladeWidget *widget)
{
GladeProperty *prop = GLADE_PROPERTY(l->data);
- if (prop->klass->virt)
+ if (prop->klass->virt || prop->klass->needs_sync)
glade_property_sync (prop);
}
@@ -662,6 +662,7 @@ glade_widget_constructor (GType type,
{
gwidget->name =
glade_project_new_widget_name (gwidget->project,
+ gwidget,
name_base);
g_free (name_base);
}
@@ -671,7 +672,7 @@ glade_widget_constructor (GType type,
}
else if (gwidget->project)
gwidget->name = glade_project_new_widget_name
- (GLADE_PROJECT (gwidget->project),
+ (gwidget->project, gwidget,
gwidget->adaptor->generic_name);
else
gwidget->name =
@@ -1228,7 +1229,8 @@ glade_widget_set_default_packing_properties (GladeWidget *container,
value = glade_property_class_make_gvalue_from_string (property_class,
def,
- child->project);
+ child->project,
+ child);
glade_widget_child_set_property (container, child,
property_class->id, value);
@@ -2377,15 +2379,8 @@ void
glade_widget_set_name (GladeWidget *widget, const gchar *name)
{
g_return_if_fail (GLADE_IS_WIDGET (widget));
- if (widget->name != name) {
-
- if (widget->project &&
- glade_project_get_widget_by_name (widget->project, name))
- {
- /* print a warning ? */
- return;
- }
-
+ if (widget->name != name)
+ {
if (widget->name)
g_free (widget->name);
diff --git a/gladeui/glade-xml-utils.h b/gladeui/glade-xml-utils.h
index 2633100a..228839d8 100644
--- a/gladeui/glade-xml-utils.h
+++ b/gladeui/glade-xml-utils.h
@@ -36,6 +36,12 @@ typedef enum
} GladeProjectFormat;
+typedef enum {
+ GLADE_POLICY_PROJECT_WIDE = 0, /* widget names are unique throughout the project */
+ GLADE_POLICY_TOPLEVEL_CONTEXTUAL /* toplevel names are unique, and widgets inside a toplevel */
+} GladeNamingPolicy;
+
+
#define GLADE_XML_TAG_PROJECT(type) \
((type == GLADE_PROJECT_FORMAT_LIBGLADE) ? \
GLADE_XML_TAG_LIBGLADE_PROJECT : GLADE_XML_TAG_BUILDER_PROJECT)
@@ -108,6 +114,7 @@ typedef enum
#define GLADE_TAG_PARENTLESS_WIDGET "parentless-widget"
#define GLADE_TAG_DISABLED "disabled"
#define GLADE_TAG_CONSTRUCT_ONLY "construct-only"
+#define GLADE_TAG_NEEDS_SYNC "needs-sync"
#define GLADE_TAG_DEFAULT_PALETTE_STATE "default-palette-state"
#define GLADE_TAG_PROJECT_CONVERT_FUNCTION "project-convert-function"
#define GLADE_TAG_REPLACE_CHILD_FUNCTION "replace-child-function"
diff --git a/plugins/gnome/glade-gnome.c b/plugins/gnome/glade-gnome.c
index 66b0e3b5..0aa68629 100644
--- a/plugins/gnome/glade-gnome.c
+++ b/plugins/gnome/glade-gnome.c
@@ -597,7 +597,7 @@ glade_gnome_dps_set_color_common (GObject *object,
property_name);
color = glade_property_class_make_gvalue_from_string (prop->klass,
- color_str, NULL);
+ color_str, NULL, NULL);
if (color) glade_property_set_value (prop, color);
}
diff --git a/plugins/gtk+/glade-column-types.c b/plugins/gtk+/glade-column-types.c
index 15c2d974..ba62f2ed 100644
--- a/plugins/gtk+/glade-column-types.c
+++ b/plugins/gtk+/glade-column-types.c
@@ -223,106 +223,31 @@ glade_eprop_column_types_finalize (GObject *object)
}
static void
-eprop_reload_value (GladeEPropColumnTypes *eprop_types)
+eprop_column_append (GladeEditorProperty *eprop,
+ GType type,
+ const gchar *column_name)
{
- GladeEditorProperty *eprop = GLADE_EDITOR_PROPERTY (eprop_types);
- GtkTreeModel *model = GTK_TREE_MODEL (eprop_types->store);
- GValue value = {0, };
- GtkTreeIter iter;
- GList *list = NULL, *l;
- GNode *data_tree = NULL;
-
- if (gtk_tree_model_get_iter_first (model, &iter))
- {
- do
- {
- GladeColumnType *data = g_new0(GladeColumnType, 1);
-
- gtk_tree_model_get (model, &iter,
- COLUMN_COLUMN_NAME, &data->column_name,
- COLUMN_GTYPE, &data->type,
- -1);
-
- list = g_list_append (list, data);
- } while (gtk_tree_model_iter_next (model, &iter));
- }
-
- glade_widget_property_get (eprop->property->widget, "data", &data_tree);
- if (data_tree)
- {
- GNode *row, *iter;
- gint colnum;
- data_tree = glade_model_data_tree_copy (data_tree);
-
- glade_command_push_group (_("Setting columns of %s"), eprop->property->widget->name);
-
- /* Remove extra columns */
- for (row = data_tree->children; row; row = row->next)
- {
-
- for (colnum = 0, iter = row->children; iter;
- colnum++, iter = iter->next)
- {
+ GladeEPropColumnTypes *eprop_types = GLADE_EPROP_COLUMN_TYPES (eprop);
+ GList *columns = NULL;
+ GladeColumnType *data;
+ GValue value = { 0, };
- }
- }
+ glade_property_get (eprop->property, &columns);
+ if (columns)
+ columns = glade_column_list_copy (columns);
- g_value_init (&value, GLADE_TYPE_MODEL_DATA_TREE);
- g_value_take_boxed (&value, data_tree);
- glade_editor_property_commit (eprop, &value);
- g_value_unset (&value);
+ data = g_new0 (GladeColumnType, 1);
+ data->column_name = g_strdup (column_name);
+ data->type = type;
- }
+ columns = g_list_append (columns, data);
g_value_init (&value, GLADE_TYPE_COLUMN_TYPE_LIST);
- g_value_take_boxed (&value, list);
+ g_value_take_boxed (&value, columns);
glade_editor_property_commit (eprop, &value);
g_value_unset (&value);
-
- if (data_tree)
- {
- glade_model_data_tree_free (data_tree);
- glade_command_pop_group ();
- }
}
-static void
-eprop_column_append (GladeEPropColumnTypes *eprop_types,
- GType type,
- const gchar *name,
- const gchar *column_name)
-{
- gtk_list_store_insert_with_values (eprop_types->store, NULL, -1,
- COLUMN_NAME, name ? name : g_type_name (type),
- COLUMN_GTYPE, type,
- COLUMN_COLUMN_NAME, column_name,
- -1);
-}
-
-static void
-glade_eprop_column_types_load (GladeEditorProperty *eprop, GladeProperty *property)
-{
- GladeEditorPropertyClass *parent_class =
- g_type_class_peek_parent (GLADE_EDITOR_PROPERTY_GET_CLASS (eprop));
- GladeEPropColumnTypes *eprop_types = GLADE_EPROP_COLUMN_TYPES (eprop);
- GList *l, *list;
-
- /* Chain up first */
- parent_class->load (eprop, property);
-
- /* Clear Store */
- gtk_list_store_clear (eprop_types->store);
- /* We could set the combo to the first item */
-
- list = g_value_get_boxed (property->value);
-
- for (l = list; l; l = g_list_next (l))
- {
- GladeColumnType *data = l->data;
-
- eprop_column_append (eprop_types, data->type, NULL, data->column_name);
- }
-}
static void
glade_eprop_column_types_add_clicked (GtkWidget *button,
@@ -340,36 +265,77 @@ glade_eprop_column_types_add_clicked (GtkWidget *button,
COLUMN_GTYPE, &type2add,
-1);
- eprop_column_append (eprop_types, type2add, name, NULL);
- eprop_reload_value (eprop_types);
+ eprop_column_append (GLADE_EDITOR_PROPERTY (eprop_types), type2add, NULL);
}
static void
glade_eprop_column_types_delete_clicked (GtkWidget *button,
GladeEPropColumnTypes *eprop_types)
{
+ /* Remove from list and commit value, dont touch the liststore except in load() */
+
GtkTreeIter iter;
if (gtk_tree_selection_get_selected (eprop_types->selection, NULL, &iter))
gtk_list_store_remove (GTK_LIST_STORE (eprop_types->store), &iter);
}
-static gboolean
-eprop_reload_value_idle (gpointer data)
-{
- eprop_reload_value (GLADE_EPROP_COLUMN_TYPES (data));
- return FALSE;
-}
-
static void
eprop_treeview_row_deleted (GtkTreeModel *tree_model,
GtkTreePath *path,
GladeEditorProperty *eprop)
{
+ GtkTreeIter iter;
if (eprop->loading) return;
- eprop_reload_value_idle (eprop);
+
+ /* Find the deleted row and remove that column... */
+ if (!gtk_tree_model_get_iter (tree_model, &iter, path))
+ return;
+
+ /* Get it by name... */
+
}
+
+static void
+eprop_column_load (GladeEPropColumnTypes *eprop_types,
+ GType type,
+ const gchar *name,
+ const gchar *column_name)
+{
+ gtk_list_store_insert_with_values (eprop_types->store, NULL, -1,
+ COLUMN_NAME, name ? name : g_type_name (type),
+ COLUMN_GTYPE, type,
+ COLUMN_COLUMN_NAME, column_name,
+ -1);
+}
+
+static void
+glade_eprop_column_types_load (GladeEditorProperty *eprop, GladeProperty *property)
+{
+ GladeEditorPropertyClass *parent_class =
+ g_type_class_peek_parent (GLADE_EDITOR_PROPERTY_GET_CLASS (eprop));
+ GladeEPropColumnTypes *eprop_types = GLADE_EPROP_COLUMN_TYPES (eprop);
+ GList *l, *list;
+
+ /* Chain up first */
+ parent_class->load (eprop, property);
+
+ /* Clear Store */
+ gtk_list_store_clear (eprop_types->store);
+ /* We could set the combo to the first item */
+
+ list = g_value_get_boxed (property->value);
+
+ for (l = list; l; l = g_list_next (l))
+ {
+ GladeColumnType *data = l->data;
+
+ eprop_column_load (eprop_types, data->type, NULL, data->column_name);
+ }
+}
+
+
static GtkWidget *
glade_eprop_column_types_create_input (GladeEditorProperty *eprop)
{
diff --git a/plugins/gtk+/glade-gtk.c b/plugins/gtk+/glade-gtk.c
index b5065a8a..781a8fc9 100644
--- a/plugins/gtk+/glade-gtk.c
+++ b/plugins/gtk+/glade-gtk.c
@@ -479,7 +479,7 @@ glade_gtk_parse_atk_props (GladeWidget *widget,
/* Set the parsed value on the property ... */
gvalue = glade_property_class_make_gvalue_from_string
- (property->klass, value, widget->project);
+ (property->klass, value, widget->project, widget);
glade_property_set_value (property, gvalue);
g_value_unset (gvalue);
g_free (gvalue);
@@ -8777,10 +8777,14 @@ glade_gtk_store_write_columns (GladeWidget *widget,
for (l = g_value_get_boxed (prop->value); l; l = g_list_next (l))
{
GladeColumnType *data = l->data;
- GladeXmlNode *column_node;
-
+ GladeXmlNode *column_node, *comment_node;
+
/* Write column names in comments... */
-
+ gchar *comment = g_strdup_printf ("column-name %s", data->column_name);
+ comment_node = glade_xml_node_new_comment (context, comment);
+ glade_xml_node_append_child (columns_node, comment_node);
+ g_free (comment);
+
column_node = glade_xml_node_new (context, GLADE_TAG_COLUMN);
glade_xml_node_append_child (columns_node, column_node);
glade_xml_node_set_property_string (column_node, GLADE_TAG_TYPE,
@@ -8989,7 +8993,7 @@ glade_gtk_store_read_data (GladeWidget *widget, GladeXmlNode *node)
* should we be doing this part in "finished" ? ... todo thinkso...
*/
value_str = glade_xml_get_content (col_node);
- value = glade_utils_value_from_string (column_type->type, value_str, widget->project);
+ value = glade_utils_value_from_string (column_type->type, value_str, widget->project, widget);
g_free (value_str);
data = glade_model_data_new (column_type->type);
diff --git a/plugins/gtk+/glade-model-data.c b/plugins/gtk+/glade-model-data.c
index 64740c97..dc99b669 100644
--- a/plugins/gtk+/glade-model-data.c
+++ b/plugins/gtk+/glade-model-data.c
@@ -286,6 +286,20 @@ append_row (GNode *node, GList *columns)
}
}
+static void
+clear_view (GladeEditorProperty *eprop)
+{
+ GladeEPropModelData *eprop_data = GLADE_EPROP_MODEL_DATA (eprop);
+ GtkTreeViewColumn *column;
+
+ /* Clear columns ... */
+ while ((column = gtk_tree_view_get_column (eprop_data->view, 0)) != NULL)
+ gtk_tree_view_remove_column (eprop_data->view, column);
+
+ /* Clear store ... (this will unref the old store) */
+ gtk_tree_view_set_model (eprop_data->view, NULL);
+
+}
/* User pressed add: append row and commit values */
static void
@@ -302,6 +316,8 @@ glade_eprop_model_data_add_clicked (GtkWidget *button,
if (!columns)
return;
+ clear_view (eprop);
+
if (!node)
node = g_node_new (NULL);
else
@@ -313,6 +329,7 @@ glade_eprop_model_data_add_clicked (GtkWidget *button,
g_value_take_boxed (&value, node);
glade_editor_property_commit (eprop, &value);
g_value_unset (&value);
+
}
/* User pressed delete: remove selected row and commit values */
@@ -394,7 +411,7 @@ eprop_model_data_generate_store (GladeEditorProperty *eprop)
iter_data = iter_node->data;
g_array_append_val (gtypes, G_VALUE_TYPE (&iter_data->value));
}
- store = gtk_list_store_newv (NUM_COLUMNS + gtypes->len, (GType *)gtypes->data);
+ store = gtk_list_store_newv (gtypes->len, (GType *)gtypes->data);
g_array_free (gtypes, TRUE);
/* Now populate the store with data */
@@ -406,11 +423,11 @@ eprop_model_data_generate_store (GladeEditorProperty *eprop)
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, COLUMN_ROW, row_num, -1);
- for (column_num = 0, iter_node = row_node->children; iter_node;
+ for (column_num = NUM_COLUMNS, iter_node = row_node->children; iter_node;
column_num++, iter_node = iter_node->next)
{
iter_data = iter_node->data;
- gtk_list_store_set_value (store, &iter, NUM_COLUMNS + column_num, &iter_data->value);
+ gtk_list_store_set_value (store, &iter, column_num, &iter_data->value);
}
}
return store;
@@ -448,13 +465,48 @@ value_text_edited (GtkCellRendererText *cell,
GladeEPropModelData *eprop_data = GLADE_EPROP_MODEL_DATA (eprop);
GtkTreeIter iter;
gint colnum = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), "column-number"));
+ gint row;
+ GNode *data_tree = NULL, *node;
+ GValue value = { 0, };
+ GladeModelData *data;
if (!gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (eprop_data->store), &iter, path))
return;
- gtk_list_store_set (eprop_data->store, &iter,
- NUM_COLUMNS + colnum, new_text,
+
+ gtk_tree_model_get (eprop_data->store, &iter,
+ COLUMN_ROW, &row,
-1);
+
+ glade_property_get (eprop->property, &data_tree);
+
+ /* if we are editing, then there is data in the datatree */
+ g_assert (data_tree);
+
+ data_tree = glade_model_data_tree_copy (data_tree);
+
+ if ((node = g_node_nth_child (data_tree, row)) != NULL)
+ {
+ if ((node = g_node_nth_child (node, colnum)) != NULL)
+ {
+ data = node->data;
+
+ g_value_set_string (&(data->value), new_text);
+ }
+ }
+
+ g_value_init (&value, GLADE_TYPE_MODEL_DATA_TREE);
+ g_value_take_boxed (&value, data_tree);
+ glade_editor_property_commit (eprop, &value);
+ g_value_unset (&value);
+
+ /* No need to update store, it will be reloaded in load() */
+/* gtk_list_store_set (eprop_data->store, &iter, */
+/* NUM_COLUMNS + colnum, new_text, */
+/* -1); */
+
+ /* XXX Set string in data here and commit ! */
+
}
static GtkTreeViewColumn *
@@ -479,7 +531,6 @@ eprop_model_generate_column (GladeEditorProperty *eprop,
renderer = gtk_cell_renderer_text_new ();
g_object_set (G_OBJECT (renderer),
"editable", TRUE,
- "ellipsize", PANGO_ELLIPSIZE_END,
NULL);
gtk_tree_view_column_pack_start (column, renderer, FALSE);
gtk_tree_view_column_set_attributes (column, renderer,
@@ -529,7 +580,6 @@ eprop_model_generate_column (GladeEditorProperty *eprop,
g_object_set (G_OBJECT (renderer),
"editable", TRUE,
"adjustment", adjustment,
- "ellipsize", PANGO_ELLIPSIZE_END,
NULL);
gtk_tree_view_column_pack_start (column, renderer, TRUE);
@@ -589,10 +639,6 @@ eprop_model_data_generate_columns (GladeEditorProperty *eprop)
glade_property_get (eprop->property, &data_tree);
- /* Clear columns ... */
- while ((column = gtk_tree_view_get_column (eprop_data->view, 0)) != NULL)
- gtk_tree_view_remove_column (eprop_data->view, column);
-
if (!data_tree || !data_tree->children || !data_tree->children->children)
return;
@@ -614,19 +660,17 @@ glade_eprop_model_data_load (GladeEditorProperty *eprop,
GladeEditorPropertyClass *parent_class =
g_type_class_peek_parent (GLADE_EDITOR_PROPERTY_GET_CLASS (eprop));
GladeEPropModelData *eprop_data = GLADE_EPROP_MODEL_DATA (eprop);
-
- /* Chain up first */
+
+ clear_view (eprop);
+
+ /* Chain up in a clean state... */
parent_class->load (eprop, property);
-
- /* Recreate and populate store */
- if (eprop_data->store)
- g_object_unref (G_OBJECT (eprop_data->store));
-
+
if ((eprop_data->store = eprop_model_data_generate_store (eprop)) != NULL)
{
eprop_data->selection = gtk_tree_view_get_selection (eprop_data->view);
- /* Pass ownership of the store to the model */
+ /* Pass ownership of the store to the view... */
gtk_tree_view_set_model (eprop_data->view, GTK_TREE_MODEL (eprop_data->store));
g_object_unref (G_OBJECT (eprop_data->store));
@@ -635,7 +679,7 @@ glade_eprop_model_data_load (GladeEditorProperty *eprop,
eprop);
}
- /* Clear and create new columns with renderers */
+ /* Create new columns with renderers */
eprop_model_data_generate_columns (eprop);
}
diff --git a/plugins/gtk+/gtk+.xml.in b/plugins/gtk+/gtk+.xml.in
index d14ad24a..17ef4f60 100644
--- a/plugins/gtk+/gtk+.xml.in
+++ b/plugins/gtk+/gtk+.xml.in
@@ -901,7 +901,7 @@ embedded in another object</_tooltip>
<signal id="popup" since="2.12"/>
</signals>
<properties>
- <property id="model" libglade-unsupported="True"/>
+ <property id="model" libglade-unsupported="True" create-type="GtkListStore"/>
<property id="popup-shown" since="2.10"/>
<property id="tearoff-title" since="2.10"/>
<property id="active" ignore="True"/>
@@ -1068,8 +1068,8 @@ embedded in another object</_tooltip>
</packing-actions>
<properties>
- <property id="n-rows" default="3" query="True"/>
- <property id="n-columns" default="3" query="True"/>
+ <property id="n-rows" default="3" query="True" needs-sync="True"/>
+ <property id="n-columns" default="3" query="True" needs-sync="True"/>
</properties>
<packing-properties>
diff --git a/src/glade-window.c b/src/glade-window.c
index a4868aa2..59626f37 100644
--- a/src/glade-window.c
+++ b/src/glade-window.c
@@ -1705,7 +1705,6 @@ notebook_tab_removed_cb (GtkNotebook *notebook,
GladeWindow *window)
{
GladeProject *project;
- GladeInspector *inspector;
--window->priv->num_tabs;
@@ -1721,13 +1720,12 @@ notebook_tab_removed_cb (GtkNotebook *notebook,
G_CALLBACK (project_selection_changed_cb),
window);
- /* FIXME: this function needs to be preferably called somewhere else */
- glade_app_remove_project (project);
-
- inspector = (GladeInspector *) gtk_notebook_get_nth_page (GTK_NOTEBOOK (window->priv->inspectors_notebook), page_num);
gtk_notebook_remove_page (GTK_NOTEBOOK (window->priv->inspectors_notebook), page_num);
+ /* FIXME: this function needs to be preferably called somewhere else */
+ glade_app_remove_project (project);
+
refresh_projects_list_menu (window);
refresh_title (window);
@@ -2501,7 +2499,9 @@ add_project (GladeWindow *window, GladeProject *project)
view = glade_design_view_new (project);
gtk_widget_show (view);
+ /* Pass ownership of the project to the app */
glade_app_add_project (project);
+ g_object_unref (project);
gtk_notebook_append_page (GTK_NOTEBOOK (window->priv->notebook), GTK_WIDGET (view), NULL);
gtk_notebook_set_current_page (GTK_NOTEBOOK (window->priv->notebook), -1);