/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * Copyright (C) 2008 Juan Pablo Ugarte.
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser 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.
 *
 * Authors:
 *   Juan Pablo Ugarte <juanpablougarte@gmail.com>
 *   Tristan Van Berkom <tvb@gnome.org>
 */

#include <config.h>

#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <glib/gi18n-lib.h>
#include <string.h>

#include <gladeui/glade.h>
#include "glade-column-types.h"
#include "glade-model-data.h"

enum
{
	COLUMN_NAME,
	COLUMN_COLUMN_NAME,
	COLUMN_TYPE_EDITABLE,
	COLUMN_NAME_EDITABLE,
	COLUMN_TYPE_FOREGROUND,
	COLUMN_TYPE_STYLE,
	N_COLUMNS
};

static GtkTreeModel *types_model = NULL;

static gint 
find_by_type_name (const gchar *a, const gchar *b)
{
	return strcmp (a, b);
}

static void
column_types_store_populate_enums_flags (GtkListStore *store,
					 gboolean      enums)
{
	GtkTreeIter iter;
	GList *types = NULL, *list, *l;
	GList *adaptors = glade_widget_adaptor_list_adaptors ();

	for (list = adaptors; list; list = list->next)
	{
		GladeWidgetAdaptor *adaptor = list->data;
		GladePropertyClass *pclass;

		for (l = adaptor->properties; l; l = l->next)
		{
			pclass = l->data;

			/* special case out a few of these... */
			if (strcmp (g_type_name (pclass->pspec->value_type), "GladeGtkGnomeUIInfo") == 0 ||
			    strcmp (g_type_name (pclass->pspec->value_type), "GladeStock") == 0 ||
			    strcmp (g_type_name (pclass->pspec->value_type), "GladeStockImage") == 0 ||
			    strcmp (g_type_name (pclass->pspec->value_type), "GladeGtkImageType") == 0 ||
			    strcmp (g_type_name (pclass->pspec->value_type), "GladeGtkButtonType") == 0 ||
			    strcmp (g_type_name (pclass->pspec->value_type), "GladeGnomeDruidPagePosition") == 0 ||
			    strcmp (g_type_name (pclass->pspec->value_type), "GladeGnomeIconListSelectionMode") == 0 ||
			    strcmp (g_type_name (pclass->pspec->value_type), "GladeGnomeMessageBoxType") == 0)
				continue;

			if ((enums ? G_TYPE_IS_ENUM (pclass->pspec->value_type) : 
			     G_TYPE_IS_FLAGS (pclass->pspec->value_type)) &&
			    !g_list_find_custom (types, g_type_name (pclass->pspec->value_type), 
						 (GCompareFunc)find_by_type_name))
				types = g_list_prepend (types, g_strdup (g_type_name (pclass->pspec->value_type)));

		}
	}
	g_list_free (adaptors);

	types = g_list_sort (types, (GCompareFunc)find_by_type_name);

	for (l = types; l; l = l->next)
	{
		gchar *type_name = l->data;

		gtk_list_store_append (store, &iter);
		gtk_list_store_set (store, &iter,
				    COLUMN_NAME, type_name,
				    -1);
		g_free (type_name);
	}
	g_list_free (types);
}

static void
column_types_store_populate (GtkListStore *store)
{
	GtkTreeIter iter;
	gint i;
	GType types[] = {
		G_TYPE_CHAR,
		G_TYPE_UCHAR,
		G_TYPE_BOOLEAN,
		G_TYPE_INT,
		G_TYPE_UINT,
		G_TYPE_LONG,
		G_TYPE_ULONG,
		G_TYPE_INT64,
		G_TYPE_UINT64,
		G_TYPE_FLOAT,
		G_TYPE_DOUBLE,
		G_TYPE_STRING,
		G_TYPE_POINTER,
		G_TYPE_OBJECT,
		GDK_TYPE_PIXBUF};
	
	for (i = 0; i < sizeof (types) / sizeof (GType); i++)
	{
		gtk_list_store_append (store, &iter);
		gtk_list_store_set (store, &iter,
				    COLUMN_NAME, g_type_name (types[i]),
				    -1);
	}

	column_types_store_populate_enums_flags (store, TRUE);
	column_types_store_populate_enums_flags (store, FALSE);
}

GList *
glade_column_list_copy (GList *list)
{
	GList *l, *retval = NULL;
	
	for (l = list; l; l = g_list_next (l))
	{
		GladeColumnType *data = l->data;
		GladeColumnType *new_data = 
			glade_column_type_new (data->type_name, data->column_name);

		retval = g_list_prepend (retval, new_data);
	}
	
	return g_list_reverse (retval);
}

GladeColumnType *
glade_column_type_new (const gchar *type_name,
		       const gchar *column_name)
{
	GladeColumnType *column = g_slice_new0 (GladeColumnType);

	column->type_name   = g_strdup (type_name);
	column->column_name = g_strdup (column_name);

	return column;
}

void
glade_column_type_free (GladeColumnType *column)
{
	g_free (column->type_name);
	g_free (column->column_name);
	g_slice_free (GladeColumnType, 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 = g_list_first (list); l; l = l->next)
	{
		iter = l->data;
		if (strcmp (column_name, iter->column_name) == 0)
		{
			column = iter;
			break;
		}
	}

	return column;
}

GType
glade_column_type_list_get_type (void)
{
	static GType type_id = 0;

	if (!type_id)
	{
		type_id = g_boxed_type_register_static
			("GladeColumnTypeList", 
			 (GBoxedCopyFunc) glade_column_list_copy,
			 (GBoxedFreeFunc) glade_column_list_free);
	}
	return type_id;
}

/**************************** GladeEditorProperty *****************************/
typedef struct
{
	GladeEditorProperty parent_instance;

	GtkListStore     *store;
	GtkTreeView      *view;
	GtkTreeSelection *selection;

	GladeNameContext *context;

	gboolean           adding_column;
	gboolean           want_focus;
	gboolean           setting_cursor;

	GtkTreeViewColumn *name_column;
	GtkTreeViewColumn *type_column;
} GladeEPropColumnTypes;

GLADE_MAKE_EPROP (GladeEPropColumnTypes, glade_eprop_column_types)
#define GLADE_EPROP_COLUMN_TYPES(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_EPROP_COLUMN_TYPES, GladeEPropColumnTypes))
#define GLADE_EPROP_COLUMN_TYPES_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GLADE_TYPE_EPROP_COLUMN_TYPES, GladeEPropColumnTypesClass))
#define GLADE_IS_EPROP_COLUMN_TYPES(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GLADE_TYPE_EPROP_COLUMN_TYPES))
#define GLADE_IS_EPROP_COLUMN_TYPES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GLADE_TYPE_EPROP_COLUMN_TYPES))
#define GLADE_EPROP_COLUMN_TYPES_GET_CLASS(o)    (G_TYPE_INSTANCE_GET_CLASS ((o), GLADE_EPROP_COLUMN_TYPES, GladeEPropColumnTypesClass))

static void
glade_eprop_column_types_finalize (GObject *object)
{
	/* Chain up */
	GObjectClass *parent_class = g_type_class_peek_parent (G_OBJECT_GET_CLASS (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)
	{
		GType data_type;

		column = list->data;

		data_type = g_type_from_name (column->type_name);
		
		if ((idx = glade_model_data_column_index (data_tree, column->column_name)) < 0)
		{
			glade_model_data_insert_column (data_tree,
							data_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,
		     const gchar *type_name,
		     const gchar *column_name)
{
	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);

	data = glade_column_type_new (type_name, column_name);

	columns = g_list_append (columns, data);

	eprop_types->adding_column = TRUE;
	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 ();

	eprop_types->adding_column = FALSE;
}

static gboolean
eprop_treeview_key_press (GtkWidget           *treeview,
			  GdkEventKey         *event,
			  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;

	if (event->keyval == GDK_Delete &&
	    gtk_tree_selection_get_selected (eprop_types->selection, NULL, &iter))
	{
		gtk_tree_model_get (GTK_TREE_MODEL (eprop_types->store), &iter,
				    COLUMN_COLUMN_NAME, &column_name, -1);

		/* Cant delete the symbolic "add new" row */
		if (!column_name)
			return TRUE;

		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));

		eprop_types->want_focus = TRUE;

		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);

		eprop_types->want_focus = FALSE;

	}

	return (event->keyval == GDK_Delete);
}

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);


	/* This can happen when the user performs DnD and there
	 * are no columns yet */
	if (!columns)
		return FALSE;

	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);
			if (!column_name)
				continue;

			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
