1293 lines
38 KiB
C
1293 lines
38 KiB
C
/*
|
|
* mooutils-treeview.c
|
|
*
|
|
* Copyright (C) 2004-2006 by Yevgen Muntyan <muntyan@math.tamu.edu>
|
|
*
|
|
* 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.
|
|
*
|
|
* See COPYING file that comes with this distribution.
|
|
*/
|
|
|
|
#include "mooutils/mooutils-treeview.h"
|
|
#include "mooutils/moomarshals.h"
|
|
|
|
|
|
#define MOO_TYPE_TREE_HELPER (_moo_tree_helper_get_type ())
|
|
#define MOO_TREE_HELPER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MOO_TYPE_TREE_HELPER, MooTreeHelper))
|
|
#define MOO_TREE_HELPER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOO_TYPE_TREE_HELPER, MooTreeHelperClass))
|
|
#define MOO_IS_TREE_HELPER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MOO_TYPE_TREE_HELPER))
|
|
#define MOO_IS_TREE_HELPER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOO_TYPE_TREE_HELPER))
|
|
#define MOO_TREE_HELPER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOO_TYPE_TREE_HELPER, MooTreeHelperClass))
|
|
|
|
|
|
typedef enum {
|
|
TREE_VIEW,
|
|
COMBO_BOX
|
|
} WidgetType;
|
|
|
|
struct _MooTreeHelper {
|
|
GtkObject parent;
|
|
|
|
WidgetType type;
|
|
gpointer widget;
|
|
|
|
GtkWidget *new_btn;
|
|
GtkWidget *delete_btn;
|
|
GtkWidget *up_btn;
|
|
GtkWidget *down_btn;
|
|
};
|
|
|
|
|
|
GType _moo_tree_helper_get_type (void) G_GNUC_CONST;
|
|
|
|
static void moo_tree_helper_new_row (MooTreeHelper *helper);
|
|
static void moo_tree_helper_delete_row (MooTreeHelper *helper);
|
|
static void moo_tree_helper_row_up (MooTreeHelper *helper);
|
|
static void moo_tree_helper_row_down (MooTreeHelper *helper);
|
|
static void moo_tree_helper_real_update_widgets (MooTreeHelper *helper,
|
|
GtkTreeModel *model,
|
|
GtkTreePath *path);
|
|
static GtkTreeModel *moo_tree_helper_get_model (MooTreeHelper *helper);
|
|
static gboolean moo_tree_helper_get_selected (MooTreeHelper *helper,
|
|
GtkTreeModel **model,
|
|
GtkTreeIter *iter);
|
|
|
|
|
|
G_DEFINE_TYPE (MooTreeHelper, _moo_tree_helper, GTK_TYPE_OBJECT)
|
|
|
|
|
|
enum {
|
|
NEW_ROW,
|
|
DELETE_ROW,
|
|
MOVE_ROW,
|
|
UPDATE_WIDGETS,
|
|
UPDATE_MODEL,
|
|
TREE_NUM_SIGNALS
|
|
};
|
|
|
|
static guint tree_signals[TREE_NUM_SIGNALS];
|
|
|
|
|
|
static void
|
|
tree_selection_changed (GtkTreeSelection *selection,
|
|
MooTreeHelper *helper)
|
|
{
|
|
GtkTreeRowReference *old_row;
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
GtkTreePath *path, *old_path;
|
|
|
|
old_row = g_object_get_data (G_OBJECT (selection), "moo-tree-helper-current-row");
|
|
old_path = old_row ? gtk_tree_row_reference_get_path (old_row) : NULL;
|
|
|
|
if (old_row && !old_path)
|
|
{
|
|
g_object_set_data (G_OBJECT (selection), "moo-tree-helper-current-row", NULL);
|
|
old_row = NULL;
|
|
}
|
|
|
|
if (gtk_tree_selection_get_selected (selection, &model, &iter))
|
|
{
|
|
path = gtk_tree_model_get_path (model, &iter);
|
|
|
|
if (old_path && !gtk_tree_path_compare (old_path, path))
|
|
{
|
|
gtk_tree_path_free (old_path);
|
|
gtk_tree_path_free (path);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!old_path)
|
|
return;
|
|
|
|
path = NULL;
|
|
}
|
|
|
|
if (old_path)
|
|
moo_tree_helper_update_model (helper, model, old_path);
|
|
|
|
moo_tree_helper_real_update_widgets (helper, model, path);
|
|
|
|
if (path)
|
|
{
|
|
GtkTreeRowReference *row;
|
|
row = gtk_tree_row_reference_new (model, path);
|
|
g_object_set_data_full (G_OBJECT (selection), "moo-tree-helper-current-row", row,
|
|
(GDestroyNotify) gtk_tree_row_reference_free);
|
|
}
|
|
else
|
|
{
|
|
g_object_set_data (G_OBJECT (selection), "moo-tree-helper-current-row", NULL);
|
|
}
|
|
|
|
gtk_tree_path_free (path);
|
|
gtk_tree_path_free (old_path);
|
|
}
|
|
|
|
|
|
static void
|
|
combo_changed (GtkComboBox *combo,
|
|
MooTreeHelper *helper)
|
|
{
|
|
GtkTreeRowReference *old_row;
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
GtkTreePath *path, *old_path;
|
|
|
|
g_return_if_fail (MOO_IS_TREE_HELPER (helper));
|
|
g_return_if_fail (combo == helper->widget);
|
|
|
|
old_row = g_object_get_data (G_OBJECT (combo), "moo-tree-helper-current-row");
|
|
old_path = old_row ? gtk_tree_row_reference_get_path (old_row) : NULL;
|
|
|
|
if (old_row && !old_path)
|
|
{
|
|
g_object_set_data (G_OBJECT (combo), "moo-tree-helper-current-row", NULL);
|
|
old_row = NULL;
|
|
}
|
|
|
|
if (moo_tree_helper_get_selected (helper, &model, &iter))
|
|
{
|
|
path = gtk_tree_model_get_path (model, &iter);
|
|
|
|
if (old_path && !gtk_tree_path_compare (old_path, path))
|
|
{
|
|
gtk_tree_path_free (old_path);
|
|
gtk_tree_path_free (path);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!old_path)
|
|
return;
|
|
|
|
path = NULL;
|
|
}
|
|
|
|
if (old_path)
|
|
moo_tree_helper_update_model (helper, model, old_path);
|
|
|
|
moo_tree_helper_real_update_widgets (helper, model, path);
|
|
|
|
if (path)
|
|
{
|
|
GtkTreeRowReference *row;
|
|
row = gtk_tree_row_reference_new (model, path);
|
|
g_object_set_data_full (G_OBJECT (combo), "moo-tree-helper-current-row", row,
|
|
(GDestroyNotify) gtk_tree_row_reference_free);
|
|
}
|
|
else
|
|
{
|
|
g_object_set_data (G_OBJECT (combo), "moo-tree-helper-current-row", NULL);
|
|
}
|
|
|
|
gtk_tree_path_free (path);
|
|
gtk_tree_path_free (old_path);
|
|
}
|
|
|
|
|
|
static void
|
|
moo_tree_helper_destroy (GtkObject *object)
|
|
{
|
|
MooTreeHelper *helper = MOO_TREE_HELPER (object);
|
|
|
|
if (helper->widget)
|
|
{
|
|
GtkTreeSelection *selection;
|
|
|
|
g_signal_handlers_disconnect_by_func (helper->widget,
|
|
(gpointer) gtk_object_destroy,
|
|
helper);
|
|
|
|
switch (helper->type)
|
|
{
|
|
case TREE_VIEW:
|
|
selection = gtk_tree_view_get_selection (helper->widget);
|
|
g_signal_handlers_disconnect_by_func (selection,
|
|
(gpointer) tree_selection_changed,
|
|
helper);
|
|
break;
|
|
|
|
case COMBO_BOX:
|
|
g_signal_handlers_disconnect_by_func (helper->widget,
|
|
(gpointer) combo_changed,
|
|
helper);
|
|
break;
|
|
}
|
|
|
|
if (helper->new_btn)
|
|
g_signal_handlers_disconnect_by_func (helper->new_btn,
|
|
(gpointer) moo_tree_helper_new_row,
|
|
helper);
|
|
if (helper->delete_btn)
|
|
g_signal_handlers_disconnect_by_func (helper->delete_btn,
|
|
(gpointer) moo_tree_helper_delete_row,
|
|
helper);
|
|
if (helper->up_btn)
|
|
g_signal_handlers_disconnect_by_func (helper->up_btn,
|
|
(gpointer) moo_tree_helper_row_up,
|
|
helper);
|
|
if (helper->down_btn)
|
|
g_signal_handlers_disconnect_by_func (helper->down_btn,
|
|
(gpointer) moo_tree_helper_row_down,
|
|
helper);
|
|
|
|
helper->widget = NULL;
|
|
}
|
|
|
|
GTK_OBJECT_CLASS (_moo_tree_helper_parent_class)->destroy (object);
|
|
}
|
|
|
|
|
|
static void
|
|
_moo_tree_helper_class_init (MooTreeHelperClass *klass)
|
|
{
|
|
GTK_OBJECT_CLASS(klass)->destroy = moo_tree_helper_destroy;
|
|
|
|
tree_signals[NEW_ROW] =
|
|
g_signal_new ("new-row",
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (MooTreeHelperClass, new_row),
|
|
g_signal_accumulator_true_handled, NULL,
|
|
_moo_marshal_BOOL__OBJECT_BOXED,
|
|
G_TYPE_BOOLEAN, 2,
|
|
GTK_TYPE_TREE_MODEL,
|
|
GTK_TYPE_TREE_PATH | G_SIGNAL_TYPE_STATIC_SCOPE);
|
|
|
|
tree_signals[DELETE_ROW] =
|
|
g_signal_new ("delete-row",
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (MooTreeHelperClass, delete_row),
|
|
g_signal_accumulator_true_handled, NULL,
|
|
_moo_marshal_BOOL__OBJECT_BOXED,
|
|
G_TYPE_BOOLEAN, 2,
|
|
GTK_TYPE_TREE_MODEL,
|
|
GTK_TYPE_TREE_PATH | G_SIGNAL_TYPE_STATIC_SCOPE);
|
|
|
|
tree_signals[MOVE_ROW] =
|
|
g_signal_new ("move-row",
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (MooTreeHelperClass, move_row),
|
|
g_signal_accumulator_true_handled, NULL,
|
|
_moo_marshal_BOOL__OBJECT_BOXED_BOXED,
|
|
G_TYPE_BOOLEAN, 3,
|
|
GTK_TYPE_TREE_MODEL,
|
|
GTK_TYPE_TREE_PATH | G_SIGNAL_TYPE_STATIC_SCOPE,
|
|
GTK_TYPE_TREE_PATH | G_SIGNAL_TYPE_STATIC_SCOPE);
|
|
|
|
tree_signals[UPDATE_WIDGETS] =
|
|
g_signal_new ("update-widgets",
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (MooTreeHelperClass, update_widgets),
|
|
NULL, NULL,
|
|
_moo_marshal_VOID__OBJECT_BOXED_BOXED,
|
|
G_TYPE_NONE, 3,
|
|
GTK_TYPE_TREE_MODEL,
|
|
GTK_TYPE_TREE_PATH | G_SIGNAL_TYPE_STATIC_SCOPE,
|
|
GTK_TYPE_TREE_ITER | G_SIGNAL_TYPE_STATIC_SCOPE);
|
|
|
|
tree_signals[UPDATE_MODEL] =
|
|
g_signal_new ("update-model",
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (MooTreeHelperClass, update_model),
|
|
NULL, NULL,
|
|
_moo_marshal_VOID__OBJECT_BOXED_BOXED,
|
|
G_TYPE_NONE, 3,
|
|
GTK_TYPE_TREE_MODEL,
|
|
GTK_TYPE_TREE_PATH | G_SIGNAL_TYPE_STATIC_SCOPE,
|
|
GTK_TYPE_TREE_ITER | G_SIGNAL_TYPE_STATIC_SCOPE);
|
|
}
|
|
|
|
|
|
void
|
|
moo_tree_view_select_first (GtkTreeView *tree_view)
|
|
{
|
|
GtkTreeSelection *selection;
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
|
|
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
|
|
|
|
selection = gtk_tree_view_get_selection (tree_view);
|
|
model = gtk_tree_view_get_model (tree_view);
|
|
|
|
if (gtk_tree_model_get_iter_first (model, &iter))
|
|
gtk_tree_selection_select_iter (selection, &iter);
|
|
}
|
|
|
|
|
|
void
|
|
moo_combo_box_select_first (GtkComboBox *combo)
|
|
{
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
|
|
g_return_if_fail (GTK_IS_COMBO_BOX (combo));
|
|
|
|
model = gtk_combo_box_get_model (combo);
|
|
|
|
if (gtk_tree_model_get_iter_first (model, &iter))
|
|
gtk_combo_box_set_active_iter (combo, &iter);
|
|
}
|
|
|
|
|
|
static void
|
|
moo_tree_helper_real_update_widgets (MooTreeHelper *helper,
|
|
GtkTreeModel *model,
|
|
GtkTreePath *path)
|
|
{
|
|
GtkTreeIter iter;
|
|
|
|
if (!path)
|
|
{
|
|
if (helper->delete_btn)
|
|
gtk_widget_set_sensitive (helper->delete_btn, FALSE);
|
|
if (helper->up_btn)
|
|
gtk_widget_set_sensitive (helper->up_btn, FALSE);
|
|
if (helper->down_btn)
|
|
gtk_widget_set_sensitive (helper->down_btn, FALSE);
|
|
}
|
|
else
|
|
{
|
|
int *indices;
|
|
int n_rows;
|
|
|
|
if (helper->delete_btn)
|
|
gtk_widget_set_sensitive (helper->delete_btn, TRUE);
|
|
|
|
indices = gtk_tree_path_get_indices (path);
|
|
|
|
if (helper->up_btn)
|
|
gtk_widget_set_sensitive (helper->up_btn, indices[0] != 0);
|
|
|
|
n_rows = gtk_tree_model_iter_n_children (model, NULL);
|
|
|
|
if (helper->down_btn)
|
|
gtk_widget_set_sensitive (helper->down_btn, indices[0] != n_rows - 1);
|
|
}
|
|
|
|
if (path)
|
|
gtk_tree_model_get_iter (model, &iter, path);
|
|
|
|
g_signal_emit (helper, tree_signals[UPDATE_WIDGETS], 0,
|
|
model, path, path ? &iter : NULL);
|
|
}
|
|
|
|
|
|
void
|
|
moo_tree_helper_update_model (MooTreeHelper *helper,
|
|
GtkTreeModel *model,
|
|
GtkTreePath *path)
|
|
{
|
|
GtkTreePath *freeme = NULL;
|
|
GtkTreeIter iter;
|
|
|
|
g_return_if_fail (MOO_IS_TREE_HELPER (helper));
|
|
g_return_if_fail (!model || GTK_IS_TREE_MODEL (model));
|
|
|
|
if (!model)
|
|
model = moo_tree_helper_get_model (helper);
|
|
|
|
if (!path && moo_tree_helper_get_selected (helper, NULL, &iter))
|
|
path = freeme = gtk_tree_model_get_path (model, &iter);
|
|
|
|
if (path)
|
|
{
|
|
gtk_tree_model_get_iter (model, &iter, path);
|
|
g_signal_emit (helper, tree_signals[UPDATE_MODEL], 0,
|
|
model, path, &iter);
|
|
}
|
|
|
|
gtk_tree_path_free (freeme);
|
|
}
|
|
|
|
|
|
static GtkTreeModel *
|
|
moo_tree_helper_get_model (MooTreeHelper *helper)
|
|
{
|
|
switch (helper->type)
|
|
{
|
|
case TREE_VIEW:
|
|
return gtk_tree_view_get_model (helper->widget);
|
|
case COMBO_BOX:
|
|
return gtk_combo_box_get_model (helper->widget);
|
|
}
|
|
|
|
g_return_val_if_reached (NULL);
|
|
}
|
|
|
|
|
|
static gboolean
|
|
moo_tree_helper_get_selected (MooTreeHelper *helper,
|
|
GtkTreeModel **model,
|
|
GtkTreeIter *iter)
|
|
{
|
|
GtkTreeSelection *selection;
|
|
|
|
switch (helper->type)
|
|
{
|
|
case TREE_VIEW:
|
|
selection = gtk_tree_view_get_selection (helper->widget);
|
|
return gtk_tree_selection_get_selected (selection, model, iter);
|
|
|
|
case COMBO_BOX:
|
|
if (model)
|
|
*model = gtk_combo_box_get_model (helper->widget);
|
|
return gtk_combo_box_get_active_iter (helper->widget, iter);
|
|
}
|
|
|
|
g_return_val_if_reached (FALSE);
|
|
}
|
|
|
|
|
|
static int
|
|
iter_get_index (GtkTreeModel *model,
|
|
GtkTreeIter *iter)
|
|
{
|
|
int index;
|
|
GtkTreePath *path;
|
|
|
|
path = gtk_tree_model_get_path (model, iter);
|
|
|
|
if (!path)
|
|
return -1;
|
|
|
|
index = gtk_tree_path_get_indices(path)[0];
|
|
|
|
gtk_tree_path_free (path);
|
|
return index;
|
|
}
|
|
|
|
|
|
static void
|
|
moo_tree_helper_new_row (MooTreeHelper *helper)
|
|
{
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
GtkTreeSelection *selection;
|
|
GtkTreePath *path;
|
|
int index;
|
|
gboolean result;
|
|
|
|
g_return_if_fail (helper->type == TREE_VIEW);
|
|
|
|
selection = gtk_tree_view_get_selection (helper->widget);
|
|
|
|
if (!gtk_tree_selection_get_selected (selection, &model, &iter))
|
|
index = gtk_tree_model_iter_n_children (model, NULL);
|
|
else
|
|
index = iter_get_index (model, &iter) + 1;
|
|
|
|
path = gtk_tree_path_new_from_indices (index, -1);
|
|
|
|
g_signal_emit (helper, tree_signals[NEW_ROW], 0, model, path, &result);
|
|
|
|
if (result && gtk_tree_model_get_iter (model, &iter, path))
|
|
gtk_tree_selection_select_iter (selection, &iter);
|
|
|
|
gtk_tree_path_free (path);
|
|
}
|
|
|
|
|
|
static void
|
|
moo_tree_helper_delete_row (MooTreeHelper *helper)
|
|
{
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
GtkTreeSelection *selection;
|
|
GtkTreePath *path;
|
|
gboolean result;
|
|
|
|
g_return_if_fail (helper->type == TREE_VIEW);
|
|
|
|
selection = gtk_tree_view_get_selection (helper->widget);
|
|
|
|
if (!gtk_tree_selection_get_selected (selection, &model, &iter))
|
|
g_return_if_reached ();
|
|
|
|
path = gtk_tree_model_get_path (model, &iter);
|
|
|
|
g_signal_emit (helper, tree_signals[DELETE_ROW], 0, model, path, &result);
|
|
|
|
if (result && (gtk_tree_model_get_iter (model, &iter, path) ||
|
|
(gtk_tree_path_prev (path) && gtk_tree_model_get_iter (model, &iter, path))))
|
|
gtk_tree_selection_select_iter (selection, &iter);
|
|
else
|
|
moo_tree_helper_update_widgets (helper);
|
|
|
|
gtk_tree_path_free (path);
|
|
}
|
|
|
|
|
|
static void
|
|
moo_tree_helper_row_move (MooTreeHelper *helper,
|
|
gboolean up)
|
|
{
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
GtkTreePath *path, *new_path;
|
|
GtkTreeSelection *selection;
|
|
gboolean result;
|
|
|
|
g_return_if_fail (helper->type == TREE_VIEW);
|
|
|
|
selection = gtk_tree_view_get_selection (helper->widget);
|
|
|
|
if (!gtk_tree_selection_get_selected (selection, &model, &iter))
|
|
g_return_if_reached ();
|
|
|
|
path = gtk_tree_model_get_path (model, &iter);
|
|
new_path = gtk_tree_path_copy (path);
|
|
|
|
if (up && !gtk_tree_path_prev (new_path))
|
|
g_return_if_reached ();
|
|
else if (!up)
|
|
gtk_tree_path_next (new_path);
|
|
|
|
g_signal_emit (helper, tree_signals[MOVE_ROW], 0, model, path, new_path, &result);
|
|
|
|
if (result)
|
|
moo_tree_helper_real_update_widgets (helper, model, new_path);
|
|
|
|
gtk_tree_path_free (new_path);
|
|
gtk_tree_path_free (path);
|
|
}
|
|
|
|
|
|
static void
|
|
moo_tree_helper_row_up (MooTreeHelper *helper)
|
|
{
|
|
moo_tree_helper_row_move (helper, TRUE);
|
|
}
|
|
|
|
|
|
static void
|
|
moo_tree_helper_row_down (MooTreeHelper *helper)
|
|
{
|
|
moo_tree_helper_row_move (helper, FALSE);
|
|
}
|
|
|
|
|
|
static void
|
|
_moo_tree_helper_init (G_GNUC_UNUSED MooTreeHelper *helper)
|
|
{
|
|
}
|
|
|
|
|
|
static void
|
|
moo_tree_helper_connect (MooTreeHelper *helper,
|
|
GtkWidget *widget,
|
|
GtkWidget *new_btn,
|
|
GtkWidget *delete_btn,
|
|
GtkWidget *up_btn,
|
|
GtkWidget *down_btn)
|
|
{
|
|
GtkTreeSelection *selection;
|
|
|
|
g_return_if_fail (MOO_IS_TREE_HELPER (helper));
|
|
g_return_if_fail (GTK_IS_TREE_VIEW (widget) || GTK_IS_COMBO_BOX (widget));
|
|
g_return_if_fail (helper->widget == NULL);
|
|
|
|
helper->widget = widget;
|
|
|
|
if (GTK_IS_TREE_VIEW (widget))
|
|
helper->type = TREE_VIEW;
|
|
else
|
|
helper->type = COMBO_BOX;
|
|
|
|
helper->new_btn = new_btn;
|
|
helper->delete_btn = delete_btn;
|
|
helper->up_btn = up_btn;
|
|
helper->down_btn = down_btn;
|
|
|
|
g_signal_connect_swapped (widget, "destroy",
|
|
G_CALLBACK (gtk_object_destroy),
|
|
helper);
|
|
|
|
switch (helper->type)
|
|
{
|
|
case TREE_VIEW:
|
|
selection = gtk_tree_view_get_selection (helper->widget);
|
|
g_signal_connect (selection, "changed",
|
|
G_CALLBACK (tree_selection_changed),
|
|
helper);
|
|
break;
|
|
|
|
case COMBO_BOX:
|
|
g_signal_connect (widget, "changed",
|
|
G_CALLBACK (combo_changed),
|
|
helper);
|
|
break;
|
|
}
|
|
|
|
if (new_btn)
|
|
g_signal_connect_swapped (new_btn, "clicked",
|
|
G_CALLBACK (moo_tree_helper_new_row),
|
|
helper);
|
|
if (delete_btn)
|
|
g_signal_connect_swapped (delete_btn, "clicked",
|
|
G_CALLBACK (moo_tree_helper_delete_row),
|
|
helper);
|
|
if (up_btn)
|
|
g_signal_connect_swapped (up_btn, "clicked",
|
|
G_CALLBACK (moo_tree_helper_row_up),
|
|
helper);
|
|
if (down_btn)
|
|
g_signal_connect_swapped (down_btn, "clicked",
|
|
G_CALLBACK (moo_tree_helper_row_down),
|
|
helper);
|
|
}
|
|
|
|
|
|
MooTreeHelper *
|
|
moo_tree_helper_new (GtkWidget *widget,
|
|
GtkWidget *new_btn,
|
|
GtkWidget *delete_btn,
|
|
GtkWidget *up_btn,
|
|
GtkWidget *down_btn)
|
|
{
|
|
MooTreeHelper *helper;
|
|
|
|
g_return_val_if_fail (GTK_IS_TREE_VIEW (widget) || GTK_IS_COMBO_BOX (widget), NULL);
|
|
|
|
helper = g_object_new (MOO_TYPE_TREE_HELPER, NULL);
|
|
gtk_object_sink (g_object_ref (helper));
|
|
|
|
moo_tree_helper_connect (helper, widget, new_btn, delete_btn, up_btn, down_btn);
|
|
|
|
return helper;
|
|
}
|
|
|
|
|
|
void
|
|
moo_tree_helper_update_widgets (MooTreeHelper *helper)
|
|
{
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
|
|
g_return_if_fail (MOO_IS_TREE_HELPER (helper));
|
|
|
|
if (moo_tree_helper_get_selected (helper, &model, &iter))
|
|
{
|
|
GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
|
|
moo_tree_helper_real_update_widgets (MOO_TREE_HELPER (helper), model, path);
|
|
gtk_tree_path_free (path);
|
|
}
|
|
else
|
|
{
|
|
moo_tree_helper_real_update_widgets (MOO_TREE_HELPER (helper), NULL, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* MooConfigHelper
|
|
*/
|
|
|
|
#define MOO_TYPE_CONFIG_HELPER (_moo_config_helper_get_type ())
|
|
#define MOO_CONFIG_HELPER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MOO_TYPE_CONFIG_HELPER, MooConfigHelper))
|
|
#define MOO_CONFIG_HELPER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOO_TYPE_CONFIG_HELPER, MooConfigHelperClass))
|
|
#define MOO_IS_CONFIG_HELPER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MOO_TYPE_CONFIG_HELPER))
|
|
#define MOO_IS_CONFIG_HELPER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOO_TYPE_CONFIG_HELPER))
|
|
#define MOO_CONFIG_HELPER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOO_TYPE_CONFIG_HELPER, MooConfigHelperClass))
|
|
|
|
|
|
enum {
|
|
NEW_ITEM,
|
|
SET_FROM_ITEM,
|
|
SET_FROM_WIDGETS,
|
|
CONFIG_NUM_SIGNALS
|
|
};
|
|
|
|
static guint config_signals[CONFIG_NUM_SIGNALS];
|
|
|
|
|
|
typedef void (*MooConfigItemToWidget) (MooConfig *config,
|
|
MooConfigItem *item,
|
|
GtkWidget *widget,
|
|
gpointer data);
|
|
typedef void (*MooConfigWidgetToItem) (GtkWidget *widget,
|
|
MooConfig *config,
|
|
MooConfigItem *item,
|
|
gpointer data);
|
|
|
|
|
|
typedef struct {
|
|
char *key;
|
|
gboolean update_live;
|
|
gulong handler;
|
|
MooConfigItemToWidget item_to_widget;
|
|
MooConfigWidgetToItem widget_to_item;
|
|
gpointer data;
|
|
} WidgetInfo;
|
|
|
|
struct _MooConfigHelper {
|
|
MooTreeHelper parent;
|
|
GSList *widgets;
|
|
};
|
|
|
|
GType _moo_config_helper_get_type (void) G_GNUC_CONST;
|
|
G_DEFINE_TYPE (MooConfigHelper, _moo_config_helper, MOO_TYPE_TREE_HELPER)
|
|
|
|
|
|
static WidgetInfo *
|
|
get_info (gpointer widget)
|
|
{
|
|
return g_object_get_data (G_OBJECT (widget), "moo-config-helper-widget-info");
|
|
}
|
|
|
|
|
|
static void
|
|
moo_config_helper_destroy (GtkObject *object)
|
|
{
|
|
MooConfigHelper *helper = MOO_CONFIG_HELPER (object);
|
|
|
|
if (helper->widgets)
|
|
{
|
|
GSList *l;
|
|
|
|
for (l = helper->widgets; l != NULL; l = l->next)
|
|
{
|
|
GtkWidget *widget = l->data;
|
|
WidgetInfo *info = get_info (widget);
|
|
|
|
if (info->handler)
|
|
g_signal_handler_disconnect (widget, info->handler);
|
|
|
|
g_object_set_data (G_OBJECT (widget), "moo-config-helper-widget-info", NULL);
|
|
}
|
|
|
|
g_slist_free (helper->widgets);
|
|
helper->widgets = NULL;
|
|
}
|
|
|
|
GTK_OBJECT_CLASS(_moo_config_helper_parent_class)->destroy (object);
|
|
}
|
|
|
|
|
|
static gboolean
|
|
moo_config_helper_new_row (MooTreeHelper *tree_helper,
|
|
GtkTreeModel *model,
|
|
GtkTreePath *path)
|
|
{
|
|
int index;
|
|
MooConfigItem *item;
|
|
MooConfigHelper *helper = MOO_CONFIG_HELPER (tree_helper);
|
|
|
|
g_return_val_if_fail (path != NULL, FALSE);
|
|
g_return_val_if_fail (gtk_tree_path_get_depth (path) == 1, FALSE);
|
|
|
|
index = gtk_tree_path_get_indices(path)[0];
|
|
item = moo_config_new_item (MOO_CONFIG (model), index, TRUE);
|
|
g_return_val_if_fail (item != NULL, FALSE);
|
|
|
|
g_signal_emit (helper, config_signals[NEW_ITEM], 0, model, item);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static gboolean
|
|
moo_config_helper_delete_row (G_GNUC_UNUSED MooTreeHelper *tree_helper,
|
|
GtkTreeModel *model,
|
|
GtkTreePath *path)
|
|
{
|
|
int index;
|
|
|
|
g_return_val_if_fail (path != NULL, FALSE);
|
|
g_return_val_if_fail (gtk_tree_path_get_depth (path) == 1, FALSE);
|
|
|
|
index = gtk_tree_path_get_indices(path)[0];
|
|
moo_config_delete_item (MOO_CONFIG (model), index, TRUE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static gboolean
|
|
moo_config_helper_move_row (G_GNUC_UNUSED MooTreeHelper *helper,
|
|
GtkTreeModel *model,
|
|
GtkTreePath *old_path,
|
|
GtkTreePath *new_path)
|
|
{
|
|
g_return_val_if_fail (old_path && new_path, FALSE);
|
|
g_return_val_if_fail (gtk_tree_path_get_depth (old_path) == 1, FALSE);
|
|
g_return_val_if_fail (gtk_tree_path_get_depth (new_path) == 1, FALSE);
|
|
moo_config_move_item (MOO_CONFIG (model),
|
|
gtk_tree_path_get_indices(old_path)[0],
|
|
gtk_tree_path_get_indices(new_path)[0],
|
|
TRUE);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static void
|
|
moo_config_helper_update_widgets_real (MooTreeHelper *tree_helper,
|
|
GtkTreeModel *model,
|
|
GtkTreePath *path,
|
|
GtkTreeIter *iter)
|
|
{
|
|
GSList *l;
|
|
MooConfigItem *item = NULL;
|
|
MooConfigHelper *helper = MOO_CONFIG_HELPER (tree_helper);
|
|
|
|
g_return_if_fail (MOO_IS_CONFIG (model));
|
|
|
|
if (path)
|
|
{
|
|
gtk_tree_model_get (model, iter, 0, &item, -1);
|
|
g_return_if_fail (item != NULL);
|
|
}
|
|
|
|
for (l = helper->widgets; l != NULL; l = l->next)
|
|
{
|
|
GtkWidget *widget;
|
|
WidgetInfo *info;
|
|
|
|
widget = l->data;
|
|
info = get_info (widget);
|
|
|
|
if (info->handler)
|
|
g_signal_handler_block (widget, info->handler);
|
|
|
|
gtk_widget_set_sensitive (widget, item != NULL);
|
|
|
|
if (item)
|
|
{
|
|
info->item_to_widget (MOO_CONFIG (model), item, widget, info->data);
|
|
}
|
|
else
|
|
{
|
|
if (GTK_IS_TOGGLE_BUTTON (widget))
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
|
|
else if (GTK_IS_ENTRY (widget))
|
|
gtk_entry_set_text (GTK_ENTRY (widget), "");
|
|
else
|
|
gtk_text_buffer_set_text (gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget)),
|
|
"", -1);
|
|
}
|
|
|
|
if (info->handler)
|
|
g_signal_handler_unblock (widget, info->handler);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
moo_config_helper_update_model_real (MooTreeHelper *tree_helper,
|
|
GtkTreeModel *model,
|
|
GtkTreePath *path,
|
|
GtkTreeIter *iter)
|
|
{
|
|
GSList *l;
|
|
MooConfigItem *item = NULL;
|
|
MooConfigHelper *helper = MOO_CONFIG_HELPER (tree_helper);
|
|
|
|
g_return_if_fail (MOO_IS_CONFIG (model));
|
|
g_return_if_fail (path != NULL);
|
|
|
|
gtk_tree_model_get (model, iter, 0, &item, -1);
|
|
|
|
if (!item)
|
|
return;
|
|
|
|
for (l = helper->widgets; l != NULL; l = l->next)
|
|
{
|
|
GtkWidget *widget;
|
|
WidgetInfo *info;
|
|
|
|
widget = l->data;
|
|
info = get_info (widget);
|
|
|
|
info->widget_to_item (widget, MOO_CONFIG (model), item, info->data);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
_moo_config_helper_class_init (MooConfigHelperClass *klass)
|
|
{
|
|
MooTreeHelperClass *tree_class = MOO_TREE_HELPER_CLASS (klass);
|
|
|
|
GTK_OBJECT_CLASS(klass)->destroy = moo_config_helper_destroy;
|
|
|
|
tree_class->new_row = moo_config_helper_new_row;
|
|
tree_class->delete_row = moo_config_helper_delete_row;
|
|
tree_class->move_row = moo_config_helper_move_row;
|
|
tree_class->update_widgets = moo_config_helper_update_widgets_real;
|
|
tree_class->update_model = moo_config_helper_update_model_real;
|
|
|
|
config_signals[NEW_ITEM] =
|
|
g_signal_new ("new-item",
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (MooConfigHelperClass, new_item),
|
|
NULL, NULL,
|
|
_moo_marshal_VOID__OBJECT_POINTER,
|
|
G_TYPE_NONE, 2,
|
|
MOO_TYPE_CONFIG,
|
|
MOO_TYPE_CONFIG_ITEM);
|
|
|
|
config_signals[SET_FROM_ITEM] =
|
|
g_signal_new ("set-from-item",
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (MooConfigHelperClass, set_from_item),
|
|
NULL, NULL,
|
|
_moo_marshal_VOID__OBJECT_POINTER,
|
|
G_TYPE_NONE, 2,
|
|
MOO_TYPE_CONFIG,
|
|
MOO_TYPE_CONFIG_ITEM);
|
|
|
|
config_signals[SET_FROM_WIDGETS] =
|
|
g_signal_new ("set-from-widgets",
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (MooConfigHelperClass, set_from_widgets),
|
|
NULL, NULL,
|
|
_moo_marshal_VOID__OBJECT_POINTER,
|
|
G_TYPE_NONE, 2,
|
|
MOO_TYPE_CONFIG,
|
|
MOO_TYPE_CONFIG_ITEM);
|
|
}
|
|
|
|
|
|
static void
|
|
_moo_config_helper_init (MooConfigHelper *helper)
|
|
{
|
|
helper->widgets = NULL;
|
|
}
|
|
|
|
|
|
MooConfigHelper *
|
|
moo_config_helper_new (GtkWidget *tree_view,
|
|
GtkWidget *new_btn,
|
|
GtkWidget *delete_btn,
|
|
GtkWidget *up_btn,
|
|
GtkWidget *down_btn)
|
|
{
|
|
MooConfigHelper *helper;
|
|
|
|
g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
|
|
|
|
helper = g_object_new (MOO_TYPE_CONFIG_HELPER, NULL);
|
|
gtk_object_sink (g_object_ref (helper));
|
|
|
|
moo_tree_helper_connect (MOO_TREE_HELPER (helper), tree_view,
|
|
new_btn, delete_btn, up_btn, down_btn);
|
|
|
|
return helper;
|
|
}
|
|
|
|
|
|
static void
|
|
button_toggled (MooTreeHelper *helper,
|
|
GtkToggleButton *button)
|
|
{
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
MooConfigItem *item = NULL;
|
|
WidgetInfo *info;
|
|
GtkTreeSelection *selection;
|
|
|
|
selection = gtk_tree_view_get_selection (helper->widget);
|
|
|
|
if (!gtk_tree_selection_get_selected (selection, &model, &iter))
|
|
return;
|
|
|
|
info = get_info (button);
|
|
g_return_if_fail (info != NULL);
|
|
|
|
gtk_tree_model_get (model, &iter, 0, &item, -1);
|
|
g_return_if_fail (item != NULL);
|
|
|
|
moo_config_set_bool (MOO_CONFIG (model), item, info->key,
|
|
gtk_toggle_button_get_active (button), TRUE);
|
|
}
|
|
|
|
|
|
static void
|
|
entry_changed (MooTreeHelper *helper,
|
|
GtkEntry *entry)
|
|
{
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
const char *text;
|
|
MooConfigItem *item = NULL;
|
|
WidgetInfo *info;
|
|
GtkTreeSelection *selection;
|
|
|
|
selection = gtk_tree_view_get_selection (helper->widget);
|
|
|
|
if (!gtk_tree_selection_get_selected (selection, &model, &iter))
|
|
return;
|
|
|
|
info = get_info (entry);
|
|
g_return_if_fail (info != NULL);
|
|
|
|
text = gtk_entry_get_text (entry);
|
|
gtk_tree_model_get (model, &iter, 0, &item, -1);
|
|
g_return_if_fail (item != NULL);
|
|
|
|
if (info->key)
|
|
moo_config_set (MOO_CONFIG (model), item,
|
|
info->key, text, TRUE);
|
|
else
|
|
moo_config_set_item_content (MOO_CONFIG (model), item,
|
|
text, TRUE);
|
|
}
|
|
|
|
|
|
static void
|
|
toggle_button_to_item (GtkToggleButton *button,
|
|
MooConfig *config,
|
|
MooConfigItem *item)
|
|
{
|
|
gboolean value;
|
|
WidgetInfo *info = get_info (button);
|
|
|
|
g_return_if_fail (info != NULL);
|
|
|
|
value = gtk_toggle_button_get_active (button);
|
|
moo_config_set_bool (config, item, info->key, value, TRUE);
|
|
}
|
|
|
|
static void
|
|
entry_to_item (GtkEntry *entry,
|
|
MooConfig *config,
|
|
MooConfigItem *item)
|
|
{
|
|
const char *text;
|
|
WidgetInfo *info = get_info (entry);
|
|
|
|
g_return_if_fail (info != NULL);
|
|
|
|
text = gtk_entry_get_text (entry);
|
|
|
|
if (info->key)
|
|
moo_config_set (config, item, info->key, text, TRUE);
|
|
else
|
|
moo_config_set_item_content (config, item, text, TRUE);
|
|
}
|
|
|
|
static void
|
|
text_view_to_item (GtkTextView *view,
|
|
MooConfig *config,
|
|
MooConfigItem *item)
|
|
{
|
|
char *text;
|
|
GtkTextBuffer *buffer;
|
|
GtkTextIter start, end;
|
|
WidgetInfo *info = get_info (view);
|
|
|
|
g_return_if_fail (info != NULL);
|
|
|
|
buffer = gtk_text_view_get_buffer (view);
|
|
gtk_text_buffer_get_bounds (buffer, &start, &end);
|
|
text = gtk_text_buffer_get_slice (buffer, &start, &end, TRUE);
|
|
|
|
if (!text[0])
|
|
{
|
|
g_free (text);
|
|
text = NULL;
|
|
}
|
|
|
|
if (info->key)
|
|
moo_config_set (config, item, info->key, text, TRUE);
|
|
else
|
|
moo_config_set_item_content (config, item, text, TRUE);
|
|
|
|
g_free (text);
|
|
}
|
|
|
|
static MooConfigWidgetToItem
|
|
get_widget_to_item_func (GtkWidget *widget)
|
|
{
|
|
if (GTK_IS_TOGGLE_BUTTON (widget))
|
|
return (MooConfigWidgetToItem) toggle_button_to_item;
|
|
else if (GTK_IS_ENTRY (widget))
|
|
return (MooConfigWidgetToItem) entry_to_item;
|
|
else if (GTK_IS_TEXT_VIEW (widget))
|
|
return (MooConfigWidgetToItem) text_view_to_item;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
|
|
static void
|
|
item_to_toggle_button (MooConfig *config,
|
|
MooConfigItem *item,
|
|
GtkToggleButton *button)
|
|
{
|
|
gboolean value;
|
|
WidgetInfo *info = get_info (button);
|
|
|
|
g_return_if_fail (info != NULL);
|
|
|
|
value = moo_config_get_bool (config, item, info->key);
|
|
gtk_toggle_button_set_active (button, value);
|
|
}
|
|
|
|
static void
|
|
item_to_entry (G_GNUC_UNUSED MooConfig *config,
|
|
MooConfigItem *item,
|
|
GtkEntry *entry)
|
|
{
|
|
const char *text;
|
|
WidgetInfo *info = get_info (entry);
|
|
|
|
g_return_if_fail (info != NULL);
|
|
|
|
if (info->key)
|
|
text = moo_config_item_get (item, info->key);
|
|
else
|
|
text = moo_config_item_get_content (item);
|
|
|
|
gtk_entry_set_text (entry, text ? text : "");
|
|
}
|
|
|
|
static void
|
|
item_to_text_view (G_GNUC_UNUSED MooConfig *config,
|
|
MooConfigItem *item,
|
|
GtkTextView *view)
|
|
{
|
|
const char *text;
|
|
GtkTextBuffer *buffer;
|
|
WidgetInfo *info = get_info (view);
|
|
|
|
g_return_if_fail (info != NULL);
|
|
|
|
if (info->key)
|
|
text = moo_config_item_get (item, info->key);
|
|
else
|
|
text = moo_config_item_get_content (item);
|
|
|
|
buffer = gtk_text_view_get_buffer (view);
|
|
gtk_text_buffer_set_text (buffer, text ? text : "", -1);
|
|
}
|
|
|
|
static MooConfigItemToWidget
|
|
get_item_to_widget_func (GtkWidget *widget)
|
|
{
|
|
if (GTK_IS_TOGGLE_BUTTON (widget))
|
|
return (MooConfigItemToWidget) item_to_toggle_button;
|
|
else if (GTK_IS_ENTRY (widget))
|
|
return (MooConfigItemToWidget) item_to_entry;
|
|
else if (GTK_IS_TEXT_VIEW (widget))
|
|
return (MooConfigItemToWidget) item_to_text_view;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
|
|
static WidgetInfo *
|
|
widget_info_new (const char *key,
|
|
gboolean update_live)
|
|
{
|
|
WidgetInfo *info = g_new0 (WidgetInfo, 1);
|
|
|
|
info->key = g_strdup (key);
|
|
info->update_live = update_live;
|
|
|
|
return info;
|
|
}
|
|
|
|
|
|
static void
|
|
widget_info_free (WidgetInfo *info)
|
|
{
|
|
if (info)
|
|
{
|
|
g_free (info->key);
|
|
g_free (info);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
moo_config_helper_add_widget_full (MooConfigHelper *helper,
|
|
GtkWidget *widget,
|
|
const char *key,
|
|
MooConfigWidgetToItem widget_to_item_func,
|
|
MooConfigItemToWidget item_to_widget_func,
|
|
gpointer data,
|
|
gboolean update_live)
|
|
{
|
|
WidgetInfo *info;
|
|
|
|
g_return_if_fail (!update_live || key != NULL);
|
|
|
|
g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget) ||
|
|
GTK_IS_ENTRY (widget) || GTK_IS_TEXT_VIEW (widget));
|
|
|
|
if (!widget_to_item_func)
|
|
{
|
|
widget_to_item_func = get_widget_to_item_func (widget);
|
|
g_return_if_fail (widget_to_item_func != NULL);
|
|
}
|
|
|
|
if (!item_to_widget_func)
|
|
{
|
|
item_to_widget_func = get_item_to_widget_func (widget);
|
|
g_return_if_fail (item_to_widget_func != NULL);
|
|
}
|
|
|
|
info = widget_info_new (key, update_live);
|
|
info->widget_to_item = widget_to_item_func;
|
|
info->item_to_widget = item_to_widget_func;
|
|
info->data = data;
|
|
|
|
helper->widgets = g_slist_prepend (helper->widgets, widget);
|
|
g_object_set_data_full (G_OBJECT (widget), "moo-config-helper-widget-info", info,
|
|
(GDestroyNotify) widget_info_free);
|
|
|
|
if (update_live)
|
|
{
|
|
if (GTK_IS_TOGGLE_BUTTON (widget))
|
|
info->handler =
|
|
g_signal_connect_swapped (widget, "toggled",
|
|
G_CALLBACK (button_toggled),
|
|
helper);
|
|
else if (GTK_IS_ENTRY (widget))
|
|
info->handler =
|
|
g_signal_connect_swapped (widget, "changed",
|
|
G_CALLBACK (entry_changed),
|
|
helper);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
moo_config_helper_add_widget (MooConfigHelper *helper,
|
|
GtkWidget *widget,
|
|
const char *key,
|
|
gboolean update_live)
|
|
{
|
|
g_return_if_fail (MOO_IS_CONFIG_HELPER (helper));
|
|
g_return_if_fail (GTK_IS_WIDGET (widget));
|
|
moo_config_helper_add_widget_full (helper, widget, key,
|
|
NULL, NULL, NULL,
|
|
update_live);
|
|
}
|
|
|
|
|
|
void
|
|
moo_config_helper_update_model (MooConfigHelper *helper,
|
|
GtkTreeModel *model,
|
|
GtkTreePath *path)
|
|
{
|
|
g_return_if_fail (MOO_IS_CONFIG_HELPER (helper));
|
|
moo_tree_helper_update_model (MOO_TREE_HELPER (helper), model, path);
|
|
}
|