Commit c3a2cd32 authored by Tristan Van Berkom's avatar Tristan Van Berkom

Cleaned up code, now data will dynamically reorder itself upon column


	* plugins/gtk+/glade-gtk.c, plugins/gtk+/glade-column-types.c, plugins/gtk+/glade-model-data.c:
	Cleaned up code, now data will dynamically reorder itself upon column changes, data is mostly
	all editable save for some glitches, and all columns have unique names to which the data is
	directly related.


svn path=/trunk/; revision=1974
parent 40af51e3
......@@ -19,7 +19,9 @@
* 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.
Cleaned up code, now data will dynamically reorder itself upon column changes, data is mostly
all editable save for some glitches, and all columns have unique names to which the data is
directly related.
2008-10-10 Tristan Van Berkom <tvb@gnome.org>
......
......@@ -43,5 +43,6 @@
#include <gladeui/glade-utils.h>
#include <gladeui/glade-builtins.h>
#include <gladeui/glade-fixed.h>
#include <gladeui/glade-name-context.h>
#endif /* __GLADE_H__ */
......@@ -18,6 +18,7 @@
*
* Authors:
* Juan Pablo Ugarte <juanpablougarte@gmail.com>
* Tristan Van Berkom <tvb@gnome.org>
*/
#include <config.h>
......@@ -68,7 +69,6 @@ column_types_store_populate (GtkListStore *store)
G_TYPE_DOUBLE,
G_TYPE_STRING,
G_TYPE_POINTER,
G_TYPE_BOXED,
G_TYPE_PARAM,
G_TYPE_OBJECT,
GDK_TYPE_PIXBUF};
......@@ -102,22 +102,40 @@ glade_column_list_copy (GList *list)
return g_list_reverse (retval);
}
void
glade_column_type_free (GladeColumnType *column)
{
g_free (column->column_name);
g_free (column);
}
void
glade_column_list_free (GList *list)
{
g_list_foreach (list, (GFunc)glade_column_type_free, NULL);
g_list_free (list);
}
GladeColumnType *
glade_column_list_find_column (GList *list, const gchar *column_name)
{
GladeColumnType *column = NULL, *iter;
GList *l;
for (l = list; l; l = g_list_next (l))
for (l = g_list_first (list); l; l = l->next)
{
GladeColumnType *data = l->data;
g_free (data->column_name);
g_free (data);
iter = l->data;
if (strcmp (column_name, iter->column_name) == 0)
{
column = iter;
break;
}
}
g_list_free (list);
return column;
}
GType
glade_column_type_list_get_type (void)
{
......@@ -204,6 +222,8 @@ typedef struct
GtkComboBox *combo;
GtkListStore *store;
GtkTreeSelection *selection;
GladeNameContext *context;
} GladeEPropColumnTypes;
GLADE_MAKE_EPROP (GladeEPropColumnTypes, glade_eprop_column_types)
......@@ -222,6 +242,71 @@ glade_eprop_column_types_finalize (GObject *object)
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gint
get_extra_column (GNode *data_tree, GList *columns)
{
GladeModelData *data;
GNode *iter;
gint idx = -1;
/* extra columns trail at the end so walk backwards... */
for (iter = g_node_last_child (data_tree->children); iter; iter = iter->prev)
{
data = iter->data;
if (!glade_column_list_find_column (columns, data->name))
{
idx = g_node_child_position (data_tree->children, iter);
break;
}
}
return idx;
}
static void
eprop_column_adjust_rows (GladeEditorProperty *eprop, GList *columns)
{
GladeColumnType *column;
GNode *data_tree = NULL;
GladeWidget *widget = eprop->property->widget;
GList *list;
GladeProperty *property;
gint idx;
property = glade_widget_get_property (widget, "data");
glade_property_get (property, &data_tree);
if (!data_tree)
return;
data_tree = glade_model_data_tree_copy (data_tree);
/* Add mising columns and reorder... */
for (list = g_list_last (columns); list; list = list->prev)
{
column = list->data;
if ((idx = glade_model_data_column_index (data_tree, column->column_name)) < 0)
{
glade_model_data_insert_column (data_tree,
column->type,
column->column_name,
0);
}
else
glade_model_data_reorder_column (data_tree, idx, 0);
}
/* Remove trailing obsolete */
while ((idx = get_extra_column (data_tree, columns)) >= 0)
glade_model_data_remove_column (data_tree, idx);
glade_command_set_property (property, data_tree);
glade_model_data_tree_free (data_tree);
}
static void
eprop_column_append (GladeEditorProperty *eprop,
GType type,
......@@ -242,12 +327,19 @@ eprop_column_append (GladeEditorProperty *eprop,
columns = g_list_append (columns, data);
glade_command_push_group (_("Setting columns on %s"),
glade_widget_get_name (eprop->property->widget));
g_value_init (&value, GLADE_TYPE_COLUMN_TYPE_LIST);
g_value_take_boxed (&value, columns);
glade_editor_property_commit (eprop, &value);
eprop_column_adjust_rows (eprop, columns);
g_value_unset (&value);
}
glade_command_pop_group ();
}
static void
glade_eprop_column_types_add_clicked (GtkWidget *button,
......@@ -255,28 +347,118 @@ glade_eprop_column_types_add_clicked (GtkWidget *button,
{
GtkTreeIter iter;
GType type2add;
gchar *name;
gchar *type_name, *column_name;
if (gtk_combo_box_get_active_iter (eprop_types->combo, &iter) == FALSE)
return;
gtk_tree_model_get (types_model, &iter,
COLUMN_NAME, &name,
COLUMN_GTYPE, &type2add,
-1);
eprop_column_append (GLADE_EDITOR_PROPERTY (eprop_types), type2add, NULL);
type_name = g_ascii_strdown (g_type_name (type2add), -1);
column_name = glade_name_context_new_name (eprop_types->context, type_name);
eprop_column_append (GLADE_EDITOR_PROPERTY (eprop_types), type2add, column_name);
g_free (column_name);
g_free (type_name);
}
static void
glade_eprop_column_types_delete_clicked (GtkWidget *button,
GladeEPropColumnTypes *eprop_types)
GladeEditorProperty *eprop)
{
/* Remove from list and commit value, dont touch the liststore except in load() */
GladeEPropColumnTypes *eprop_types = GLADE_EPROP_COLUMN_TYPES (eprop);
GtkTreeIter iter;
GList *columns = NULL;
GladeColumnType *column;
GValue value = { 0, };
gchar *column_name;
GtkTreeIter iter;
if (gtk_tree_selection_get_selected (eprop_types->selection, NULL, &iter))
gtk_list_store_remove (GTK_LIST_STORE (eprop_types->store), &iter);
{
gtk_tree_model_get (GTK_TREE_MODEL (eprop_types->store), &iter,
COLUMN_COLUMN_NAME, &column_name, -1);
g_assert (column_name);
glade_property_get (eprop->property, &columns);
if (columns)
columns = glade_column_list_copy (columns);
g_assert (columns);
/* Find and remove the offending column... */
column = glade_column_list_find_column (columns, column_name);
g_assert (column);
columns = g_list_remove (columns, column);
glade_column_type_free (column);
glade_command_push_group (_("Setting columns on %s"),
glade_widget_get_name (eprop->property->widget));
g_value_init (&value, GLADE_TYPE_COLUMN_TYPE_LIST);
g_value_take_boxed (&value, columns);
glade_editor_property_commit (eprop, &value);
eprop_column_adjust_rows (eprop, columns);
g_value_unset (&value);
glade_command_pop_group ();
g_free (column_name);
}
}
static gboolean
columns_changed_idle (GladeEditorProperty *eprop)
{
GladeEPropColumnTypes *eprop_types = GLADE_EPROP_COLUMN_TYPES (eprop);
GladeColumnType *column;
GValue value = { 0, };
GList *new_list = NULL, *columns = NULL, *list;
GtkTreeIter iter;
gchar *column_name;
glade_property_get (eprop->property, &columns);
g_assert (columns);
columns = glade_column_list_copy (columns);
if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (eprop_types->store), &iter))
{
do
{
column_name = NULL;
gtk_tree_model_get (GTK_TREE_MODEL (eprop_types->store), &iter,
COLUMN_COLUMN_NAME, &column_name, -1);
g_assert (column_name);
column = glade_column_list_find_column (columns, column_name);
g_assert (column);
new_list = g_list_prepend (new_list, column);
g_free (column_name);
}
while (gtk_tree_model_iter_next (GTK_TREE_MODEL (eprop_types->store), &iter));
}
/* any missing columns to free ? */
for (list = columns; list; list = list->next)
{
if (!g_list_find (new_list, list->data))
glade_column_type_free ((GladeColumnType *)list->data);
}
g_list_free (columns);
glade_command_push_group (_("Setting columns on %s"),
glade_widget_get_name (eprop->property->widget));
g_value_init (&value, GLADE_TYPE_COLUMN_TYPE_LIST);
g_value_take_boxed (&value, g_list_reverse (new_list));
glade_editor_property_commit (eprop, &value);
eprop_column_adjust_rows (eprop, new_list);
g_value_unset (&value);
glade_command_pop_group ();
return FALSE;
}
static void
......@@ -284,27 +466,18 @@ eprop_treeview_row_deleted (GtkTreeModel *tree_model,
GtkTreePath *path,
GladeEditorProperty *eprop)
{
GtkTreeIter iter;
if (eprop->loading) return;
/* Find the deleted row and remove that column... */
if (!gtk_tree_model_get_iter (tree_model, &iter, path))
return;
/* Get it by name... */
g_idle_add ((GSourceFunc)columns_changed_idle, eprop);
}
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_NAME, g_type_name (type),
COLUMN_GTYPE, type,
COLUMN_COLUMN_NAME, column_name,
-1);
......@@ -316,25 +489,108 @@ glade_eprop_column_types_load (GladeEditorProperty *eprop, GladeProperty *proper
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;
GList *l, *list = NULL;
/* Chain up first */
parent_class->load (eprop, property);
if (eprop_types->context)
glade_name_context_destroy (eprop_types->context);
eprop_types->context = NULL;
if (!property) return;
eprop_types->context = glade_name_context_new ();
g_signal_handlers_block_by_func (G_OBJECT (eprop_types->store),
eprop_treeview_row_deleted, eprop);
/* 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);
glade_property_get (property, &list);
for (l = list; l; l = g_list_next (l))
{
GladeColumnType *data = l->data;
eprop_column_load (eprop_types, data->type, NULL, data->column_name);
eprop_column_load (eprop_types, data->type, data->column_name);
glade_name_context_add_name (eprop_types->context, data->column_name);
}
g_signal_handlers_unblock_by_func (G_OBJECT (eprop_types->store),
eprop_treeview_row_deleted, eprop);
}
static void
column_name_edited (GtkCellRendererText *cell,
const gchar *path,
const gchar *new_column_name,
GladeEditorProperty *eprop)
{
GladeEPropColumnTypes *eprop_types = GLADE_EPROP_COLUMN_TYPES (eprop);
GtkTreeIter iter;
gchar *old_column_name = NULL, *column_name;
GList *columns = NULL;
GladeColumnType *column;
GValue value = { 0, };
GNode *data_tree = NULL;
GladeProperty *property;
if (!gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (eprop_types->store), &iter, path))
return;
gtk_tree_model_get (GTK_TREE_MODEL (eprop_types->store), &iter, COLUMN_COLUMN_NAME, &old_column_name, -1);
/* Attempt to rename the column, and commit if successfull... */
glade_property_get (eprop->property, &columns);
if (columns)
columns = glade_column_list_copy (columns);
g_assert (columns);
column = glade_column_list_find_column (columns, old_column_name);
/* Bookkeep the exclusive names... */
if (glade_name_context_has_name (eprop_types->context, new_column_name))
column_name = glade_name_context_new_name (eprop_types->context, new_column_name);
else
column_name = g_strdup (new_column_name);
glade_name_context_add_name (eprop_types->context, column_name);
glade_name_context_release_name (eprop_types->context, old_column_name);
/* Set real column name */
g_free (column->column_name);
column->column_name = column_name;
/* The "columns" copy of this string doesnt last long... */
column_name = g_strdup (column_name);
glade_command_push_group (_("Setting columns on %s"),
glade_widget_get_name (eprop->property->widget));
g_value_init (&value, GLADE_TYPE_COLUMN_TYPE_LIST);
g_value_take_boxed (&value, columns);
glade_editor_property_commit (eprop, &value);
g_value_unset (&value);
property = glade_widget_get_property (eprop->property->widget, "data");
glade_property_get (property, &data_tree);
if (data_tree)
{
data_tree = glade_model_data_tree_copy (data_tree);
glade_model_data_column_rename (data_tree, old_column_name, column_name);
glade_command_set_property (property, data_tree);
glade_model_data_tree_free (data_tree);
}
glade_command_pop_group ();
g_free (old_column_name);
g_free (column_name);
}
static GtkWidget *
glade_eprop_column_types_create_input (GladeEditorProperty *eprop)
......@@ -388,16 +644,35 @@ glade_eprop_column_types_create_input (GladeEditorProperty *eprop)
treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (eprop_types->store));
eprop_types->selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
gtk_tree_view_set_reorderable (GTK_TREE_VIEW (treeview), TRUE);
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
col = gtk_tree_view_column_new_with_attributes ("Type Name",
//gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
/* type column */
col = gtk_tree_view_column_new_with_attributes ("Column type",
gtk_cell_renderer_text_new (),
"text", COLUMN_NAME,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), col);
/* name column */
cell = gtk_cell_renderer_text_new ();
g_object_set (G_OBJECT (cell), "editable", TRUE, NULL);
g_signal_connect (G_OBJECT (cell), "edited",
G_CALLBACK (column_name_edited), eprop);
col = gtk_tree_view_column_new_with_attributes ("Column name",
cell,
"text", COLUMN_COLUMN_NAME,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), col);
gtk_container_add (GTK_CONTAINER (swin), treeview);
g_object_set (G_OBJECT (vbox), "height-request", 200, NULL);
gtk_widget_show_all (vbox);
return vbox;
}
......@@ -52,6 +52,9 @@ GParamSpec *glade_standard_column_types_spec (void);
void glade_column_list_free (GList *list);
GList *glade_column_list_copy (GList *list);
void glade_column_type_free (GladeColumnType *column);
GladeColumnType *glade_column_list_find_column (GList *list, const gchar *column_name);
G_END_DECLS
#endif /* _GLADE_COLUMN_TYPES_H_ */
......@@ -379,7 +379,7 @@ combos_data_tree_from_items (gchar **items)
for (i = 0; items[i]; i++)
{
GladeModelData *data = glade_model_data_new (G_TYPE_STRING);
GladeModelData *data = glade_model_data_new (G_TYPE_STRING, "item");
g_value_set_string (&data->value, items[i]);
......
......@@ -8630,6 +8630,7 @@ glade_gtk_store_set_data (GObject *object,
gint colnum;
GtkTreeIter row_iter;
GladeModelData *data;
GType column_type;
if (GTK_IS_LIST_STORE (object))
gtk_list_store_clear (GTK_LIST_STORE (object));
......@@ -8659,6 +8660,13 @@ glade_gtk_store_set_data (GObject *object,
if (!g_list_nth (columns, colnum))
break;
/* Abort if theres a type mismatch, the widget's being rebuilt
* and a sync will come soon with the right values
*/
column_type = gtk_tree_model_get_column_type (GTK_TREE_MODEL (object), colnum);
if (!g_type_is_a (G_VALUE_TYPE (&data->value), column_type))
break;
if (GTK_IS_LIST_STORE (object))
gtk_list_store_set_value (GTK_LIST_STORE (object),
&row_iter,
......@@ -8780,7 +8788,7 @@ glade_gtk_store_write_columns (GladeWidget *widget,
GladeXmlNode *column_node, *comment_node;
/* Write column names in comments... */
gchar *comment = g_strdup_printf ("column-name %s", data->column_name);
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);
......@@ -8893,6 +8901,7 @@ glade_gtk_store_write_widget (GladeWidgetAdaptor *adaptor,
static void
glade_gtk_store_read_columns (GladeWidget *widget, GladeXmlNode *node)
{
GladeNameContext *context;
GladeXmlNode *columns_node;
GladeProperty *property;
GladeXmlNode *prop;
......@@ -8906,30 +8915,38 @@ glade_gtk_store_read_columns (GladeWidget *widget, GladeXmlNode *node)
if ((columns_node = glade_xml_search_child (node, GLADE_TAG_COLUMNS)) == NULL)
return;
context = glade_name_context_new ();
for (prop = glade_xml_node_get_children_with_comments (columns_node); prop;
prop = glade_xml_node_next_with_comments (prop))
{
GladeColumnType *data = g_new0 (GladeColumnType, 1);
gchar *type, *comment_str, buffer[256];
if (!glade_xml_node_verify (prop, GLADE_TAG_COLUMN) &&
if (!glade_xml_node_verify_silent (prop, GLADE_TAG_COLUMN) &&
!glade_xml_node_is_comment (prop)) continue;
if (glade_xml_node_is_comment (prop))
{
comment_str = glade_xml_get_content (prop);
if (sscanf (comment_str, "column-name %s", buffer) == 1)
{
if (sscanf (comment_str, " column-name %s", buffer) == 1)
strncpy (column_name, buffer, 255);
g_free (comment_str);
continue;
}
g_free (comment_str);
continue;
}
type = glade_xml_get_property_string_required (prop, GLADE_TAG_TYPE, NULL);
data->type = g_type_from_name (type);
data->column_name = g_strdup (column_name);
data->column_name = column_name[0] ? g_strdup (column_name) : g_ascii_strdown (type, -1);
if (glade_name_context_has_name (context, data->column_name))
{
gchar *name = glade_name_context_new_name (context, data->column_name);
g_free (data->column_name);
data->column_name = name;
}
glade_name_context_add_name (context, data->column_name);
types = g_list_prepend (types, data);
g_free (type);
......@@ -8996,11 +9013,13 @@ glade_gtk_store_read_data (GladeWidget *widget, GladeXmlNode *node)
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);
data = glade_model_data_new (column_type->type, column_type->column_name);
g_value_copy (value, &data->value);
g_value_unset (value);
g_free (value);
data->name = g_strdup (column_type->column_name);
data->i18n_translatable = glade_xml_get_property_boolean (col_node, GLADE_TAG_TRANSLATABLE, FALSE);
data->i18n_context = glade_xml_get_property_string (col_node, GLADE_TAG_CONTEXT);
data->i18n_comment = glade_xml_get_property_string (col_node, GLADE_TAG_COMMENT);
......
......@@ -31,7 +31,7 @@
#include "glade-column-types.h"
GladeModelData *
glade_model_data_new (GType type)
glade_model_data_new (GType type, const gchar *column_name)
{
GladeModelData *data = g_new0 (GladeModelData, 1);
g_value_init (&data->value, type);
......@@ -39,6 +39,8 @@ glade_model_data_new (GType type)
if (type == G_TYPE_STRING)
data->i18n_translatable = TRUE;
data->name = g_strdup (column_name);
return data;
}
......@@ -100,9 +102,24 @@ glade_model_data_tree_free (GNode *node)
}
}
GladeModelData *
glade_model_data_tree_get_data (GNode *data_tree, gint row, gint colnum)
{
GNode *node;
g_return_val_if_fail (data_tree != NULL, NULL);
if ((node = g_node_nth_child (data_tree, row)) != NULL)
if ((node = g_node_nth_child (node, colnum)) != NULL)
return (GladeModelData *)node->data;
return NULL;
}
void
glade_model_data_insert_column (GNode *node,
GType type,
const gchar *column_name,
gint nth)
{
GNode *row, *item;
......@@ -114,7 +131,7 @@ glade_model_data_insert_column (GNode *node,
{
g_return_if_fail (nth >= 0 && nth <= g_node_n_children (row));
data = glade_model_data_new (type);
data = glade_model_data_new (type, column_name);
item = g_node_new (data);
g_node_insert (row, nth, item);
}
......@@ -122,7 +139,6 @@ glade_model_data_insert_column (GNode *node,
void
glade_model_data_remove_column (GNode *node,
GType type,
gint nth)
{
GNode *row, *item;
......@@ -162,6 +178,50 @@ glade_model_data_reorder_column (GNode *node,
}
}
gint
glade_model_data_column_index (GNode *node,
const gchar *column_name)
{
gint i;
GNode *item;
GladeModelData *data;
g_return_val_if_fail (node != NULL, -1);
for (i = 0, item = node->children->children; item; i++, item = item->next)
{
data = item->data;
if (strcmp (data->name, column_name) == 0)
return i;
}
return -1;
}
void
glade_model_data_column_rename (GNode *node,
const gchar *column_name,
const gchar *new_name)
{
gint idx;
GNode *row, *iter;
GladeModelData *data;
g_return_if_fail (node != NULL);
if ((idx = glade_model_data_column_index (node, column_name)) < 0)
return;
for (row = node->children; row; row = row->next)
{
g_print ("Setting new name %s for old name %s at index %d\n",
new_name, column_name, idx);
iter = g_node_nth_child (row, idx);
data = iter->data;
g_free (data->name);
data->name = g_strdup (new_name);
}
}
GType
glade_model_data_tree_get_type (void)
{
......@@ -255,6 +315,7 @@ typedef struct
GtkTreeView *view;
GtkListStore *store;
GtkTreeSelection *selection;
GNode *pending_data_tree;
} GladeEPropModelData;
GLADE_MAKE_EPROP (GladeEPropModelData, glade_eprop_model_data)
......@@ -281,7 +342,7 @@ append_row (GNode *node, GList *columns)
for (list = columns; list; list = list->next)
{
column = list->data;
data = glade_model_data_new (column->type);
data = glade_model_data_new (column->type, column->column_name);
g_node_append_data (row, data);
}
}
......@@ -432,30 +493,62 @@ eprop_model_data_generate_store (GladeEditorProperty *eprop)
}
return