Put all of the UI utility functions into the "git" namespace.
[anjuta-git-plugin.git] / plugins / class-gen / element-editor.c
bloba725d748e0b7bcaf2e8f01ecab636a783b12d841
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /* element-editor.c
3 * Copyright (C) 2006 Armin Burgmeier
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 #include "element-editor.h"
21 #include "cell-renderer-flags.h"
23 #include <gtk/gtktreeselection.h>
24 #include <gtk/gtkcellrenderercombo.h>
25 #include <gtk/gtkcellrenderertext.h>
26 #include <gtk/gtkcellrenderer.h>
27 #include <gtk/gtkliststore.h>
28 #include <gtk/gtkentry.h>
30 typedef struct _CgElementEditorColumn CgElementEditorColumn;
31 struct _CgElementEditorColumn
33 CgElementEditor *parent;
34 CgElementEditorColumnType type;
35 GtkTreeViewColumn *column;
36 GtkCellRenderer *renderer;
39 typedef struct _CgElementEditorReference CgElementEditorReference;
40 struct _CgElementEditorReference
42 CgElementEditorColumn *column;
43 gchar *path_str;
46 typedef struct _CgElementEditorPrivate CgElementEditorPrivate;
47 struct _CgElementEditorPrivate
49 GtkTreeView *view;
50 GtkTreeModel *list;
52 guint n_columns;
53 CgElementEditorColumn *columns;
55 GtkButton *add_button;
56 GtkButton *remove_button;
59 #define CG_ELEMENT_EDITOR_PRIVATE(o) \
60 (G_TYPE_INSTANCE_GET_PRIVATE( \
61 (o), \
62 CG_TYPE_ELEMENT_EDITOR, \
63 CgElementEditorPrivate \
66 enum {
67 PROP_0,
69 /* Construct only */
70 PROP_TREEVIEW
73 static GObjectClass *parent_class = NULL;
75 static CgElementEditorReference *
76 cg_element_editor_reference_new (CgElementEditorColumn *column,
77 const gchar *path_str)
79 CgElementEditorReference *ref;
80 ref = g_new (CgElementEditorReference, 1);
82 ref->column = column;
83 ref->path_str = g_strdup (path_str);
85 return ref;
88 static void
89 cg_element_editor_reference_free (CgElementEditorReference *ref)
91 g_free (ref->path_str);
92 g_free (ref);
95 static void
96 cg_element_editor_select (CgElementEditor *editor,
97 GtkTreePath *path,
98 guint column)
100 CgElementEditorPrivate *priv;
101 priv = CG_ELEMENT_EDITOR_PRIVATE (editor);
103 if (column < priv->n_columns)
105 gtk_widget_grab_focus (GTK_WIDGET (priv->view));
108 gtk_tree_view_scroll_to_cell (priv->view, path,
109 priv->columns[column].column, FALSE,
110 0.0, 0.0);
112 gtk_tree_view_set_cursor_on_cell (priv->view, path,
113 priv->columns[column].column,
114 priv->columns[column].renderer,
115 TRUE);
119 static gboolean
120 cg_element_editor_edited_idle_cb (gpointer user_data)
122 CgElementEditorReference *ref;
123 CgElementEditorPrivate *priv;
124 GtkTreePath *path;
126 ref = (CgElementEditorReference *) user_data;
127 priv = CG_ELEMENT_EDITOR_PRIVATE (ref->column->parent);
129 path = gtk_tree_path_new_from_string (ref->path_str);
131 cg_element_editor_select (ref->column->parent, path,
132 ref->column - priv->columns);
134 gtk_tree_path_free (path);
135 return FALSE;
138 static void
139 cg_element_editor_row_inserted_cb (G_GNUC_UNUSED GtkTreeModel *model,
140 GtkTreePath *path,
141 G_GNUC_UNUSED GtkTreeIter *iter,
142 gpointer user_data)
144 CgElementEditor *editor;
145 CgElementEditorPrivate *priv;
146 CgElementEditorReference* ref;
147 gchar* path_str;
149 editor = CG_ELEMENT_EDITOR (user_data);
150 priv = CG_ELEMENT_EDITOR_PRIVATE (editor);
152 path_str = gtk_tree_path_to_string(path);
153 ref = cg_element_editor_reference_new (&priv->columns[0], path_str);
154 g_free(path_str);
156 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
157 cg_element_editor_edited_idle_cb, ref,
158 (GDestroyNotify) cg_element_editor_reference_free);
161 static void
162 cg_element_editor_list_edited_cb (G_GNUC_UNUSED GtkCellRendererText *renderer,
163 const gchar *path_str,
164 const gchar *text,
165 gpointer user_data)
167 CgElementEditorReference *new_ref;
168 CgElementEditorColumn* column;
169 CgElementEditorPrivate *priv;
170 GtkTreePath *path;
171 GtkTreeIter iter;
173 column = (CgElementEditorColumn *) user_data;
174 priv = CG_ELEMENT_EDITOR_PRIVATE (column->parent);
176 path = gtk_tree_path_new_from_string (path_str);
177 gtk_tree_model_get_iter (priv->list, &iter, path);
179 gtk_list_store_set (GTK_LIST_STORE (priv->list), &iter,
180 column - priv->columns, text, -1);
181 gtk_tree_path_free (path);
183 if(column - priv->columns + 1 < priv->n_columns)
185 /* We do not immediately select the new column because if this entry
186 * caused the column to be resized we first want to get the resize done.
187 * Otherwise, the next editing widget would appear at the old position
188 * of the next column (before the resize of this one). */
189 new_ref = cg_element_editor_reference_new (column + 1, path_str);
190 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
191 cg_element_editor_edited_idle_cb, new_ref,
192 (GDestroyNotify) cg_element_editor_reference_free);
196 static void
197 cg_element_editor_string_edited_cb (G_GNUC_UNUSED GtkCellRendererText
198 *renderer,
199 const gchar *path_str,
200 const gchar *text,
201 gpointer user_data)
203 CgElementEditorColumn *column;
204 CgElementEditorPrivate *priv;
205 GtkTreePath *path;
206 GtkTreeIter iter;
208 column = (CgElementEditorColumn *) user_data;
209 priv = CG_ELEMENT_EDITOR_PRIVATE (column->parent);
211 path = gtk_tree_path_new_from_string (path_str);
212 gtk_tree_model_get_iter (priv->list, &iter, path);
213 gtk_tree_path_free (path);
215 gtk_list_store_set(GTK_LIST_STORE(priv->list), &iter,
216 column - priv->columns, text, -1);
219 static void
220 cg_element_editor_string_activate_cb (G_GNUC_UNUSED GtkEntry *entry,
221 gpointer user_data)
223 CgElementEditorPrivate* priv;
224 CgElementEditorReference *ref;
225 CgElementEditorReference *new_ref;
227 ref = (CgElementEditorReference *) user_data;
228 priv = CG_ELEMENT_EDITOR_PRIVATE(ref->column->parent);
230 /* We do not immediately select the new column because if this entry
231 * caused the column to be resized we first want to get the resize done.
232 * Otherwise, the next editing widget would appear at the old position
233 * of the next column (before the resize of this one). */
234 if(ref->column - priv->columns + 1 < priv->n_columns)
236 new_ref = cg_element_editor_reference_new (ref->column + 1,
237 ref->path_str);
239 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
240 cg_element_editor_edited_idle_cb, new_ref,
241 (GDestroyNotify) cg_element_editor_reference_free);
245 static void
246 cg_element_editor_string_editing_started_cb (G_GNUC_UNUSED
247 GtkCellRenderer *renderer,
248 GtkCellEditable *editable,
249 const gchar *path_str,
250 gpointer user_data)
252 if (GTK_IS_ENTRY (editable))
254 g_signal_connect_data (G_OBJECT (editable), "activate",
255 G_CALLBACK (cg_element_editor_string_activate_cb),
256 cg_element_editor_reference_new (user_data, path_str),
257 (GClosureNotify) cg_element_editor_reference_free,
258 G_CONNECT_AFTER);
262 static void
263 cg_element_editor_arguments_editing_started_cb (G_GNUC_UNUSED
264 GtkCellRenderer *renderer,
265 GtkCellEditable *editable,
266 const gchar *path_str,
267 gpointer user_data)
269 const gchar *text;
271 if (GTK_IS_ENTRY (editable))
273 text = gtk_entry_get_text (GTK_ENTRY (editable));
274 if (text == NULL || *text == '\0')
276 gtk_entry_set_text (GTK_ENTRY (editable), "()");
278 /* TODO: This does not work, although we are connected with
279 * G_CONNECT_AFTER... */
280 gtk_editable_set_position (GTK_EDITABLE (editable), 1);
283 /* cg_element_editor_argumens_activate_cb would to exactly the same
284 * as cg_element_editor_string_activate_cb, so there is no
285 * extra function. */
286 g_signal_connect_data (G_OBJECT (editable), "activate",
287 G_CALLBACK (cg_element_editor_string_activate_cb),
288 cg_element_editor_reference_new (user_data, path_str),
289 (GClosureNotify) cg_element_editor_reference_free,
290 G_CONNECT_AFTER);
294 static void
295 cg_element_editor_add_button_clicked_cb (G_GNUC_UNUSED GtkButton *button,
296 gpointer user_data)
298 CgElementEditor *editor;
299 CgElementEditorPrivate *priv;
300 GtkTreeIter iter;
302 editor = CG_ELEMENT_EDITOR (user_data);
303 priv = CG_ELEMENT_EDITOR_PRIVATE (editor);
305 gtk_list_store_append (GTK_LIST_STORE (priv->list), &iter);
308 static void
309 cg_element_editor_remove_button_clicked_cb (G_GNUC_UNUSED GtkButton *button,
310 gpointer user_data)
312 CgElementEditor *editor;
313 CgElementEditorPrivate *priv;
314 GtkTreeSelection *selection;
315 GtkTreeIter *iter;
316 GtkTreePath *path;
317 GList *selected_rows;
318 GList *selected_iters;
319 GList *cur_item;
321 editor = CG_ELEMENT_EDITOR (user_data);
322 priv = CG_ELEMENT_EDITOR_PRIVATE (editor);
323 selection = gtk_tree_view_get_selection (priv->view);
324 selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
325 selected_iters = NULL;
327 /* Convert paths to iters because changing the model borks offsets
328 * in paths, but since GtkListStore has GTK_TREE_MODEL_PERSIST set,
329 * iters continue to live after changing the model. */
330 for (cur_item = selected_rows; cur_item != NULL; cur_item = cur_item->next)
332 path = cur_item->data;
333 iter = g_new (GtkTreeIter, 1);
335 gtk_tree_model_get_iter (priv->list, iter, path);
336 selected_iters = g_list_prepend (selected_iters, iter);
338 gtk_tree_path_free (path);
341 for (cur_item = selected_iters;
342 cur_item != NULL;
343 cur_item = cur_item->next)
345 iter = cur_item->data;
346 gtk_list_store_remove (GTK_LIST_STORE (priv->list), iter);
347 g_free (iter);
350 g_list_free (selected_rows);
351 g_list_free (selected_iters);
354 static void
355 cg_element_editor_selection_changed_cb (GtkTreeSelection *selection,
356 gpointer user_data)
358 CgElementEditor *editor;
359 CgElementEditorPrivate *priv;
361 editor = CG_ELEMENT_EDITOR (user_data);
362 priv = CG_ELEMENT_EDITOR_PRIVATE (editor);
364 if (gtk_tree_selection_count_selected_rows (selection) > 0)
365 gtk_widget_set_sensitive (GTK_WIDGET (priv->remove_button), TRUE);
366 else
367 gtk_widget_set_sensitive (GTK_WIDGET (priv->remove_button), FALSE);
370 static void
371 cg_element_editor_init (CgElementEditor *element_editor)
373 CgElementEditorPrivate *priv;
374 priv = CG_ELEMENT_EDITOR_PRIVATE (element_editor);
376 priv->view = NULL;
377 priv->list = NULL;
378 priv->n_columns = 0;
379 priv->columns = NULL;
382 static void
383 cg_element_editor_finalize (GObject *object)
385 CgElementEditor *element_editor;
386 CgElementEditorPrivate *priv;
388 element_editor = CG_ELEMENT_EDITOR (object);
389 priv = CG_ELEMENT_EDITOR_PRIVATE (element_editor);
391 g_free (priv->columns);
392 if (priv->list != NULL)
393 g_object_unref (G_OBJECT (priv->list));
395 G_OBJECT_CLASS (parent_class)->finalize (object);
398 static void
399 cg_element_editor_set_property (GObject *object,
400 guint prop_id,
401 const GValue *value,
402 GParamSpec *pspec)
404 CgElementEditor *element_editor;
405 CgElementEditorPrivate *priv;
407 g_return_if_fail (CG_IS_ELEMENT_EDITOR (object));
409 element_editor = CG_ELEMENT_EDITOR (object);
410 priv = CG_ELEMENT_EDITOR_PRIVATE (element_editor);
412 switch (prop_id)
414 case PROP_TREEVIEW:
415 priv->view = g_value_get_object (value);
416 break;
417 default:
418 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
419 break;
423 static void
424 cg_element_editor_get_property (GObject *object,
425 guint prop_id,
426 GValue *value,
427 GParamSpec *pspec)
429 CgElementEditor *element_editor;
430 CgElementEditorPrivate *priv;
432 g_return_if_fail (CG_IS_ELEMENT_EDITOR (object));
434 element_editor = CG_ELEMENT_EDITOR (object);
435 priv = CG_ELEMENT_EDITOR_PRIVATE (element_editor);
437 switch (prop_id)
439 case PROP_TREEVIEW:
440 g_value_set_object (value, G_OBJECT (priv->view));
441 break;
442 default:
443 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
444 break;
448 static void
449 cg_element_editor_class_init(CgElementEditorClass *klass)
451 GObjectClass* object_class = G_OBJECT_CLASS (klass);
452 parent_class = g_type_class_peek_parent (klass);
454 g_type_class_add_private (klass, sizeof (CgElementEditorPrivate));
456 object_class->finalize = cg_element_editor_finalize;
457 object_class->set_property = cg_element_editor_set_property;
458 object_class->get_property = cg_element_editor_get_property;
460 g_object_class_install_property(object_class,
461 PROP_TREEVIEW,
462 g_param_spec_object("tree-view",
463 "Tree view",
464 "Tree view the element editor works on",
465 GTK_TYPE_TREE_VIEW,
466 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
469 GType
470 cg_element_editor_get_type (void)
472 static GType our_type = 0;
474 if (our_type == 0)
476 static const GTypeInfo our_info =
478 sizeof (CgElementEditorClass),
479 (GBaseInitFunc) NULL,
480 (GBaseFinalizeFunc) NULL,
481 (GClassInitFunc) cg_element_editor_class_init,
482 NULL,
483 NULL,
484 sizeof (CgElementEditor),
486 (GInstanceInitFunc) cg_element_editor_init,
487 NULL
490 our_type = g_type_register_static (G_TYPE_OBJECT, "CgElementEditor",
491 &our_info, 0);
494 return our_type;
497 static void
498 cg_element_editor_init_list_renderer(CgElementEditorColumn *column,
499 GType *type,
500 va_list *arglist)
502 GtkTreeModel *combo_list;
503 const gchar **items;
504 GtkTreeIter iter;
506 *type = G_TYPE_STRING;
508 column->renderer = gtk_cell_renderer_combo_new ();
509 combo_list = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
511 for (items = va_arg (*arglist, const gchar **);
512 *items != NULL;
513 ++ items)
515 gtk_list_store_append (GTK_LIST_STORE (combo_list), &iter);
516 gtk_list_store_set (GTK_LIST_STORE (combo_list), &iter, 0, *items, -1);
519 g_object_set(column->renderer, "model", combo_list, "text-column", 0,
520 "editable", TRUE, "has-entry", FALSE, NULL);
522 g_signal_connect (G_OBJECT (column->renderer), "edited",
523 G_CALLBACK (cg_element_editor_list_edited_cb), column);
525 g_object_unref (G_OBJECT (combo_list));
528 static void
529 cg_element_editor_init_flags_renderer (CgElementEditorColumn *column,
530 GType *type,
531 va_list *arglist)
533 GtkTreeModel *combo_list;
534 const CgElementEditorFlags *items;
535 GtkTreeIter iter;
537 *type = G_TYPE_STRING;
539 column->renderer = cg_cell_renderer_flags_new ();
540 combo_list = GTK_TREE_MODEL (gtk_list_store_new (2, G_TYPE_STRING,
541 G_TYPE_STRING));
543 for (items = va_arg (*arglist, const CgElementEditorFlags *);
544 items->name != NULL;
545 ++ items)
547 gtk_list_store_append (GTK_LIST_STORE (combo_list), &iter);
548 gtk_list_store_set (GTK_LIST_STORE (combo_list), &iter,
549 0, items->name, 1, items->abbrevation, -1);
552 g_object_set (column->renderer, "model", combo_list, "text-column", 0,
553 "abbrevation_column", 1, "editable", TRUE, NULL);
555 g_signal_connect (G_OBJECT (column->renderer), "edited",
556 G_CALLBACK (cg_element_editor_list_edited_cb), column);
558 g_object_unref (G_OBJECT (combo_list));
561 static void
562 cg_element_editor_init_string_renderer (CgElementEditorColumn *column,
563 GType *type,
564 G_GNUC_UNUSED va_list *arglist)
566 *type = G_TYPE_STRING;
567 column->renderer = gtk_cell_renderer_text_new ();
569 g_object_set (G_OBJECT (column->renderer), "editable", TRUE, NULL);
571 /* We intentionally do not only connect to the "edited" signal here
572 * because this one is also fired when the user types something in and
573 * then clicks somewhere else. In such a situation, s/he wants to continue
574 * editing somewhere else, but we would start editing the next column
575 * which seems wrong.
577 * The "edited" signal handler does only store the new text whereas the
578 * "editing-started" signal handler connects to the "activate" signal of
579 * the resulting entry. This way, pressing enter to terminate the editing
580 * goes on to the next column, but other ways to terminate the input
581 * process do not. */
582 g_signal_connect_after (G_OBJECT (column->renderer), "edited",
583 G_CALLBACK (cg_element_editor_string_edited_cb),
584 column);
586 g_signal_connect_after (G_OBJECT (column->renderer), "editing-started",
587 G_CALLBACK(cg_element_editor_string_editing_started_cb), column);
590 static void
591 cg_element_editor_init_arguments_renderer (CgElementEditorColumn *column,
592 GType *type,
593 G_GNUC_UNUSED va_list *arglist)
595 *type = G_TYPE_STRING;
596 column->renderer = gtk_cell_renderer_text_new ();
598 g_object_set (G_OBJECT (column->renderer), "editable", TRUE, NULL);
600 /* Same as above */
601 g_signal_connect_after (G_OBJECT (column->renderer), "edited",
602 G_CALLBACK (cg_element_editor_string_edited_cb),
603 column);
605 g_signal_connect_after (G_OBJECT (column->renderer), "editing-started",
606 G_CALLBACK(cg_element_editor_arguments_editing_started_cb), column);
609 CgElementEditor *
610 cg_element_editor_new (GtkTreeView *view,
611 GtkButton *add_button,
612 GtkButton *remove_button,
613 guint n_columns,
614 ...)
616 CgElementEditor *editor;
617 CgElementEditorPrivate *priv;
618 CgElementEditorColumnType column;
619 GtkTreeSelection *selection;
620 const gchar *title;
621 GType *types;
622 va_list arglist;
623 guint i;
625 editor = CG_ELEMENT_EDITOR (g_object_new (CG_TYPE_ELEMENT_EDITOR,
626 "tree-view", view, NULL));
628 priv = CG_ELEMENT_EDITOR_PRIVATE (editor);
630 types = g_malloc (sizeof (GType) * n_columns);
631 priv->n_columns = n_columns;
632 priv->columns = g_malloc (sizeof (CgElementEditorColumn) * n_columns);
634 va_start (arglist, n_columns);
635 for (i = 0; i < n_columns; ++ i)
637 priv->columns[i].parent = editor;
639 title = va_arg (arglist, const gchar *);
640 column = va_arg (arglist, CgElementEditorColumnType);
641 priv->columns[i].type = column;
643 priv->columns[i].column = gtk_tree_view_column_new ();
644 gtk_tree_view_column_set_title (priv->columns[i].column, title);
646 switch (column)
648 case CG_ELEMENT_EDITOR_COLUMN_LIST:
649 cg_element_editor_init_list_renderer (&priv->columns[i],
650 &types[i], &arglist);
651 break;
652 case CG_ELEMENT_EDITOR_COLUMN_FLAGS:
653 cg_element_editor_init_flags_renderer (&priv->columns[i],
654 &types[i], &arglist);
655 break;
656 case CG_ELEMENT_EDITOR_COLUMN_STRING:
657 cg_element_editor_init_string_renderer (&priv->columns[i],
658 &types[i], &arglist);
659 break;
660 case CG_ELEMENT_EDITOR_COLUMN_ARGUMENTS:
661 cg_element_editor_init_arguments_renderer (&priv->columns[i],
662 &types[i], &arglist);
663 break;
664 default:
665 g_assert_not_reached ();
666 break;
669 gtk_tree_view_column_pack_start (priv->columns[i].column,
670 priv->columns[i].renderer, TRUE);
672 gtk_tree_view_append_column (view, priv->columns[i].column);
674 va_end (arglist);
676 priv->list = GTK_TREE_MODEL (gtk_list_store_newv (n_columns, types));
677 g_free (types);
679 /* Second pass, associate attributes */
680 for (i = 0; i < n_columns; ++ i)
682 switch (priv->columns[i].type)
684 case CG_ELEMENT_EDITOR_COLUMN_LIST:
685 case CG_ELEMENT_EDITOR_COLUMN_FLAGS:
686 case CG_ELEMENT_EDITOR_COLUMN_STRING:
687 case CG_ELEMENT_EDITOR_COLUMN_ARGUMENTS:
688 gtk_tree_view_column_add_attribute (priv->columns[i].column,
689 priv->columns[i].renderer,
690 "text", i);
692 break;
693 default:
694 g_assert_not_reached ();
695 break;
699 g_signal_connect_after (G_OBJECT (priv->list), "row-inserted",
700 G_CALLBACK (cg_element_editor_row_inserted_cb),
701 editor);
703 priv->add_button = add_button;
704 priv->remove_button = remove_button;
706 if(priv->add_button != NULL)
708 g_signal_connect (G_OBJECT(priv->add_button), "clicked",
709 G_CALLBACK (cg_element_editor_add_button_clicked_cb),
710 editor);
713 if(priv->remove_button != NULL)
715 g_signal_connect (G_OBJECT (priv->remove_button), "clicked",
716 G_CALLBACK (cg_element_editor_remove_button_clicked_cb), editor);
719 selection = gtk_tree_view_get_selection (view);
720 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
722 if(priv->remove_button != NULL)
724 g_signal_connect(G_OBJECT (selection), "changed",
725 G_CALLBACK (cg_element_editor_selection_changed_cb),
726 editor);
729 gtk_tree_view_set_model (view, priv->list);
730 return editor;
733 static void
734 cg_element_editor_set_valuesv_foreach_func (gpointer key,
735 gpointer data,
736 gpointer user_data)
738 GString *str;
739 gchar *escaped;
741 str = (GString*)user_data;
742 escaped = g_strescape ((const gchar *) data, NULL);
744 g_string_append (str, (const gchar *) key);
745 g_string_append (str, "=\"");
746 g_string_append (str, escaped);
747 g_string_append (str, "\";");
748 g_free (escaped);
751 static void
752 cg_element_editor_set_valuesv (CgElementEditor *editor,
753 const gchar *name,
754 NPWValueHeap *values,
755 CgElementEditorTransformFunc func,
756 gpointer user_data,
757 const gchar **field_names)
759 CgElementEditorPrivate *priv;
760 GtkTreeIter iter;
761 gboolean result;
762 GString *value_str;
763 gchar *value_name;
764 GHashTable *table;
765 gchar *single_value;
766 NPWValue *value;
767 guint32 i;
768 guint32 row_counter;
770 priv = CG_ELEMENT_EDITOR_PRIVATE (editor);
771 row_counter = 0;
773 value_str = g_string_sized_new (256);
775 for (result = gtk_tree_model_get_iter_first (priv->list, &iter);
776 result == TRUE;
777 result = gtk_tree_model_iter_next (priv->list, &iter))
779 value_name = g_strdup_printf ("%s[%d]", name, row_counter);
781 table = g_hash_table_new_full (g_str_hash, g_str_equal,
782 NULL, (GDestroyNotify) g_free);
784 for (i = 0; i < priv->n_columns; ++ i)
786 gtk_tree_model_get (priv->list, &iter, i, &single_value, -1);
787 g_hash_table_insert (table, (gpointer) field_names[i],
788 single_value);
791 if(func != NULL) func (table, user_data);
793 g_string_append_c (value_str, '{');
794 g_hash_table_foreach (table,
795 cg_element_editor_set_valuesv_foreach_func,
796 value_str);
797 g_string_append_c (value_str, '}');
798 g_hash_table_destroy (table);
800 value = npw_value_heap_find_value (values, value_name);
802 npw_value_heap_set_value (values, value, value_str->str,
803 NPW_VALID_VALUE);
805 g_string_set_size (value_str, 0);
806 g_free (value_name);
808 ++ row_counter;
811 g_string_free (value_str, TRUE);
814 void
815 cg_element_editor_set_values (CgElementEditor *editor,
816 const gchar *name,
817 NPWValueHeap *values,
818 CgElementEditorTransformFunc func,
819 gpointer user_data,
820 ...)
822 const gchar **field_names;
823 CgElementEditorPrivate *priv;
824 va_list arglist;
825 guint32 i;
827 priv = CG_ELEMENT_EDITOR_PRIVATE (editor);
829 field_names = g_malloc (sizeof (const gchar *) * priv->n_columns);
830 va_start (arglist, user_data);
832 for (i = 0; i < priv->n_columns; ++ i)
833 field_names[i] = va_arg (arglist, const gchar*);
835 cg_element_editor_set_valuesv (editor, name, values, func,
836 user_data, field_names);
838 va_end (arglist);
839 g_free (field_names);
842 void
843 cg_element_editor_set_value_count (CgElementEditor *editor,
844 const gchar *name,
845 NPWValueHeap *values,
846 CgElementEditorConditionFunc func,
847 gpointer user_data)
849 CgElementEditorPrivate* priv;
850 GtkTreeIter iter;
851 gboolean result;
852 NPWValue *value;
853 const gchar **vals;
854 gchar count_str[16];
855 guint count;
856 guint i;
858 priv = CG_ELEMENT_EDITOR_PRIVATE (editor);
859 vals = g_malloc (priv->n_columns * sizeof (const gchar *));
860 count = 0;
862 for (result = gtk_tree_model_get_iter_first (priv->list, &iter);
863 result == TRUE;
864 result = gtk_tree_model_iter_next (priv->list, &iter))
866 for (i = 0; i < priv->n_columns; ++ i)
868 gtk_tree_model_get (priv->list, &iter, i, &vals[i], -1);
871 if (func == NULL)
873 ++ count;
875 else if (func (vals, user_data) == TRUE)
877 ++ count;
881 g_free (vals);
883 sprintf (count_str, "%u", count);
884 value = npw_value_heap_find_value (values, name);
885 npw_value_heap_set_value (values, value, count_str, NPW_VALID_VALUE);