eprop_treeview_row_deleted (GtkTreeModel *tree_model,
			    GtkTreePath  *path,
			    GladeEditorProperty *eprop)
{
	if (eprop->loading) return;

	g_idle_add ((GSourceFunc)columns_changed_idle, eprop);
}

static void
eprop_column_add_new (GladeEPropColumnTypes *eprop_types)
{
	gtk_list_store_insert_with_values (eprop_types->store, NULL, -1,
					   COLUMN_NAME, _("< define a new column >"),
					   COLUMN_TYPE_EDITABLE, TRUE,
					   COLUMN_NAME_EDITABLE, FALSE,
					   COLUMN_TYPE_FOREGROUND, "Gray",
					   COLUMN_TYPE_STYLE, PANGO_STYLE_ITALIC,
					   -1);
}

static void
eprop_column_load (GladeEPropColumnTypes *eprop_types,
		   const gchar *type_name,
		   const gchar *column_name)
{
	gtk_list_store_insert_with_values (eprop_types->store, NULL, -1,
					   COLUMN_NAME, type_name,
					   COLUMN_COLUMN_NAME, column_name,
					   COLUMN_TYPE_EDITABLE, FALSE,
					   COLUMN_NAME_EDITABLE, TRUE,
					   COLUMN_TYPE_FOREGROUND, "Black",
					   COLUMN_TYPE_STYLE, PANGO_STYLE_NORMAL,
					   -1);
}


static void
eprop_types_focus_cell (GladeEPropColumnTypes *eprop_types, gboolean use_path, gboolean add_cell, gboolean edit_cell)
{
	/* Focus and edit the first column of a newly added row */
	if (eprop_types->store)
	{
		GtkTreePath *new_item_path;
		GtkTreeIter  iter;
		gint n_children;
		gint needed_row;

		n_children = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (eprop_types->store), NULL);

		needed_row = n_children - (add_cell ? 1 : 2);

		if (use_path)
			new_item_path = gtk_tree_path_new_from_string 
				(g_object_get_data (G_OBJECT (eprop_types), "current-path-str"));
		else if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (eprop_types->store),
							&iter, NULL, needed_row))
			new_item_path = gtk_tree_model_get_path (GTK_TREE_MODEL (eprop_types->store), &iter);
		else
			return;

		eprop_types->setting_cursor = TRUE;

		gtk_widget_grab_focus (GTK_WIDGET (eprop_types->view));
		gtk_tree_view_expand_to_path (eprop_types->view, new_item_path);
		
		gtk_tree_view_set_cursor (eprop_types->view, new_item_path,
					  add_cell ? eprop_types->type_column : eprop_types->name_column, 
					  edit_cell);
		
		eprop_types->setting_cursor = FALSE;
		
		gtk_tree_path_free (new_item_path);
	}
}

static gboolean
eprop_types_focus_new (GladeEPropColumnTypes *eprop_types)
{
	eprop_types_focus_cell (eprop_types, FALSE, TRUE, FALSE);
	return FALSE;
}

static gboolean
eprop_types_focus_name (GladeEPropColumnTypes *eprop_types)
{
	eprop_types_focus_cell (eprop_types, FALSE, FALSE, TRUE);
	return FALSE;
}

