Commit 4f1e473e authored by Tristan Van Berkom's avatar Tristan Van Berkom

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
parent 9c7ab5cc
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],
......
......@@ -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
......
......@@ -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);
}
......
......@@ -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 ());
}
}
......@@ -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,
......
......@@ -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);
......
......@@ -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);
}
......
/* -*- 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);
}
/* -*- 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__ */
This diff is collapsed.
......@@ -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
......
......@@ -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)