Commit 5da94940 authored by Johannes Schmid's avatar Johannes Schmid

signal-model: Implemented signal model inside GladeSignalEditor

This is the initial implementation, it is able to show all signals and also shows a dummy
signal handler to be able to add new handlers to a signal.
parent ea640a6a
......@@ -60,7 +60,6 @@
enum
{
UPDATE_UI,
SIGNAL_EDITOR_CREATED,
LAST_SIGNAL
};
......@@ -295,12 +294,6 @@ glade_app_update_ui_default (GladeApp *app)
glade_app_refresh_undo_redo_button (app, list->data, FALSE);
}
static void
glade_app_signal_editor_created_default (GladeApp *app, GladeSignalEditor *signal_editor)
{
glade_signal_editor_construct_signals_list (signal_editor);
}
static gboolean
clipboard_view_on_delete_cb (GtkWidget *clipboard_view, GdkEvent *e, GladeApp *app)
{
......@@ -478,7 +471,6 @@ glade_app_class_init (GladeAppClass * klass)
object_class->set_property = glade_app_set_property;
klass->update_ui_signal = glade_app_update_ui_default;
klass->signal_editor_created = glade_app_signal_editor_created_default;
klass->show_properties = NULL;
klass->hide_properties = NULL;
......@@ -498,26 +490,6 @@ glade_app_class_init (GladeAppClass * klass)
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/**
* GladeApp::signal-editor-created:
* @gladeapp: the #GladeApp which received the signal.
* @signal_editor: the new #GladeSignalEditor.
*
* Emitted when a new signal editor created.
* A tree view is created in the default handler.
* Connect your handler before the default handler for setting a custom column or renderer
* and after it for connecting to the tree view signals
*/
glade_app_signals[SIGNAL_EDITOR_CREATED] =
g_signal_new ("signal-editor-created",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GladeAppClass,
signal_editor_created),
NULL, NULL,
glade_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, G_TYPE_OBJECT);
g_object_class_install_property
(object_class, PROP_ACTIVE_PROJECT,
g_param_spec_object
......
......@@ -82,7 +82,6 @@ struct _GladeAppClass
/* signals */
void (* update_ui_signal) (GladeApp *app);
void (* signal_editor_created) (GladeApp *app, GladeSignalEditor *signal_editor);
};
......
......@@ -1781,7 +1781,7 @@ glade_base_editor_init (GladeBaseEditor *editor)
gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scroll), e->table);
/* Signal Editor */
e->signal_editor = glade_signal_editor_new (NULL);
e->signal_editor = glade_signal_editor_new ();
gtk_widget_show (GTK_WIDGET(e->signal_editor));
gtk_widget_set_size_request (GTK_WIDGET(e->signal_editor), -1, 96);
gtk_paned_pack2 (GTK_PANED (paned), GTK_WIDGET(e->signal_editor), FALSE, FALSE);
......
......@@ -597,7 +597,7 @@ static void
glade_editor_load_signal_page (GladeEditor *editor)
{
if (editor->signal_editor == NULL) {
editor->signal_editor = glade_signal_editor_new ((gpointer) editor);
editor->signal_editor = glade_signal_editor_new ();
gtk_container_add (GTK_CONTAINER (editor->page_signals),
GTK_WIDGET(editor->signal_editor));
}
......
......@@ -46,1098 +46,21 @@
#include "glade-marshallers.h"
#include "glade-accumulators.h"
typedef gboolean (*IsVoidFunc) (const gchar *signal_handler);
enum
{
GSE_COLUMN_SIGNAL,
GSE_COLUMN_HANDLER,
GSE_COLUMN_AFTER,
GSE_COLUMN_USERDATA,
GSE_COLUMN_SWAPPED,
GSE_COLUMN_USERDATA_SLOT,
GSE_COLUMN_SWAPPED_VISIBLE,
GSE_COLUMN_AFTER_VISIBLE,
GSE_COLUMN_HANDLER_EDITABLE,
GSE_COLUMN_USERDATA_EDITABLE,
GSE_COLUMN_SLOT, /* if this row contains a "<Type...>" label */
GSE_COLUMN_BOLD,
GSE_COLUMN_CONTENT,
GSE_COLUMN_WARN,
GSE_COLUMN_TOOLTIP,
GSE_NUM_COLUMNS
};
enum
{
HANDLER_EDITING_STARTED,
USERDATA_EDITING_STARTED,
LAST_SIGNAL
};
enum
{
PROP_0,
PROP_HANDLER_COLUMN,
PROP_USERDATA_COLUMN,
PROP_HANDLER_COMPLETION,
PROP_USERDATA_COMPLETION,
PROP_HANDLER_RENDERER,
PROP_USERDATA_RENDERER
};
G_DEFINE_TYPE (GladeSignalEditor, glade_signal_editor, GTK_TYPE_VBOX)
struct _GladeSignalEditorPrivate
{
GtkTreeModel *model;
GladeWidget *widget;
GladeWidgetAdaptor *adaptor;
GladeWidgetAdaptor* adaptor;
gpointer *editor;
GtkWidget *signals_list;
GtkTreeStore *model;
GtkTreeView *tree_view;
GtkTreeModel *handler_store;
GtkTreeModel *userdata_store;
GtkCellRenderer *handler_renderer;
GtkCellRenderer *userdata_renderer;
GtkTreeViewColumn *handler_column;
GtkTreeViewColumn *userdata_column;
GtkTreeViewColumn *swapped_column_ptr;
IsVoidFunc is_void_handler;
IsVoidFunc is_void_userdata;
gulong refresh_id;
GtkWidget* signal_tree;
};
#define HANDLER_DEFAULT _("<Type here>")
#define USERDATA_DEFAULT _("<Object>")
static gboolean
glade_signal_editor_handler_editing_started_default (GladeSignalEditor *editor,
gchar *signal_name,
GtkTreeIter *iter,
GtkCellEditable *editable);
static gboolean
glade_signal_editor_userdata_editing_started_default (GladeSignalEditor *editor,
gchar *signal_name,
GtkTreeIter *iter,
GtkCellEditable *editable);
static gboolean
is_void_handler (const gchar *signal_handler)
{
return ( signal_handler == NULL ||
*signal_handler == 0 ||
g_utf8_collate (signal_handler, HANDLER_DEFAULT) == 0);
}
static gboolean
is_void_userdata (const gchar *user_data)
{
return ( user_data == NULL ||
*user_data == 0 ||
g_utf8_collate (user_data, USERDATA_DEFAULT) == 0);
}
static void
glade_signal_editor_after_swapped_toggled (GtkCellRendererToggle *cell,
gchar *path_str,
gpointer data)
{
GladeSignalEditor *editor = (GladeSignalEditor*) data;
GladeSignalEditorPrivate* priv = editor->priv;
GtkTreeModel *model = GTK_TREE_MODEL (priv->model);
GtkTreeIter iter;
GtkTreeIter iter_parent;
GladeSignal *old_signal;
GladeSignal *new_signal;
GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
gchar *signal_name;
gchar *handler;
gchar *userdata;
gboolean swapped, new_swapped;
gboolean after, new_after;
/* get toggled iter */
gtk_tree_model_get_iter (model, &iter, path);
gtk_tree_model_get (model, &iter,
GSE_COLUMN_SIGNAL, &signal_name,
GSE_COLUMN_HANDLER, &handler,
GSE_COLUMN_USERDATA,&userdata,
GSE_COLUMN_SWAPPED, &swapped,
GSE_COLUMN_AFTER, &after, -1);
if (signal_name == NULL)
{
if (!gtk_tree_model_iter_parent (model, &iter_parent, &iter))
g_assert (FALSE);
gtk_tree_model_get (model, &iter_parent, GSE_COLUMN_SIGNAL, &signal_name, -1);
g_assert (signal_name != NULL);
}
if (is_void_userdata (userdata))
{
g_free (userdata);
userdata = NULL;
}
new_after = after;
new_swapped = swapped;
if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), "signal-after-cell")))
new_after = !after;
else
new_swapped = !swapped;
old_signal = glade_signal_new (signal_name, handler, userdata, after, swapped);
new_signal = glade_signal_new (signal_name, handler, userdata, new_after, new_swapped);
glade_command_change_signal (priv->widget, old_signal, new_signal);
gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
GSE_COLUMN_AFTER, new_after,
GSE_COLUMN_SWAPPED, new_swapped,
-1);
glade_signal_free (old_signal);
glade_signal_free (new_signal);
gtk_tree_path_free (path);
g_free (signal_name);
g_free (handler);
g_free (userdata);
}
static void
append_slot (GladeSignalEditor *self, GtkTreeIter *iter_signal, const gchar *signal_name)
{
GtkTreeIter iter_new_slot;
GtkTreeIter iter_class;
GladeSignalEditorPrivate* priv = self->priv;
GtkTreeModel *model = GTK_TREE_MODEL (priv->model);
GladeSignal *sig = glade_signal_new (signal_name, NULL, NULL, FALSE, FALSE);
/* Check versioning warning here with a virtual signal */
glade_project_update_signal_support_warning (priv->widget, sig);
gtk_tree_store_append (GTK_TREE_STORE (model), &iter_new_slot, iter_signal);
gtk_tree_store_set (GTK_TREE_STORE (model), &iter_new_slot,
GSE_COLUMN_HANDLER, HANDLER_DEFAULT,
GSE_COLUMN_USERDATA, USERDATA_DEFAULT,
GSE_COLUMN_SWAPPED, FALSE,
GSE_COLUMN_SWAPPED_VISIBLE, FALSE,
GSE_COLUMN_HANDLER_EDITABLE, TRUE,
GSE_COLUMN_USERDATA_EDITABLE,FALSE,
GSE_COLUMN_AFTER, FALSE,
GSE_COLUMN_AFTER_VISIBLE, FALSE,
GSE_COLUMN_SLOT, TRUE,
GSE_COLUMN_USERDATA_SLOT, TRUE,
GSE_COLUMN_CONTENT, TRUE,
GSE_COLUMN_WARN, FALSE,
GSE_COLUMN_TOOLTIP, sig->support_warning,
-1);
gtk_tree_model_iter_parent (model, &iter_class, iter_signal);
/* mark the signal & class name as bold */
gtk_tree_store_set (GTK_TREE_STORE (model), iter_signal, GSE_COLUMN_BOLD, TRUE, -1);
gtk_tree_store_set (GTK_TREE_STORE (model), &iter_class, GSE_COLUMN_BOLD, TRUE, -1);
glade_signal_free (sig);
}
static void
move_row (GtkTreeModel *model, GtkTreeIter *from, GtkTreeIter *to)
{
gchar *handler;
gchar *userdata, *support_warning;
gboolean after;
gboolean slot;
gboolean visible;
gboolean userdata_slot;
gboolean handler_editable;
gboolean userdata_editable;
gboolean swapped;
gboolean swapped_visible;
gboolean bold, content, warn;
gtk_tree_model_get (model, from,
GSE_COLUMN_HANDLER, &handler,
GSE_COLUMN_USERDATA, &userdata,
GSE_COLUMN_AFTER, &after,
GSE_COLUMN_SLOT, &slot,
GSE_COLUMN_AFTER_VISIBLE, &visible,
GSE_COLUMN_HANDLER_EDITABLE, &handler_editable,
GSE_COLUMN_USERDATA_EDITABLE, &userdata_editable,
GSE_COLUMN_USERDATA_SLOT, &userdata_slot,
GSE_COLUMN_SWAPPED, &swapped,
GSE_COLUMN_SWAPPED_VISIBLE, &swapped_visible,
GSE_COLUMN_BOLD, &bold,
GSE_COLUMN_CONTENT, &content,
GSE_COLUMN_WARN, &warn,
GSE_COLUMN_TOOLTIP, &support_warning,
-1);
gtk_tree_store_set (GTK_TREE_STORE (model), to,
GSE_COLUMN_HANDLER, handler,
GSE_COLUMN_USERDATA, userdata,
GSE_COLUMN_AFTER, after,
GSE_COLUMN_SLOT, slot,
GSE_COLUMN_AFTER_VISIBLE, visible,
GSE_COLUMN_HANDLER_EDITABLE, handler_editable,
GSE_COLUMN_USERDATA_EDITABLE, userdata_editable,
GSE_COLUMN_USERDATA_SLOT, userdata_slot,
GSE_COLUMN_SWAPPED, swapped,
GSE_COLUMN_SWAPPED_VISIBLE, swapped_visible,
GSE_COLUMN_BOLD, bold,
GSE_COLUMN_CONTENT, content,
GSE_COLUMN_WARN, warn,
GSE_COLUMN_TOOLTIP, support_warning,
-1);
g_free (support_warning);
g_free (handler);
g_free (userdata);
}
static void
remove_slot (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *iter_signal)
{
GtkTreeIter iter_class;
gtk_tree_model_iter_parent (model, &iter_class, iter_signal);
/* special case for removing the handler of the first row */
if (iter == NULL)
{
GtkTreeIter first_iter;
gtk_tree_model_iter_nth_child (model, &first_iter, iter_signal, 0);
move_row (model, &first_iter, iter_signal);
gtk_tree_store_remove (GTK_TREE_STORE (model), &first_iter);
}
else
gtk_tree_store_remove (GTK_TREE_STORE (model), iter);
if (!gtk_tree_model_iter_has_child (model, iter_signal))
{
/* mark the signal & class name as normal */
gtk_tree_store_set (GTK_TREE_STORE (model), iter_signal,
GSE_COLUMN_BOLD, FALSE, -1);
gtk_tree_store_set (GTK_TREE_STORE (model), &iter_class,
GSE_COLUMN_BOLD, FALSE, -1);
}
}
static gboolean
glade_signal_editor_handler_editing_done (GladeSignalEditor *self,
const gchar *signal_name,
const gchar *old_handler,
const gchar *new_handler,
GtkTreeIter *iter)
{
GladeSignalEditorPrivate *priv = self->priv;
GladeWidget *glade_widget = priv->widget;
GtkTreeModel *model = GTK_TREE_MODEL (priv->model);
gchar *tmp_signal_name;
gchar *userdata;
GtkTreeIter iter_signal;
gboolean after, swapped;
gboolean is_top_handler;
gtk_tree_model_get (model, iter,
GSE_COLUMN_SIGNAL, &tmp_signal_name,
GSE_COLUMN_USERDATA, &userdata,
GSE_COLUMN_AFTER, &after,
GSE_COLUMN_SWAPPED, &swapped,
-1);
if (priv->is_void_userdata (userdata))
{
g_free (userdata);
userdata = NULL;
}
if (tmp_signal_name == NULL)
{
is_top_handler = FALSE;
gtk_tree_model_iter_parent (model, &iter_signal, iter);
}
else
{
is_top_handler = TRUE;
iter_signal = *iter;
g_free (tmp_signal_name);
}
/* we're adding a new handler */
if (old_handler == NULL && new_handler)
{
GladeSignal *new_signal = glade_signal_new (signal_name, new_handler,
NULL, FALSE, FALSE);
glade_command_add_signal (glade_widget, new_signal);
glade_signal_free (new_signal);
gtk_tree_store_set (GTK_TREE_STORE (model), iter,
GSE_COLUMN_HANDLER, new_handler,
GSE_COLUMN_AFTER_VISIBLE, TRUE,
GSE_COLUMN_SLOT, FALSE,
GSE_COLUMN_USERDATA_EDITABLE,TRUE, -1);
/* append a <Type...> slot */
append_slot (self, &iter_signal, signal_name);
}
/* we're removing a signal handler */
else if (old_handler && new_handler == NULL)
{
GladeSignal *old_signal =
glade_signal_new (signal_name,
old_handler,
userdata,
after,
swapped);
glade_command_remove_signal (glade_widget, old_signal);
glade_signal_free (old_signal);
gtk_tree_store_set
(GTK_TREE_STORE (model), iter,
GSE_COLUMN_HANDLER, HANDLER_DEFAULT,
GSE_COLUMN_AFTER, FALSE,
GSE_COLUMN_USERDATA, USERDATA_DEFAULT,
GSE_COLUMN_SWAPPED, FALSE,
GSE_COLUMN_SWAPPED_VISIBLE, FALSE,
GSE_COLUMN_HANDLER_EDITABLE, TRUE,
GSE_COLUMN_USERDATA_EDITABLE,FALSE,
GSE_COLUMN_AFTER_VISIBLE, FALSE,
GSE_COLUMN_SLOT, TRUE,
GSE_COLUMN_USERDATA_SLOT, TRUE,
GSE_COLUMN_CONTENT, TRUE,
-1);
remove_slot (model, is_top_handler ? NULL : iter, &iter_signal);
}
/* we're changing a signal handler */
else if (old_handler && new_handler)
{
GladeSignal *old_signal =
glade_signal_new
(signal_name,
old_handler,
userdata,
after,
swapped);
GladeSignal *new_signal =
glade_signal_new
(signal_name,
new_handler,
userdata,
after,
swapped);
if (glade_signal_equal (old_signal, new_signal) == FALSE)
glade_command_change_signal (glade_widget, old_signal, new_signal);
glade_signal_free (old_signal);
glade_signal_free (new_signal);
gtk_tree_store_set (GTK_TREE_STORE (model), iter,
GSE_COLUMN_HANDLER, new_handler,
GSE_COLUMN_AFTER_VISIBLE, TRUE,
GSE_COLUMN_SLOT, FALSE,
GSE_COLUMN_USERDATA_EDITABLE,TRUE, -1);
}
g_free (userdata);
return FALSE;
}
static gboolean
glade_signal_editor_userdata_editing_done (GladeSignalEditor *self,
const gchar *signal_name,
const gchar *old_userdata,
const gchar *new_userdata,
GtkTreeIter *iter)
{
GladeSignalEditorPrivate *priv = self->priv;
GtkTreeModel *model = GTK_TREE_MODEL (priv->model);
GladeWidget *glade_widget = priv->widget;
gchar *handler;
gboolean after, swapped;
GladeSignal *old_signal, *new_signal;
gtk_tree_model_get (model, iter,
GSE_COLUMN_HANDLER, &handler,
GSE_COLUMN_AFTER, &after,
GSE_COLUMN_SWAPPED, &swapped,
-1);
/* We are removing userdata */
if (new_userdata == NULL)
{
gtk_tree_store_set (GTK_TREE_STORE (model), iter,
GSE_COLUMN_USERDATA_SLOT, TRUE,
GSE_COLUMN_USERDATA, USERDATA_DEFAULT,
GSE_COLUMN_SWAPPED, FALSE,
GSE_COLUMN_SWAPPED_VISIBLE, FALSE, -1);
}
else
{
gtk_tree_store_set (GTK_TREE_STORE (model), iter,
GSE_COLUMN_USERDATA_SLOT, FALSE,
GSE_COLUMN_USERDATA, new_userdata,
GSE_COLUMN_SWAPPED_VISIBLE, TRUE,
-1);
}
old_signal = glade_signal_new (signal_name, handler, old_userdata, after, swapped);
new_signal = glade_signal_new (signal_name, handler, new_userdata, after, swapped);
if (glade_signal_equal (old_signal, new_signal) == FALSE)
glade_command_change_signal (glade_widget, old_signal, new_signal);
glade_signal_free (old_signal);
glade_signal_free (new_signal);
g_free (handler);
return FALSE;
}
static gchar *
glade_signal_editor_get_signal_name (GtkTreeModel *model, GtkTreeIter *iter)
{
gchar *signal_name;
gtk_tree_model_get (model, iter,
GSE_COLUMN_SIGNAL, &signal_name,
-1);
if (signal_name == NULL)
{
GtkTreeIter iter_signal;
if (!gtk_tree_model_iter_parent (model, &iter_signal, iter))
g_assert (FALSE);
gtk_tree_model_get (model, &iter_signal, GSE_COLUMN_SIGNAL, &signal_name, -1);
g_assert (signal_name != NULL);
}
return signal_name;
}
static void
glade_signal_editor_column_cell_edited (const gchar *path_str,
const gchar *new_value,
gpointer data,
gint column,
IsVoidFunc is_void_callback)
{
GladeSignalEditor* self = GLADE_SIGNAL_EDITOR (data);
GladeSignalEditorPrivate *priv = self->priv;
GtkTreeModel *model = GTK_TREE_MODEL (priv->model);
GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
GtkTreeIter iter;
gchar *signal_name;
gchar *old_value;
g_return_if_fail (gtk_tree_model_get_iter (model, &iter, path));
gtk_tree_path_free (path);
gtk_tree_model_get (model, &iter,
column, &old_value,
-1);
signal_name = glade_signal_editor_get_signal_name (model, &iter);
if (is_void_callback (new_value))
new_value = NULL;
if (is_void_callback (old_value))
{
g_free (old_value);
old_value = NULL;
}
/* if not a false alarm */
if (old_value || new_value);
{
switch (column)
{
case GSE_COLUMN_HANDLER:
glade_signal_editor_handler_editing_done (self,
signal_name,
old_value,
new_value,
&iter);
break;
case GSE_COLUMN_USERDATA:
glade_signal_editor_userdata_editing_done (self,
signal_name,
old_value,
new_value,
&iter);
break;
}
}
g_free (signal_name);
g_free (old_value);
}
static void
glade_signal_editor_handler_cell_edited (GtkCellRendererText *cell,
const gchar *path_str,
const gchar *new_handler,
gpointer data)
{
GladeSignalEditor *editor = GLADE_SIGNAL_EDITOR (data);
glade_signal_editor_column_cell_edited (path_str, new_handler, data,
GSE_COLUMN_HANDLER,
editor->priv->is_void_handler);
}
static void
glade_signal_editor_userdata_cell_edited (GtkCellRendererText *cell,
const gchar *path_str,
const gchar *new_userdata,
gpointer data)
{
GladeSignalEditor *editor = GLADE_SIGNAL_EDITOR (data);
glade_signal_editor_column_cell_edited (path_str, new_userdata, data,
GSE_COLUMN_USERDATA,
editor->priv->is_void_userdata);
}
static void
glade_signal_editor_column_editing_started (GtkCellEditable *editable,
const gchar *path_str,
GladeSignalEditor *editor,
guint signal)
{
GladeSignalEditorPrivate *priv = editor->priv;
GtkTreeModel *model = GTK_TREE_MODEL (priv->model);
GtkTreePath *path;
GtkTreeIter iter;
gchar *signal_name;
path = gtk_tree_path_new_from_string (path_str);
g_return_if_fail (gtk_tree_model_get_iter (model, &iter, path));
gtk_tree_path_free (path);
signal_name = glade_signal_editor_get_signal_name (model, &iter);
switch (signal)
{
case HANDLER_EDITING_STARTED:
glade_signal_editor_handler_editing_started_default (editor,
signal_name,
&iter,
editable);
break;
case USERDATA_EDITING_STARTED:
glade_signal_editor_userdata_editing_started_default (editor,
signal_name,
&iter,
editable);
break;
}
g_free (signal_name);
}
static void
glade_signal_editor_handler_editing_started (GtkCellRenderer *cell,
GtkCellEditable *editable,
const gchar *path,
GladeSignalEditor *editor)
{
glade_signal_editor_column_editing_started (editable, path,
editor, HANDLER_EDITING_STARTED);
}
static void
glade_signal_editor_userdata_editing_started (GtkCellRenderer *cell,
GtkCellEditable *editable,
const gchar *path,
GladeSignalEditor *editor)
{
glade_signal_editor_column_editing_started (editable, path,
editor, USERDATA_EDITING_STARTED);
}
static void
glade_signal_editor_signal_cell_data_func (GtkTreeViewColumn *tree_column,
GtkCellRenderer *cell,
GtkTreeModel *tree_model,
GtkTreeIter *iter,
gpointer data)
{
gboolean bold;
gtk_tree_model_get (tree_model, iter, GSE_COLUMN_BOLD, &bold, -1);
if (bold)
g_object_set (G_OBJECT (cell), "weight", PANGO_WEIGHT_BOLD, NULL);
else
g_object_set (G_OBJECT (cell), "weight", PANGO_WEIGHT_NORMAL, NULL);
}
static void
glade_signal_editor_handler_cell_data_func (GtkTreeViewColumn *tree_column,
GtkCellRenderer *cell,
GtkTreeModel *tree_model,
GtkTreeIter *iter,
gpointer data)