static gboolean
eprop_types_focus_name_no_edit (GladeEPropColumnTypes *eprop_types)
{
	eprop_types_focus_cell (eprop_types, TRUE, FALSE, FALSE);
	return FALSE;
}

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 = 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);

	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_name, data->column_name);
		glade_name_context_add_name (eprop_types->context, data->column_name);
	}

	eprop_column_add_new (eprop_types);

	if (eprop_types->adding_column && list)
		g_idle_add ((GSourceFunc)eprop_types_focus_name, eprop_types);
	else if (eprop_types->want_focus)
		g_idle_add ((GSourceFunc)eprop_types_focus_new, eprop_types);

	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 (eprop_types->adding_column)
		return;

	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);

	if (new_column_name && old_column_name && 
	    strcmp (new_column_name, old_column_name) == 0)
		return;

	/* 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 (!new_column_name  || !new_column_name[0] || 
	    glade_name_context_has_name (eprop_types->context, new_column_name))
		column_name = glade_name_context_new_name (eprop_types->context, 
							   new_column_name && new_column_name[0] ? 
							   new_column_name : "column");
	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));

	eprop_types->want_focus = TRUE;

	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 ();

	eprop_types->want_focus = FALSE;

	g_free (old_column_name);
	g_free (column_name);
}


static void
column_type_edited (GtkCellRendererText *cell,
		    const gchar         *path,
		    const gchar         *type_name,
		    GladeEditorProperty *eprop)
{
	GladeEPropColumnTypes *eprop_types = GLADE_EPROP_COLUMN_TYPES (eprop);
	GtkTreeIter            iter;
	gchar                 *column_name;

	if (!gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (eprop_types->store), &iter, path))
		return;

	if (type_name && type_name[0])
	{
		column_name = glade_name_context_new_name (eprop_types->context, type_name);
		eprop_column_append (eprop, type_name, column_name);
		g_free (column_name);
	}
	else
	{
		eprop_types->want_focus = TRUE;
		glade_editor_property_load (eprop, eprop->property);
		eprop_types->want_focus = FALSE;
	}
}


static void
types_combo_editing_started (GtkCellRenderer       *renderer,
			     GtkCellEditable       *editable,
			     gchar                 *path,
			     GladeEditorProperty   *eprop)
{
	GtkEntryCompletion *completion = gtk_entry_completion_new ();

	g_object_set_data_full (G_OBJECT (eprop), "current-path-str", g_strdup (path), g_free);

	gtk_entry_completion_set_model (completion, types_model);
	gtk_entry_completion_set_text_column (completion, 0);
	gtk_entry_completion_set_inline_completion (completion, TRUE);
	gtk_entry_set_completion (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (editable))), completion);
	g_object_unref (G_OBJECT (completion));
}

static void
types_combo_editing_canceled (GtkCellRenderer       *renderer,
			      GladeEditorProperty   *eprop)
{
	g_idle_add ((GSourceFunc)eprop_types_focus_new, eprop);
}


static void
types_name_editing_started (GtkCellRenderer       *renderer,
			     GtkCellEditable       *editable,
			     gchar                 *path_str,
			     GladeEditorProperty   *eprop)
{
	g_object_set_data_full (G_OBJECT (eprop), "current-path-str", g_strdup (path_str), g_free);
}

static void
types_name_editing_canceled (GtkCellRenderer       *renderer,
			     GladeEditorProperty   *eprop)
{
	GladeEPropColumnTypes *eprop_types = GLADE_EPROP_COLUMN_TYPES (eprop);

	if (eprop_types->adding_column || eprop_types->setting_cursor)
		return;

	g_idle_add ((GSourceFunc)eprop_types_focus_name_no_edit, eprop);
}

static GtkWidget *
glade_eprop_column_types_create_input (GladeEditorProperty *eprop)
{
	GladeEPropColumnTypes *eprop_types = GLADE_EPROP_COLUMN_TYPES (eprop);
	GtkWidget *vbox, *swin, *label;
	GtkCellRenderer *cell;
	gchar *string;

	vbox = gtk_vbox_new (FALSE, 2);
	
/* 	hbox = gtk_hbox_new (FALSE, 4); */

	if (!types_model)
	{
		/* We make sure to do this after all the adaptors are parsed 
		 * because we load the enums/flags from the adaptors
		 */
		types_model = (GtkTreeModel *)gtk_list_store_new (1,
								  G_TYPE_STRING);

		column_types_store_populate (GTK_LIST_STORE (types_model));
	}


	string = g_strdup_printf ("<b>%s</b>", _("Add and remove columns:"));
	label = gtk_label_new (string);
	g_free (string);
	gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
	gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
	gtk_misc_set_padding (GTK_MISC (label), 2, 4);
	gtk_box_pack_start (GTK_BOX (vbox), label,  FALSE, TRUE, 0);
	
	swin = gtk_scrolled_window_new (NULL, NULL);
	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin), GTK_SHADOW_IN);
	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
	gtk_box_pack_start (GTK_BOX (vbox), swin, TRUE, TRUE, 0);
	
	eprop_types->store = gtk_list_store_new (N_COLUMNS,
						 G_TYPE_STRING,
						 G_TYPE_STRING,
						 G_TYPE_BOOLEAN,
						 G_TYPE_BOOLEAN,
						 G_TYPE_STRING,
						 PANGO_TYPE_STYLE);

	g_signal_connect (eprop_types->store, "row-deleted",
			  G_CALLBACK (eprop_treeview_row_deleted),
			  eprop);
	
	eprop_types->view = (GtkTreeView *)gtk_tree_view_new_with_model (GTK_TREE_MODEL (eprop_types->store));
	eprop_types->selection = gtk_tree_view_get_selection (eprop_types->view);
	
	gtk_tree_view_set_reorderable (eprop_types->view, TRUE);
        gtk_tree_view_set_enable_search (eprop_types->view, FALSE);
	//gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);

	g_signal_connect (eprop_types->view, "key-press-event",
			  G_CALLBACK (eprop_treeview_key_press),
			  eprop);


	/* type column */
	cell = gtk_cell_renderer_combo_new ();
	g_object_set (G_OBJECT (cell), 
		      "text-column", COLUMN_NAME,
		      "model", types_model, 
		      NULL);

	g_signal_connect (G_OBJECT (cell), "editing-started",
			  G_CALLBACK (types_combo_editing_started), eprop);

	g_signal_connect (G_OBJECT (cell), "editing-canceled",
			  G_CALLBACK (types_combo_editing_canceled), eprop);

	g_signal_connect (G_OBJECT (cell), "edited",
			  G_CALLBACK (column_type_edited), eprop);

	eprop_types->type_column = 
		gtk_tree_view_column_new_with_attributes (_("Column type"), cell,
							  "foreground", COLUMN_TYPE_FOREGROUND,
							  "style", COLUMN_TYPE_STYLE,
							  "editable", COLUMN_TYPE_EDITABLE,
							  "text", COLUMN_NAME,
							  NULL);

	gtk_tree_view_column_set_expand (eprop_types->type_column, TRUE);
	gtk_tree_view_append_column (eprop_types->view, eprop_types->type_column);	

	/* name column */
	cell = gtk_cell_renderer_text_new ();
	g_signal_connect (G_OBJECT (cell), "edited",
			  G_CALLBACK (column_name_edited), eprop);	

	g_signal_connect (G_OBJECT (cell), "editing-started",
			  G_CALLBACK (types_name_editing_started), eprop);

	g_signal_connect (G_OBJECT (cell), "editing-canceled",
			  G_CALLBACK (types_name_editing_canceled), eprop);

	eprop_types->name_column = 
		gtk_tree_view_column_new_with_attributes (_("Column name"),  cell,
							  "editable", COLUMN_NAME_EDITABLE,
							  "text", COLUMN_COLUMN_NAME,
							  NULL);

	gtk_tree_view_column_set_expand (eprop_types->name_column, TRUE);

	gtk_tree_view_append_column (eprop_types->view, eprop_types->name_column);	
	gtk_container_add (GTK_CONTAINER (swin), GTK_WIDGET (eprop_types->view));
	
	g_object_set (G_OBJECT (vbox), "height-request", 200, NULL);

	gtk_widget_show_all (vbox);
	return vbox;
}
