Support individual files and folders in log output.
[anjuta-git-plugin.git] / plugins / class-gen / cell-renderer-flags.c
blob0154984177b767dc7a9f72ba0644de1e521c4957
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /* cell-renderer-flags.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 "cell-renderer-flags.h"
21 #include "combo-flags.h"
23 #include <gtk/gtkcombobox.h>
24 #include <gtk/gtktreemodel.h>
25 #include <gtk/gtkcelllayout.h>
26 #include <gtk/gtkcellrenderertext.h>
27 #include <gtk/gtkcellrenderertoggle.h>
28 #include <gtk/gtkcellrenderer.h>
30 typedef struct _CgCellRendererFlagsPrivate CgCellRendererFlagsPrivate;
31 struct _CgCellRendererFlagsPrivate
33 GtkTreeModel *model;
34 gint text_column;
35 gint abbr_column;
37 GHashTable *edit_status;
38 guint focus_out_id;
41 #define CG_CELL_RENDERER_FLAGS_PRIVATE(o) \
42 (G_TYPE_INSTANCE_GET_PRIVATE( \
43 (o), \
44 CG_TYPE_CELL_RENDERER_FLAGS, \
45 CgCellRendererFlagsPrivate \
48 enum {
49 PROP_0,
51 PROP_MODEL,
52 PROP_TEXT_COLUMN,
53 PROP_ABBR_COLUMN
56 #define CG_CELL_RENDERER_FLAGS_PATH "cg-cell-renderer-flags-path"
58 static GtkCellRendererTextClass *parent_class = NULL;
60 static void
61 cg_cell_renderer_flags_init (CgCellRendererFlags *cell_renderer_flags)
63 CgCellRendererFlagsPrivate *priv;
64 priv = CG_CELL_RENDERER_FLAGS_PRIVATE (cell_renderer_flags);
66 priv->model = NULL;
67 priv->text_column = -1;
68 priv->abbr_column = -1;
70 priv->edit_status = NULL;
71 priv->focus_out_id = 0;
74 static void
75 cg_cell_renderer_flags_finalize (GObject *object)
77 CgCellRendererFlags *cell_renderer_flags;
78 CgCellRendererFlagsPrivate *priv;
80 cell_renderer_flags = CG_CELL_RENDERER_FLAGS (object);
81 priv = CG_CELL_RENDERER_FLAGS_PRIVATE (cell_renderer_flags);
83 if (priv->edit_status != NULL)
85 g_hash_table_destroy (priv->edit_status);
86 priv->edit_status = NULL;
89 if (priv->model != NULL)
91 g_object_unref (G_OBJECT(priv->model));
92 priv->model = NULL;
95 G_OBJECT_CLASS (parent_class)-> finalize(object);
98 static void
99 cg_cell_renderer_flags_set_property (GObject *object,
100 guint prop_id,
101 const GValue *value,
102 GParamSpec *pspec)
104 CgCellRendererFlags *renderer;
105 CgCellRendererFlagsPrivate *priv;
107 g_return_if_fail (CG_IS_CELL_RENDERER_FLAGS (object));
109 renderer = CG_CELL_RENDERER_FLAGS (object);
110 priv = CG_CELL_RENDERER_FLAGS_PRIVATE (renderer);
112 switch (prop_id)
114 case PROP_MODEL:
115 if(priv->model != NULL) g_object_unref (G_OBJECT (priv->model));
116 priv->model = GTK_TREE_MODEL (g_value_dup_object (value));
117 break;
118 case PROP_TEXT_COLUMN:
119 priv->text_column = g_value_get_int (value);
120 break;
121 case PROP_ABBR_COLUMN:
122 priv->abbr_column = g_value_get_int (value);
123 break;
124 default:
125 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
126 break;
130 static void
131 cg_cell_renderer_flags_get_property (GObject *object,
132 guint prop_id,
133 GValue *value,
134 GParamSpec *pspec)
136 CgCellRendererFlags *renderer;
137 CgCellRendererFlagsPrivate *priv;
139 g_return_if_fail (CG_IS_CELL_RENDERER_FLAGS (object));
141 renderer = CG_CELL_RENDERER_FLAGS (object);
142 priv = CG_CELL_RENDERER_FLAGS_PRIVATE (renderer);
144 switch(prop_id)
146 case PROP_MODEL:
147 g_value_set_object (value, G_OBJECT (priv->model));
148 break;
149 case PROP_TEXT_COLUMN:
150 g_value_set_int (value, priv->text_column);
151 break;
152 case PROP_ABBR_COLUMN:
153 g_value_set_int (value, priv->abbr_column);
154 break;
155 default:
156 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
157 break;
161 static void
162 cg_cell_renderer_flags_editing_done (GtkCellEditable *editable,
163 G_GNUC_UNUSED gpointer data)
165 CgCellRendererFlags *cell_flags;
166 CgCellRendererFlagsPrivate *priv;
168 const gchar *path;
169 GString *str;
170 gchar *abbr;
171 GtkTreeIter iter;
172 gboolean result;
173 gboolean canceled;
175 cell_flags = CG_CELL_RENDERER_FLAGS (data);
176 priv = CG_CELL_RENDERER_FLAGS_PRIVATE (cell_flags);
178 g_assert (priv->edit_status != NULL);
180 if (priv->focus_out_id > 0)
182 g_signal_handler_disconnect (G_OBJECT (editable), priv->focus_out_id);
183 priv->focus_out_id = 0;
186 canceled = cg_combo_flags_editing_canceled (CG_COMBO_FLAGS (editable));
187 gtk_cell_renderer_stop_editing (GTK_CELL_RENDERER(cell_flags), canceled);
189 if (canceled == FALSE)
191 str = g_string_sized_new (128);
193 /* We do not just call g_hash_table_foreach to get the flags
194 * in the correct order. */
195 for (result = gtk_tree_model_get_iter_first (priv->model, &iter);
196 result != FALSE;
197 result = gtk_tree_model_iter_next (priv->model, &iter))
199 gtk_tree_model_get (priv->model, &iter,
200 priv->abbr_column, &abbr, -1);
202 if (g_hash_table_lookup (priv->edit_status, abbr) != NULL)
204 if (str->len > 0) g_string_append_c (str, '|');
205 g_string_append (str, abbr);
208 g_free (abbr);
211 path = g_object_get_data (G_OBJECT (editable),
212 CG_CELL_RENDERER_FLAGS_PATH);
214 g_signal_emit_by_name (G_OBJECT (cell_flags), "edited",
215 path, str->str);
217 g_string_free (str, TRUE);
220 g_hash_table_destroy (priv->edit_status);
221 priv->edit_status = NULL;
224 static void
225 cg_cell_renderer_flags_selected (CgComboFlags *combo,
226 GtkTreeIter *iter,
227 CgComboFlagsSelectionType type,
228 gpointer user_data)
230 CgCellRendererFlags *cell_flags;
231 CgCellRendererFlagsPrivate *priv;
232 gpointer result;
233 gchar *name;
234 gchar *abbr;
236 cell_flags = CG_CELL_RENDERER_FLAGS (user_data);
237 priv = CG_CELL_RENDERER_FLAGS_PRIVATE (cell_flags);
239 gtk_tree_model_get (priv->model, iter, priv->text_column, &name,
240 priv->abbr_column, &abbr, -1);
242 g_assert (priv->edit_status != NULL);
243 result = g_hash_table_lookup (priv->edit_status, abbr);
245 /* abbr needs not to be freed if it gets inserted into the hash table
246 * because the hash table then takes ownership of it. */
247 switch (type)
249 case CG_COMBO_FLAGS_SELECTION_NONE:
250 g_free (abbr);
251 break;
252 case CG_COMBO_FLAGS_SELECTION_SELECT:
253 if (GPOINTER_TO_INT(result) != 1)
254 g_hash_table_insert (priv->edit_status, abbr, GINT_TO_POINTER (1));
255 else
256 g_free (abbr);
258 break;
259 case CG_COMBO_FLAGS_SELECTION_UNSELECT:
260 if (GPOINTER_TO_INT (result) == 1)
261 g_hash_table_remove(priv->edit_status, abbr);
263 g_free (abbr);
264 break;
265 case CG_COMBO_FLAGS_SELECTION_TOGGLE:
266 if (GPOINTER_TO_INT (result) == 1)
268 g_hash_table_remove (priv->edit_status, abbr);
269 g_free(abbr);
271 else
273 g_hash_table_insert (priv->edit_status, abbr, GINT_TO_POINTER (1));
276 break;
277 default:
278 g_assert_not_reached ();
279 break;
282 /* This is done to get GTK+ to re-render this row with the changed flag
283 * status that is set via the cell data func, but GTK+ does not call it
284 * again because it does not know that the hash table changed. There are
285 * probably better means to achieve this, but I am not aware of those. */
286 gtk_list_store_set (GTK_LIST_STORE (priv->model), iter,
287 priv->text_column, name, -1);
289 g_free (name);
292 static gboolean
293 cg_cell_renderer_flags_focus_out_event (GtkWidget *widget,
294 G_GNUC_UNUSED GdkEvent *event,
295 gpointer data)
297 cg_cell_renderer_flags_editing_done (GTK_CELL_EDITABLE (widget), data);
298 return FALSE;
301 static void
302 cg_cell_renderer_flags_set_data_func (G_GNUC_UNUSED GtkCellLayout *cell_layout,
303 GtkCellRenderer *cell,
304 GtkTreeModel *model,
305 GtkTreeIter *iter,
306 gpointer data)
308 CgCellRendererFlags *cell_flags;
309 CgCellRendererFlagsPrivate *priv;
310 gchar *abbr;
312 cell_flags = CG_CELL_RENDERER_FLAGS (data);
313 priv = CG_CELL_RENDERER_FLAGS_PRIVATE (cell_flags);
315 if(priv->edit_status != NULL)
317 gtk_tree_model_get (model, iter, priv->abbr_column, &abbr, -1);
319 if (g_hash_table_lookup (priv->edit_status, abbr) != NULL)
320 g_object_set (G_OBJECT (cell), "active", TRUE, NULL);
321 else
322 g_object_set (G_OBJECT (cell), "active", FALSE, NULL);
324 g_free (abbr);
328 static GtkCellEditable *
329 cg_cell_renderer_flags_start_editing (GtkCellRenderer *cell,
330 G_GNUC_UNUSED GdkEvent *event,
331 G_GNUC_UNUSED GtkWidget *widget,
332 const gchar *path,
333 G_GNUC_UNUSED GdkRectangle
334 *background_area,
335 G_GNUC_UNUSED GdkRectangle *cell_area,
336 G_GNUC_UNUSED GtkCellRendererState flags)
338 CgCellRendererFlags *cell_flags;
339 CgCellRendererFlagsPrivate *priv;
340 GtkCellRendererText *cell_text;
341 const gchar *prev;
342 const gchar *pos;
344 GtkWidget *combo;
345 GtkCellRenderer *cell_combo_set;
346 GtkCellRenderer *cell_combo_text;
348 cell_flags = CG_CELL_RENDERER_FLAGS (cell);
349 priv = CG_CELL_RENDERER_FLAGS_PRIVATE (cell_flags);
351 cell_text = GTK_CELL_RENDERER_TEXT (cell);
352 if (cell_text->editable == FALSE) return NULL;
354 if (priv->model == NULL || priv->text_column < 0 || priv->abbr_column < 0)
355 return NULL;
357 cell_combo_set = gtk_cell_renderer_toggle_new ();
358 cell_combo_text = gtk_cell_renderer_text_new ();
360 combo = cg_combo_flags_new_with_model (priv->model);
362 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo),
363 cell_combo_set, FALSE);
364 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo),
365 cell_combo_text, TRUE);
367 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo),
368 cell_combo_text, "text", priv->text_column);
370 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo),
371 cell_combo_set,
372 cg_cell_renderer_flags_set_data_func,
373 cell_flags, NULL);
375 g_object_set (G_OBJECT (cell_combo_set), "activatable", FALSE, NULL);
377 /* Create hash table with current status. We could also operate
378 * directly on a string here, but a hash table is probably more
379 * efficient. */
380 g_assert (priv->edit_status == NULL);
381 priv->edit_status = g_hash_table_new_full (g_str_hash, g_str_equal,
382 (GDestroyNotify) g_free, NULL);
384 pos = cell_text->text;
385 prev = cell_text->text;
387 while (prev != NULL && *prev != '\0')
389 while (*pos != '|' && *pos != '\0') ++ pos;
391 g_hash_table_insert (priv->edit_status, g_strndup(prev, pos - prev),
392 GINT_TO_POINTER(1));
394 if(*pos != '\0') ++ pos;
395 prev = pos;
398 g_object_set_data_full (G_OBJECT (combo), CG_CELL_RENDERER_FLAGS_PATH,
399 g_strdup (path), g_free);
401 gtk_widget_show (combo);
403 g_signal_connect (G_OBJECT (combo), "editing-done",
404 G_CALLBACK (cg_cell_renderer_flags_editing_done),
405 cell_flags);
407 g_signal_connect (G_OBJECT (combo), "selected",
408 G_CALLBACK (cg_cell_renderer_flags_selected),
409 cell_flags);
411 priv->focus_out_id =
412 g_signal_connect (G_OBJECT (combo), "focus_out_event",
413 G_CALLBACK (cg_cell_renderer_flags_focus_out_event),
414 cell_flags);
416 return GTK_CELL_EDITABLE (combo);
419 static void
420 cg_cell_renderer_flags_class_init (CgCellRendererFlagsClass *klass)
422 GObjectClass *object_class = G_OBJECT_CLASS (klass);
423 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
424 parent_class = g_type_class_peek_parent (klass);
426 g_type_class_add_private (klass, sizeof (CgCellRendererFlagsPrivate));
428 object_class->finalize = cg_cell_renderer_flags_finalize;
429 object_class->set_property = cg_cell_renderer_flags_set_property;
430 object_class->get_property = cg_cell_renderer_flags_get_property;
432 cell_class->start_editing = cg_cell_renderer_flags_start_editing;
434 g_object_class_install_property (object_class,
435 PROP_MODEL,
436 g_param_spec_object ("model",
437 "Model",
438 "Model holding the available flags",
439 GTK_TYPE_TREE_MODEL,
440 G_PARAM_READWRITE));
442 g_object_class_install_property (object_class,
443 PROP_TEXT_COLUMN,
444 g_param_spec_int ("text-column",
445 "Text column",
446 "Column in the model holding the text for a flag",
448 G_MAXINT,
450 G_PARAM_READWRITE));
452 g_object_class_install_property (object_class,
453 PROP_ABBR_COLUMN,
454 g_param_spec_int ("abbrevation-column",
455 "Abbrevation column",
456 "Column in the model holding the abbrevation for a flag",
458 G_MAXINT,
460 G_PARAM_READWRITE));
463 GType
464 cg_cell_renderer_flags_get_type (void)
466 static GType our_type = 0;
468 if(our_type == 0)
470 static const GTypeInfo our_info =
472 sizeof (CgCellRendererFlagsClass),
473 (GBaseInitFunc) NULL,
474 (GBaseFinalizeFunc) NULL,
475 (GClassInitFunc) cg_cell_renderer_flags_class_init,
476 NULL,
477 NULL,
478 sizeof (CgCellRendererFlags),
480 (GInstanceInitFunc) cg_cell_renderer_flags_init,
481 NULL
484 our_type = g_type_register_static (GTK_TYPE_CELL_RENDERER_TEXT,
485 "CgCellRendererFlags",
486 &our_info, 0);
489 return our_type;
492 GtkCellRenderer *
493 cg_cell_renderer_flags_new (void)
495 GObject *object;
497 object = g_object_new (CG_TYPE_CELL_RENDERER_FLAGS, NULL);
499 return GTK_CELL_RENDERER (object);