Commit 5b131bb1 authored by Juan Pablo Ugarte's avatar Juan Pablo Ugarte
Browse files

gladeui/glade-signal-editor.[ch]:

  o added GladeSignalEditor::detail-suggestions signal
  o Fixed memory leak on handler-suggestion emmision

gladeui/glade-signal-model.c: Removed "__dummy" object data hack
  Now only the data model returns user strings like <Type Here> when the GladeSignal value is null

gladeui/glade-signal.c: fixed bug in glade_signal_set_detail() that allowed to set an empty string as a detail
parent de4a76fe
......@@ -49,7 +49,8 @@
G_DEFINE_TYPE (GladeSignalEditor, glade_signal_editor, GTK_TYPE_VBOX)
#define DUMMY_DATA "__dummy"
#define GLADE_SIGNAL_EDITOR_GET_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), GLADE_TYPE_SIGNAL_EDITOR, GladeSignalEditorPrivate))
struct _GladeSignalEditorPrivate
{
......@@ -67,14 +68,16 @@ struct _GladeSignalEditorPrivate
GtkTreeViewColumn *column_after;
GtkCellRenderer *renderer_userdata;
GtkListStore *handler_completion_store;
GtkListStore *detail_store;
GtkListStore *handler_store;
};
enum
{
SIGNAL_ACTIVATED,
CALLBACK_SUGGESTIONS,
DETAIL_SUGGESTIONS,
LAST_SIGNAL
};
......@@ -90,7 +93,7 @@ static guint glade_signal_editor_signals[LAST_SIGNAL] = { 0 };
static inline gboolean
glade_signal_is_dummy (GladeSignal *signal)
{
return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (signal), DUMMY_DATA));
return glade_signal_get_handler (signal) == NULL;
}
/* Signal handlers */
......@@ -118,7 +121,6 @@ on_handler_edited (GtkCellRendererText *renderer,
GLADE_SIGNAL_COLUMN_SIGNAL, &signal, -1);
dummy = glade_signal_is_dummy (signal);
g_object_unref (signal);
/* False alarm ? */
if (handler && !g_str_equal (old_handler, handler))
......@@ -143,6 +145,7 @@ on_handler_edited (GtkCellRendererText *renderer,
glade_command_change_signal (self->priv->widget, old_signal, new_signal);
g_object_unref (old_signal);
g_object_unref (new_signal);
}
else
......@@ -160,26 +163,24 @@ on_handler_edited (GtkCellRendererText *renderer,
}
else if (strlen (handler))
{
GladeSignal *signal;
GladeSignal *dummy;
gchar *name;
GladeSignal *new_signal;
/* Get the signal name */
gtk_tree_model_get (self->priv->model, &iter,
GLADE_SIGNAL_COLUMN_NAME, &name,
GLADE_SIGNAL_COLUMN_SIGNAL, &dummy,
GLADE_SIGNAL_COLUMN_SIGNAL, &signal,
-1);
/* Add a new signal handler */
signal = glade_signal_new (glade_signal_get_class (dummy),
handler, NULL, FALSE, FALSE);
glade_command_add_signal (self->priv->widget, signal);
g_object_unref (signal);
g_object_unref (dummy);
g_free (name);
new_signal = glade_signal_new (glade_signal_get_class (signal),
handler, NULL, FALSE, FALSE);
glade_signal_set_detail (new_signal, glade_signal_get_detail (signal));
glade_command_add_signal (self->priv->widget, new_signal);
glade_signal_set_detail (signal, NULL);
g_object_unref (new_signal);
}
}
g_object_unref (signal);
g_free (old_handler);
gtk_tree_path_free (tree_path);
}
......@@ -215,6 +216,105 @@ glade_signal_editor_callback_suggestions (GladeSignalEditor *editor,
return suggestions;
}
static gchar **
glade_signal_editor_detail_suggestions (GladeSignalEditor *editor,
GladeSignal *signal)
{
/* We only support suggestions for notify signal */
if (!g_strcmp0 (glade_signal_get_name (signal), "notify"))
{
GladeSignalEditorPrivate *priv = editor->priv;
const GList *l, *properties = glade_widget_adaptor_get_properties (priv->adaptor);
gchar **suggestions = g_new (gchar *, g_list_length ((GList *)properties) + 1);
gint i;
for (i = 0, l = properties; l; l = g_list_next (l))
{
GladePropertyClass *prop = l->data;
if (!glade_property_class_is_visible (prop) ||
glade_property_class_get_virtual (prop)) continue;
suggestions[i++] = g_strdup (glade_property_class_id (prop));
}
suggestions[i] = NULL;
return suggestions;
}
return NULL;
}
static void
gse_entry_completion_ensure_model (GtkEntry *entry, GtkTreeModel *model)
{
GtkEntryCompletion *completion = gtk_entry_completion_new ();
gtk_entry_completion_set_text_column (completion, 0);
gtk_entry_completion_set_minimum_key_length (completion, 0);
gtk_entry_completion_set_inline_completion (completion, FALSE);
gtk_entry_completion_set_inline_selection (completion, TRUE);
gtk_entry_completion_set_popup_completion (completion, TRUE);
gtk_entry_completion_set_model (completion, model);
gtk_entry_set_completion (entry, completion);
}
static void
on_detail_editing_started (GtkCellRenderer *renderer,
GtkCellEditable *editable,
gchar *path,
gpointer user_data)
{
/* Check if editable is still an entry */
if (GTK_IS_ENTRY (editable))
{
GladeSignalEditor *self = GLADE_SIGNAL_EDITOR (user_data);
GladeSignalEditorPrivate *priv = self->priv;
GtkEntry *entry = GTK_ENTRY (editable);
GtkTreePath *tree_path;
GtkTreeIter iter;
GladeSignal *signal;
gchar **suggestions;
tree_path = gtk_tree_path_new_from_string (path);
gtk_tree_model_get_iter (priv->model, &iter, tree_path);
gtk_tree_path_free (tree_path);
gtk_tree_model_get (priv->model, &iter,
GLADE_SIGNAL_COLUMN_SIGNAL, &signal,
-1);
if (glade_signal_get_detail (signal) == NULL)
gtk_entry_set_text (entry, "");
g_object_unref (signal);
gtk_entry_set_completion (entry, NULL);
gtk_list_store_clear (priv->detail_store);
g_signal_emit (self, glade_signal_editor_signals [DETAIL_SUGGESTIONS], 0, signal, &suggestions);
if (suggestions)
{
register GtkListStore *store = priv->detail_store;
gint i;
for (i = 0; suggestions[i]; i++)
{
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, 0, suggestions[i], -1);
}
gse_entry_completion_ensure_model (entry, GTK_TREE_MODEL (store));
g_strfreev (suggestions);
}
}
}
static void
on_detail_edited (GtkCellRendererText *renderer,
gchar *path,
......@@ -233,25 +333,29 @@ on_detail_edited (GtkCellRendererText *renderer,
gtk_tree_model_get (self->priv->model, &iter,
GLADE_SIGNAL_COLUMN_DETAIL, &old_detail, -1);
if (detail && g_strcmp0 (old_detail, detail))
if (detail && strlen (detail) && g_strcmp0 (old_detail, detail))
{
/* change an existing signal detail */
GladeSignal *old_signal;
GladeSignal *new_signal;
gtk_tree_model_get (self->priv->model,
&iter,
GLADE_SIGNAL_COLUMN_SIGNAL,
&old_signal, -1);
new_signal = glade_signal_clone (old_signal);
/* Change the new signal detail */
glade_signal_set_detail (new_signal, detail);
glade_command_change_signal (self->priv->widget, old_signal, new_signal);
if (glade_signal_is_dummy (old_signal))
{
glade_signal_set_detail (old_signal, detail);
}
else
{
GladeSignal *new_signal = glade_signal_clone (old_signal);
glade_signal_set_detail (new_signal, detail);
glade_command_change_signal (self->priv->widget, old_signal, new_signal);
g_object_unref (new_signal);
}
g_object_unref (new_signal);
g_object_unref (old_signal);
}
g_free (old_detail);
gtk_tree_path_free (tree_path);
......@@ -269,8 +373,6 @@ on_handler_editing_started (GtkCellRenderer *renderer,
GladeSignalEditor *self = GLADE_SIGNAL_EDITOR (user_data);
GladeSignalEditorPrivate *priv = self->priv;
GtkEntry *entry = GTK_ENTRY (editable);
GtkEntryCompletion *completion;
const gchar *signal_name = NULL;
GtkTreePath *tree_path;
GtkTreeIter iter;
GladeSignal *signal;
......@@ -284,7 +386,6 @@ on_handler_editing_started (GtkCellRenderer *renderer,
gtk_tree_model_get (priv->model, &iter,
GLADE_SIGNAL_COLUMN_SIGNAL, &signal,
-1);
signal_name = glade_signal_get_name (signal);
if (glade_signal_is_dummy (signal))
gtk_entry_set_text (entry, "");
......@@ -293,27 +394,21 @@ on_handler_editing_started (GtkCellRenderer *renderer,
g_object_unref (signal);
if (!signal_name)
return;
completion = gtk_entry_completion_new ();
gtk_entry_completion_set_text_column (completion, 0);
gtk_entry_completion_set_minimum_key_length (completion, 0);
gtk_entry_completion_set_inline_completion (completion, FALSE);
gtk_entry_completion_set_inline_selection (completion, TRUE);
gtk_entry_completion_set_popup_completion (completion, TRUE);
gtk_entry_set_completion (entry, NULL);
gtk_list_store_clear (priv->handler_store);
gtk_list_store_clear (priv->handler_completion_store);
for (i = 0; suggestions[i]; i++)
if (suggestions)
{
gtk_list_store_append (priv->handler_completion_store, &iter);
gtk_list_store_set (priv->handler_completion_store, &iter, 0, suggestions[i], -1);
register GtkListStore *store = priv->handler_store;
for (i = 0; suggestions[i]; i++)
{
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, 0, suggestions[i], -1);
}
gse_entry_completion_ensure_model (entry, GTK_TREE_MODEL (store));
g_strfreev (suggestions);
}
gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (priv->handler_completion_store));
gtk_entry_set_completion (entry, completion);
}
}
......@@ -617,6 +712,11 @@ glade_signal_editor_enable_dnd (GladeSignalEditor *editor, gboolean enabled)
static void
glade_signal_editor_dispose (GObject *object)
{
GladeSignalEditorPrivate *priv = GLADE_SIGNAL_EDITOR_GET_PRIVATE (object);
g_object_unref (priv->detail_store);
g_object_unref (priv->handler_store);
G_OBJECT_CLASS (glade_signal_editor_parent_class)->dispose (object);
}
......@@ -841,7 +941,7 @@ glade_signal_editor_detail_cell_data_func (GtkTreeViewColumn *column,
}
g_object_set (renderer,
"sensitive", !dummy,
"sensitive", TRUE,
"visible", TRUE,
"editable", TRUE,
NULL);
......@@ -1070,6 +1170,7 @@ glade_signal_editor_init (GladeSignalEditor *self)
/* Signal detail */
renderer = gtk_cell_renderer_text_new ();
g_signal_connect (renderer, "edited", G_CALLBACK(on_detail_edited), self);
g_signal_connect (renderer, "editing-started", G_CALLBACK (on_detail_editing_started), self);
priv->column_detail = gtk_tree_view_column_new_with_attributes (_("Detail"),
renderer,
"text", GLADE_SIGNAL_COLUMN_DETAIL,
......@@ -1214,8 +1315,11 @@ glade_signal_editor_init (GladeSignalEditor *self)
G_CALLBACK(glade_signal_editor_drag_begin),
self);
/* Detail completion */
priv->detail_store = gtk_list_store_new (1, G_TYPE_STRING);
/* Handler completion */
priv->handler_completion_store = gtk_list_store_new (1, G_TYPE_STRING);
priv->handler_store = gtk_list_store_new (1, G_TYPE_STRING);
/* Emit created signal */
g_signal_emit_by_name (glade_app_get(), "signal-editor-created", self);
......@@ -1236,6 +1340,7 @@ glade_signal_editor_class_init (GladeSignalEditorClass *klass)
object_class->dispose = glade_signal_editor_dispose;
klass->callback_suggestions = glade_signal_editor_callback_suggestions;
klass->detail_suggestions = glade_signal_editor_detail_suggestions;
g_type_class_add_private (klass, sizeof (GladeSignalEditorPrivate));
......@@ -1273,6 +1378,26 @@ glade_signal_editor_class_init (GladeSignalEditorClass *klass)
_glade_strv_handled_accumulator,
NULL, _glade_marshal_BOXED__OBJECT,
G_TYPE_STRV, 1,
GLADE_TYPE_SIGNAL);
/**
* GladeSignalEditor::detail-suggestions:
* @editor: the object which received the signal
* @signal: the #GladeSignal that needs callbacks suggestions
* @suggestions: Return
*
* Emitted when the editor needs to show a list of detail suggestions to the user.
*
* Returns wheter or not the event was handled.
*/
glade_signal_editor_signals[DETAIL_SUGGESTIONS] =
g_signal_new ("detail-suggestions",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GladeSignalEditorClass, detail_suggestions),
_glade_strv_handled_accumulator,
NULL, _glade_marshal_BOXED__OBJECT,
G_TYPE_STRV, 1,
GLADE_TYPE_SIGNAL);
......
......@@ -32,11 +32,11 @@ struct _GladeSignalEditorClass
GtkVBoxClass parent_class;
gchar ** (* callback_suggestions) (GladeSignalEditor *editor, GladeSignal *signal);
gchar ** (* detail_suggestions) (GladeSignalEditor *editor, GladeSignal *signal);
void (* glade_reserved1) (void);
void (* glade_reserved2) (void);
void (* glade_reserved3) (void);
void (* glade_reserved4) (void);
void (* glade_reserved5) (void);
};
GType glade_signal_editor_get_type (void) G_GNUC_CONST;
......
......@@ -30,8 +30,6 @@
#define HANDLER_DEFAULT _("<Type here>")
#define USERDATA_DEFAULT _("<Click here>")
#define DUMMY_DATA "__dummy"
struct _GladeSignalModelPrivate
{
GladeWidget *widget;
......@@ -274,7 +272,7 @@ static inline gboolean
glade_signal_model_is_dummy_handler (GladeSignalModel *model,
GladeSignal *signal)
{
return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (signal), DUMMY_DATA));
return glade_signal_get_handler (signal) == NULL;
}
static GladeSignal *
......@@ -289,12 +287,10 @@ glade_signal_model_get_dummy_handler (GladeSignalModel *model,
if (!signal)
{
signal = glade_signal_new (sig_class,
HANDLER_DEFAULT,
USERDATA_DEFAULT,
NULL,
NULL,
FALSE,
FALSE);
glade_signal_set_detail (signal, DETAIL_DEFAULT);
g_object_set_data (G_OBJECT (signal), DUMMY_DATA, GINT_TO_POINTER (TRUE));
g_hash_table_insert (model->priv->dummy_signals,
(gpointer) glade_signal_class_get_name (sig_class),
signal);
......@@ -558,14 +554,14 @@ glade_signal_model_get_value (GtkTreeModel *model,
GValue *value)
{
const gchar *widget;
GladeSignal *handler;
GladeSignal *signal;
GladeSignalModel *sig_model;
g_return_if_fail (iter != NULL);
g_return_if_fail (GLADE_IS_SIGNAL_MODEL(model));
widget = iter->user_data;
handler = iter->user_data2;
signal = iter->user_data2;
sig_model = GLADE_SIGNAL_MODEL (model);
value = g_value_init (value,
......@@ -574,39 +570,41 @@ glade_signal_model_get_value (GtkTreeModel *model,
switch (column)
{
case GLADE_SIGNAL_COLUMN_NAME:
if (handler)
if (signal)
{
g_value_set_static_string (value, glade_signal_get_name (handler));
g_value_set_static_string (value, glade_signal_get_name (signal));
break;
}
else
g_value_set_static_string (value, widget);
break;
case GLADE_SIGNAL_COLUMN_SHOW_NAME:
if (handler)
if (signal)
{
GPtrArray *handlers = g_hash_table_lookup (sig_model->priv->signals,
glade_signal_get_name (handler));
if (!handlers || !handlers->len || g_ptr_array_find (handlers, handler) == 0)
glade_signal_get_name (signal));
if (!handlers || !handlers->len || g_ptr_array_find (handlers, signal) == 0)
g_value_set_boolean (value, TRUE);
else
g_value_set_boolean (value,
FALSE);
g_value_set_boolean (value, FALSE);
break;
}
else if (widget)
g_value_set_boolean (value, TRUE);
break;
case GLADE_SIGNAL_COLUMN_HANDLER:
if (handler)
g_value_set_static_string (value, glade_signal_get_handler (handler));
if (signal)
{
const gchar *handler = glade_signal_get_handler (signal);
g_value_set_static_string (value, handler ? handler : HANDLER_DEFAULT);
}
else
g_value_set_static_string (value, "");
break;
case GLADE_SIGNAL_COLUMN_OBJECT:
if (handler)
if (signal)
{
const gchar *userdata = glade_signal_get_userdata (handler);
const gchar *userdata = glade_signal_get_userdata (signal);
if (userdata && strlen (userdata))
g_value_set_static_string (value, userdata);
else
......@@ -617,29 +615,32 @@ glade_signal_model_get_value (GtkTreeModel *model,
g_value_set_static_string (value, "");
break;
case GLADE_SIGNAL_COLUMN_SWAP:
if (handler)
g_value_set_boolean (value, glade_signal_get_swapped (handler));
if (signal)
g_value_set_boolean (value, glade_signal_get_swapped (signal));
else
g_value_set_boolean (value, FALSE);
break;
case GLADE_SIGNAL_COLUMN_AFTER:
if (handler)
g_value_set_boolean (value, glade_signal_get_after (handler));
if (signal)
g_value_set_boolean (value, glade_signal_get_after (signal));
else
g_value_set_boolean (value, FALSE);
break;
case GLADE_SIGNAL_COLUMN_TOOLTIP:
if (handler)
g_value_set_string (value, glade_signal_get_support_warning (handler));
if (signal)
g_value_set_string (value, glade_signal_get_support_warning (signal));
else
g_value_set_static_string (value, NULL);
break;
case GLADE_SIGNAL_COLUMN_SIGNAL:
g_value_set_object (value, handler);
g_value_set_object (value, signal);
break;
case GLADE_SIGNAL_COLUMN_DETAIL:
if (handler)
g_value_set_static_string (value, glade_signal_get_detail (handler));
if (signal)
{
const gchar *detail = glade_signal_get_detail (signal);
g_value_set_static_string (value, detail ? detail : DETAIL_DEFAULT);
}
else
g_value_set_static_string (value, "");
break;
......
......@@ -450,7 +450,7 @@ glade_signal_set_detail (GladeSignal *signal, const gchar *detail)
g_strcmp0 (signal->priv->detail, detail))
{
g_free (signal->priv->detail);
signal->priv->detail = (detail || g_utf8_strlen (detail, -1)) ? g_strdup (detail) : NULL;
signal->priv->detail = (detail && g_utf8_strlen (detail, -1)) ? g_strdup (detail) : NULL;
g_object_notify_by_pspec (G_OBJECT (signal), properties[PROP_DETAIL]);
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment