fix .desktop file
[gconf-editor] / src / gconf-cell-renderer.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3  * Copyright (C) 2001, 2002 Anders Carlsson <andersca@gnu.org>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
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 GNU
13  * General Public License for more details.
14  *
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., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19
20 #include <config.h>
21 #include "gconf-cell-renderer.h"
22
23 #include <gtk/gtk.h>
24 #include <glib/gi18n.h>
25
26 #include "gconf-util.h"
27 #include "gconf-marshal.h"
28
29 #define GCONF_CELL_RENDERER_TEXT_PATH "gconf-cell-renderer-text-path"
30 #define GCONF_CELL_RENDERER_VALUE "gconf-cell-renderer-value"
31 #define SCHEMA_TEXT "<schema>"
32
33 enum {
34         PROP_ZERO,
35         PROP_VALUE
36 };
37
38 enum {
39         CHANGED,
40         CHECK_WRITABLE,
41         LAST_SIGNAL
42 };
43
44 static guint gconf_cell_signals[LAST_SIGNAL] = { 0 };
45
46 G_DEFINE_TYPE(GConfCellRenderer, gconf_cell_renderer, GTK_TYPE_CELL_RENDERER)
47
48
49 static void
50 gconf_cell_renderer_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec)
51 {
52         GConfCellRenderer *cellvalue;
53
54         cellvalue = GCONF_CELL_RENDERER (object);
55         
56         switch (param_id) {
57         case PROP_VALUE:
58                 g_value_set_boxed (value, cellvalue->value);
59                 break;
60         default:
61                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
62                 break;
63         }
64
65 }
66
67 static void
68 gconf_cell_renderer_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec *pspec)
69 {
70         GConfCellRenderer *cellvalue;
71         GConfValue *gconf_value;
72         GtkCellRendererMode new_mode = GTK_CELL_RENDERER_MODE_INERT;
73         
74         cellvalue = GCONF_CELL_RENDERER (object);
75
76         switch (param_id) {
77         case PROP_VALUE:
78                 if (cellvalue->value) 
79                         gconf_value_free (cellvalue->value);
80
81                 gconf_value = g_value_get_boxed (value);
82
83                 if (gconf_value) {
84                         cellvalue->value = gconf_value_copy (gconf_value);
85
86                         switch (gconf_value->type) {
87                         case GCONF_VALUE_INT:
88                         case GCONF_VALUE_FLOAT:
89                         case GCONF_VALUE_STRING:
90                                 new_mode = GTK_CELL_RENDERER_MODE_EDITABLE;
91                                 break;
92                                 
93                         case GCONF_VALUE_BOOL:
94                                 new_mode = GTK_CELL_RENDERER_MODE_ACTIVATABLE;
95                                 break;
96
97                         case GCONF_VALUE_LIST:
98                         case GCONF_VALUE_SCHEMA:
99                         case GCONF_VALUE_PAIR:
100                                 new_mode = GTK_CELL_RENDERER_MODE_INERT;
101                                 break;
102                         default:
103                                 g_warning ("unhandled value type %d", gconf_value->type);
104                                 break;
105                         }
106                 }
107                 else {
108                         cellvalue->value = NULL;
109                 }
110
111                 g_object_set (object, "mode", new_mode, NULL);
112                 break;
113         default:
114                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
115                 break;  
116         }
117 }
118
119 static void
120 gconf_cell_renderer_finalize (GObject *object)
121 {
122         GConfCellRenderer *renderer = GCONF_CELL_RENDERER (object);
123
124         if (renderer->value)
125                 gconf_value_free (renderer->value);
126
127         g_object_unref (renderer->text_renderer);
128         g_object_unref (renderer->toggle_renderer);
129
130         (* G_OBJECT_CLASS (gconf_cell_renderer_parent_class)->finalize) (object);
131 }
132
133 static void
134 gconf_cell_renderer_get_size (GtkCellRenderer *cell, GtkWidget *widget, GdkRectangle *cell_area,
135                               gint *x_offset, gint *y_offset, gint *width, gint *height)
136 {
137         GConfCellRenderer *cellvalue;
138         gchar *tmp_str;
139         
140         cellvalue = GCONF_CELL_RENDERER (cell);
141
142         if (cellvalue->value == NULL) {
143                 g_object_set (G_OBJECT (cellvalue->text_renderer),
144                               "text", _("<no value>"),
145                               NULL);
146                 gtk_cell_renderer_get_size (cellvalue->text_renderer, widget, cell_area,
147                                             x_offset, y_offset, width, height);
148                 return;
149         }
150         
151         switch (cellvalue->value->type) {
152         case GCONF_VALUE_FLOAT:
153         case GCONF_VALUE_INT:
154                 tmp_str = gconf_value_to_string (cellvalue->value);
155                 g_object_set (G_OBJECT (cellvalue->text_renderer),
156                               "text", tmp_str,
157                               NULL);
158                 gtk_cell_renderer_get_size (cellvalue->text_renderer, widget, cell_area,
159                                             x_offset, y_offset, width, height);
160                 g_free (tmp_str);
161                 break;
162         case GCONF_VALUE_STRING:
163                 g_object_set (G_OBJECT (cellvalue->text_renderer),
164                               "text", gconf_value_get_string (cellvalue->value),
165                               NULL);
166                 gtk_cell_renderer_get_size (cellvalue->text_renderer, widget, cell_area,
167                                             x_offset, y_offset, width, height);
168                 break;
169         case GCONF_VALUE_BOOL:
170                 g_object_set (G_OBJECT (cellvalue->toggle_renderer),
171                               "xalign", 0.0,
172                               "active", gconf_value_get_bool (cellvalue->value),
173                               NULL);
174                 gtk_cell_renderer_get_size (cellvalue->toggle_renderer, widget, cell_area,
175                                             x_offset, y_offset, width, height);
176                 break;
177         case GCONF_VALUE_SCHEMA:
178                 g_object_set (G_OBJECT (cellvalue->text_renderer),
179                               "text", SCHEMA_TEXT,
180                               NULL);
181                 gtk_cell_renderer_get_size (cellvalue->text_renderer,
182                                             widget, cell_area,
183                                             x_offset, y_offset, width, height);
184                 break;
185         case GCONF_VALUE_LIST:
186                 tmp_str = gconf_value_to_string (cellvalue->value);
187                 g_object_set (G_OBJECT (cellvalue->text_renderer),
188                               "text", tmp_str,
189                               NULL);
190                 gtk_cell_renderer_get_size (cellvalue->text_renderer,
191                                             widget, cell_area,
192                                             x_offset, y_offset, width, height);
193                 g_free (tmp_str);
194                 break;
195         case GCONF_VALUE_PAIR:
196                 tmp_str = gconf_value_to_string (cellvalue->value);
197                 g_object_set (G_OBJECT (cellvalue->text_renderer),
198                               "text", tmp_str,
199                               NULL);
200                 gtk_cell_renderer_get_size (cellvalue->text_renderer,
201                                             widget, cell_area,
202                                             x_offset, y_offset, width, height);
203                 g_free (tmp_str);
204                 break;
205         default:
206                 g_print ("get_size: Unknown type: %d\n", cellvalue->value->type);
207                 break;
208         }
209 }
210
211 static void
212 gconf_cell_renderer_text_editing_done (GtkCellEditable *entry, GConfCellRenderer *cell)
213 {
214         const gchar *path;
215         const gchar *new_text;
216         GConfValue *value;
217         
218         if (GTK_ENTRY (entry)->editing_canceled)
219                 return;
220
221         path = g_object_get_data (G_OBJECT (entry), GCONF_CELL_RENDERER_TEXT_PATH);
222         value = g_object_get_data (G_OBJECT (entry), GCONF_CELL_RENDERER_VALUE);
223         new_text = gtk_entry_get_text (GTK_ENTRY (entry));
224
225         switch (value->type) {
226         case GCONF_VALUE_STRING:
227                 gconf_value_set_string (value, new_text);
228                 break;
229         case GCONF_VALUE_FLOAT:
230                 gconf_value_set_float (value, (gdouble)(g_ascii_strtod (new_text, NULL)));
231                 break;
232         case GCONF_VALUE_INT:
233                 gconf_value_set_int (value, (gint)(g_ascii_strtod (new_text, NULL)));
234                 break;
235         default:
236                 g_error ("editing done, unknown value %d", value->type);
237                 break;
238         }
239         
240         g_signal_emit (cell, gconf_cell_signals[CHANGED], 0, path, value);
241 }
242
243 static gboolean
244 gconf_cell_renderer_check_writability (GConfCellRenderer *cell, const gchar *path)
245 {
246         gboolean ret = TRUE;
247         g_signal_emit (cell, gconf_cell_signals[CHECK_WRITABLE], 0, path, &ret);
248         return ret;
249 }
250
251 static GtkCellEditable *
252 gconf_cell_renderer_start_editing (GtkCellRenderer      *cell,
253                                    GdkEvent             *event,
254                                    GtkWidget            *widget,
255                                    const gchar          *path,
256                                    GdkRectangle         *background_area,
257                                    GdkRectangle         *cell_area,
258                                    GtkCellRendererState  flags)
259 {
260         GtkWidget *entry;
261         GConfCellRenderer *cellvalue;
262         gchar *tmp_str;
263
264         cellvalue = GCONF_CELL_RENDERER (cell);
265
266         /* If not writable then we definately can't edit */
267         if ( ! gconf_cell_renderer_check_writability (cellvalue, path))
268                 return NULL;
269         
270         switch (cellvalue->value->type) {
271         case GCONF_VALUE_INT:
272         case GCONF_VALUE_FLOAT:
273         case GCONF_VALUE_STRING:
274                 tmp_str = gconf_value_to_string (cellvalue->value);
275                 entry = g_object_new (GTK_TYPE_ENTRY,
276                                       "has_frame", FALSE,
277                                       "text", tmp_str,
278                                       NULL);
279                 g_free (tmp_str);
280                 g_signal_connect (entry, "editing_done",
281                                   G_CALLBACK (gconf_cell_renderer_text_editing_done), cellvalue);
282
283                 g_object_set_data_full (G_OBJECT (entry), GCONF_CELL_RENDERER_TEXT_PATH, g_strdup (path), g_free);
284                 g_object_set_data_full (G_OBJECT (entry), GCONF_CELL_RENDERER_VALUE, gconf_value_copy (cellvalue->value), (GDestroyNotify)gconf_value_free);
285                 
286                 gtk_widget_show (entry);
287
288                 return GTK_CELL_EDITABLE (entry);
289                 break;
290         default:
291                 g_error ("%d shouldn't be handled here", cellvalue->value->type);
292                 break;
293         }
294
295         
296         return NULL;
297 }
298
299 static gint
300 gconf_cell_renderer_activate (GtkCellRenderer      *cell,
301                               GdkEvent             *event,
302                               GtkWidget            *widget,
303                               const gchar          *path,
304                               GdkRectangle         *background_area,
305                               GdkRectangle         *cell_area,
306                               GtkCellRendererState  flags)
307 {
308         GConfCellRenderer *cellvalue;
309         
310         cellvalue = GCONF_CELL_RENDERER (cell);
311
312         if (cellvalue->value == NULL)
313                 return TRUE;
314
315         switch (cellvalue->value->type) {
316         case GCONF_VALUE_BOOL:
317                 gconf_value_set_bool (cellvalue->value, !gconf_value_get_bool (cellvalue->value));
318                 g_signal_emit (cell, gconf_cell_signals[CHANGED], 0, path, cellvalue->value);
319                 
320                 break;
321         default:
322                 g_error ("%d shouldn't be handled here", cellvalue->value->type);
323                 break;
324         }
325
326         return TRUE;
327 }
328
329 static void
330 gconf_cell_renderer_render (GtkCellRenderer *cell, GdkWindow *window, GtkWidget *widget,
331                             GdkRectangle *background_area, GdkRectangle *cell_area, GdkRectangle *expose_area,
332                             GtkCellRendererState flags)
333 {
334         GConfCellRenderer *cellvalue;
335         char *tmp_str;
336         
337         cellvalue = GCONF_CELL_RENDERER (cell);
338
339         if (cellvalue->value == NULL) {
340                 g_object_set (G_OBJECT (cellvalue->text_renderer),
341                               "text", _("<no value>"),
342                               NULL);
343
344                 gtk_cell_renderer_render (cellvalue->text_renderer, window, widget,
345                                           background_area, cell_area, expose_area, flags);
346                 return;
347         }
348
349         switch (cellvalue->value->type) {
350         case GCONF_VALUE_FLOAT:
351         case GCONF_VALUE_INT:
352                 tmp_str = gconf_value_to_string (cellvalue->value);
353                 g_object_set (G_OBJECT (cellvalue->text_renderer),
354                               "text", tmp_str,
355                               NULL);
356                 gtk_cell_renderer_render (cellvalue->text_renderer, window, widget,
357                                           background_area, cell_area, expose_area, flags);
358                 g_free (tmp_str);
359                 break;
360         case GCONF_VALUE_STRING:
361                 g_object_set (G_OBJECT (cellvalue->text_renderer),
362                               "text", gconf_value_get_string (cellvalue->value),
363                               NULL);
364                 gtk_cell_renderer_render (cellvalue->text_renderer, window, widget,
365                                           background_area, cell_area, expose_area, flags);
366                 break;
367         case GCONF_VALUE_BOOL:
368                 g_object_set (G_OBJECT (cellvalue->toggle_renderer),
369                               "xalign", 0.0,
370                               "active", gconf_value_get_bool (cellvalue->value),
371                               NULL);
372                 
373                 gtk_cell_renderer_render (cellvalue->toggle_renderer, window, widget,
374                                           background_area, cell_area, expose_area, flags);
375                 break;
376
377         case GCONF_VALUE_SCHEMA:
378                 g_object_set (G_OBJECT (cellvalue->text_renderer),
379                               "text", SCHEMA_TEXT,
380                               NULL);
381                 
382                 gtk_cell_renderer_render (cellvalue->text_renderer, window, widget,
383                                           background_area, cell_area, expose_area, flags);
384                 break;
385                 
386         case GCONF_VALUE_LIST:
387                 tmp_str = gconf_value_to_string (cellvalue->value);
388                 g_object_set (G_OBJECT (cellvalue->text_renderer),
389                               "text", tmp_str,
390                               NULL);
391                 
392                 gtk_cell_renderer_render (cellvalue->text_renderer, window, widget,
393                                           background_area, cell_area, expose_area, flags);
394                 g_free (tmp_str);
395                 break;
396         case GCONF_VALUE_PAIR:
397                 tmp_str = gconf_value_to_string (cellvalue->value);
398                 g_object_set (G_OBJECT (cellvalue->text_renderer),
399                               "text", tmp_str,
400                               NULL);
401                 gtk_cell_renderer_render (cellvalue->text_renderer, window, widget,
402                                           background_area, cell_area, expose_area, flags);
403                 g_free (tmp_str);
404                 break;
405
406         default:
407                 g_print ("render: Unknown type: %d\n", cellvalue->value->type);
408                 break;
409         }
410 }
411
412 static void
413 gconf_cell_renderer_class_init (GConfCellRendererClass *klass)
414 {
415         GObjectClass *object_class = (GObjectClass *)klass;
416         GtkCellRendererClass *cell_renderer_class = (GtkCellRendererClass *)klass;
417
418         object_class->get_property = gconf_cell_renderer_get_property;
419         object_class->set_property = gconf_cell_renderer_set_property;
420         object_class->finalize = gconf_cell_renderer_finalize;
421
422         cell_renderer_class->get_size = gconf_cell_renderer_get_size;
423         cell_renderer_class->render = gconf_cell_renderer_render;
424         cell_renderer_class->activate = gconf_cell_renderer_activate;
425         cell_renderer_class->start_editing = gconf_cell_renderer_start_editing;
426
427         g_object_class_install_property (object_class, PROP_VALUE,
428                                          g_param_spec_boxed ("value",
429                                                              NULL, NULL,
430                                                              GCONF_TYPE_VALUE,
431                                                              G_PARAM_READWRITE));
432
433         gconf_cell_signals[CHANGED] =
434                 g_signal_new ("changed",
435                               G_TYPE_FROM_CLASS (object_class),
436                               G_SIGNAL_RUN_LAST,
437                               G_STRUCT_OFFSET (GConfCellRendererClass, changed),
438                               (GSignalAccumulator) NULL, NULL,
439                               gconf_marshal_VOID__STRING_BOXED,
440                               G_TYPE_NONE, 2,
441                               G_TYPE_STRING,
442                               GCONF_TYPE_VALUE);
443         gconf_cell_signals[CHECK_WRITABLE] =
444                 g_signal_new ("check_writable",
445                               G_TYPE_FROM_CLASS (object_class),
446                               G_SIGNAL_RUN_LAST,
447                               G_STRUCT_OFFSET (GConfCellRendererClass, changed),
448                               (GSignalAccumulator) NULL, NULL,
449                               gconf_marshal_BOOLEAN__STRING,
450                               G_TYPE_BOOLEAN, 1,
451                               G_TYPE_STRING);
452 }
453
454 static void
455 gconf_cell_renderer_init (GConfCellRenderer *renderer)
456 {
457         GTK_CELL_RENDERER (renderer)->mode = GTK_CELL_RENDERER_MODE_ACTIVATABLE;
458         
459         renderer->text_renderer = gtk_cell_renderer_text_new ();
460         g_object_ref_sink (renderer->text_renderer);
461
462         renderer->toggle_renderer = gtk_cell_renderer_toggle_new ();
463         g_object_ref_sink (renderer->toggle_renderer);
464 }
465
466
467
468 GtkCellRenderer *
469 gconf_cell_renderer_new (void)
470 {
471   return GTK_CELL_RENDERER (g_object_new (GCONF_TYPE_CELL_RENDERER, NULL));
472 }
473