1 /*
2 * Copyright (C) 2001 Ximian, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 * Authors:
19 * Chema Celorio <chema@celorio.com>
20 * Tristan Van Berkom <tristan.van.berkom@gmail.com>
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 /**
28 * SECTION:glade-property-class
29 * @Title: GladePropertyClass
30 * @Short_Description: Property Class-wide metadata.
31 *
32 * #GladePropertyClass is a structure based on a #GParamSpec and parameters
33 * from the Glade catalog files and describes how properties are to be handled
34 * in Glade; it also provides an interface to convert #GValue to strings and
35 * va_lists etc (back and forth).
36 */
37
38 #include <string.h>
39 #include <stdlib.h>
40 #include <glib/gi18n-lib.h>
41
42 #include "glade.h"
43 #include "glade-widget.h"
44 #include "glade-property.h"
45 #include "glade-property-class.h"
46 #include "glade-editor-property.h"
47 #include "glade-displayable-values.h"
48 #include "glade-debug.h"
49
50 #define NUMERICAL_STEP_INCREMENT 1.0F
51 #define NUMERICAL_PAGE_INCREMENT 10.0F
52 #define NUMERICAL_PAGE_SIZE 0.0F
53
54 #define FLOATING_STEP_INCREMENT 0.01F
55 #define FLOATING_PAGE_INCREMENT 0.1F
56 #define FLOATING_PAGE_SIZE 0.00F
57
58
59 struct _GladePropertyClass
60 {
61 GladeWidgetAdaptor *adaptor; /* The GladeWidgetAdaptor that this property class
62 * was created for.
63 */
64
65 guint16 version_since_major; /* Version in which this property was */
66 guint16 version_since_minor; /* introduced. */
67
68 GParamSpec *pspec; /* The Parameter Specification for this property.
69 */
70
71 gchar *id; /* The id of the property. Like "label" or "xpad"
72 * this is a non-translatable string
73 */
74
75 gchar *name; /* The name of the property. Like "Label" or "X Pad"
76 * this is a translatable string
77 */
78
79 gchar *tooltip; /* The default tooltip for the property editor rows.
80 */
81
82 GValue *def; /* The default value for this property (this will exist
83 * as a copy of orig_def if not specified by the catalog)
84 */
85
86 GValue *orig_def; /* The real default value obtained through introspection.
87 * (used to decide whether we should write to the
88 * glade file or not, or to restore the loaded property
89 * correctly); all property classes have and orig_def.
90 */
91
92 guint multiline : 1; /* Whether to use multiple lines to edit this text property.
93 */
94
95 guint virt : 1; /* Whether this is a virtual property with its pspec supplied
96 * via the catalog (or hard code-paths); or FALSE if its a real
97 * GObject introspected property
98 */
99
100 guint optional : 1; /* Some properties are optional by nature like
101 * default width. It can be set or not set. A
102 * default property has a check box in the
103 * left that enables/disables the input
104 */
105
106 guint optional_default : 1; /* For optional values, what the default is */
107
108 guint construct_only : 1; /* Whether this property is G_PARAM_CONSTRUCT_ONLY or not */
109
110 guint common : 1; /* Common properties go in the common tab */
111 guint atk : 1; /* Atk properties go in the atk tab */
112 guint packing : 1; /* Packing properties go in the packing tab */
113 guint query : 1; /* Whether we should explicitly ask the user about this property
114 * when instantiating a widget with this property (through a popup
115 * dialog).
116 */
117
118 guint translatable : 1; /* The property should be translatable, which
119 * means that it needs extra parameters in the
120 * UI.
121 */
122
123 /* These three are the master switches for the glade-file output,
124 * property editor availability & live object updates in the glade environment.
125 */
126 guint save : 1; /* Whether we should save to the glade file or not
127 * (mostly just for virtual internal glade properties,
128 * also used for properties with generic pspecs that
129 * are saved in custom ways by the plugin)
130 */
131 guint save_always : 1; /* Used to make a special case exception and always
132 * save this property regardless of what the default
133 * value is (used for some special cases like properties
134 * that are assigned initial values in composite widgets
135 * or derived widget code).
136 */
137 guint visible : 1; /* Whether or not to show this property in the editor &
138 * reset dialog.
139 */
140
141 guint custom_layout : 1; /* Properties marked as custom_layout will not be included
142 * in a base #GladeEditorTable implementation (use this
143 * for properties you want to layout in custom ways in
144 * a #GladeEditable widget
145 */
146
147 guint ignore : 1; /* When true, we will not sync the object when the property
148 * changes, or load values from the object.
149 */
150
151 guint needs_sync : 1; /* Virtual properties need to be synchronized after object
152 * creation, some properties that are not virtual also need
153 * handling from the backend, if "needs-sync" is true then
154 * this property will by synced with virtual properties.
155 */
156
157 guint is_modified : 1; /* If true, this property_class has been "modified" from the
158 * the standard property by a xml file. */
159
160 guint themed_icon : 1; /* Some GParamSpecString properties reffer to icon names
161 * in the icon theme... these need to be specified in the
162 * property class definition if proper editing tools are to
163 * be used.
164 */
165 guint stock_icon : 1; /* String properties can also denote stock icons, including
166 * icons from icon factories...
167 */
168 guint stock : 1; /* ... or a narrower list of "items" from gtk builtin stock items.
169 */
170
171 guint transfer_on_paste : 1; /* If this is a packing prop,
172 * wether we should transfer it on paste.
173 */
174
175 guint parentless_widget : 1; /* True if this property should point to a parentless widget
176 * in the project
177 */
178
179 guint deprecated : 1; /* True if this property is deprecated */
180
181 gdouble weight; /* This will determine the position of this property in
182 * the editor.
183 */
184
185 gchar *create_type; /* If this is an object property and you want the option to create
186 * one from the object selection dialog, then set the name of the
187 * concrete type here.
188 */
189 };
190
191 /**
192 * glade_property_class_new:
193 * @adaptor: The #GladeWidgetAdaptor to create this property for
194 * @id: the id for the new property class
195 *
196 * Returns: a new #GladePropertyClass
197 */
198 GladePropertyClass *
glade_property_class_new(GladeWidgetAdaptor * adaptor,const gchar * id)199 glade_property_class_new (GladeWidgetAdaptor *adaptor,
200 const gchar *id)
201 {
202 GladePropertyClass *property_class;
203
204 property_class = g_slice_new0 (GladePropertyClass);
205 property_class->adaptor = adaptor;
206 property_class->pspec = NULL;
207 property_class->id = g_strdup (id);
208 property_class->name = NULL;
209 property_class->tooltip = NULL;
210 property_class->def = NULL;
211 property_class->orig_def = NULL;
212 property_class->query = FALSE;
213 property_class->optional = FALSE;
214 property_class->optional_default = FALSE;
215 property_class->is_modified = FALSE;
216 property_class->common = FALSE;
217 property_class->packing = FALSE;
218 property_class->atk = FALSE;
219 property_class->visible = TRUE;
220 property_class->custom_layout = FALSE;
221 property_class->save = TRUE;
222 property_class->save_always = FALSE;
223 property_class->ignore = FALSE;
224 property_class->needs_sync = FALSE;
225 property_class->themed_icon = FALSE;
226 property_class->stock = FALSE;
227 property_class->stock_icon = FALSE;
228 property_class->translatable = FALSE;
229 property_class->virt = TRUE;
230 property_class->transfer_on_paste = FALSE;
231 property_class->weight = -1.0;
232 property_class->parentless_widget = FALSE;
233
234 /* Initialize property versions & deprecated to adaptor */
235 property_class->version_since_major = GWA_VERSION_SINCE_MAJOR (adaptor);
236 property_class->version_since_minor = GWA_VERSION_SINCE_MINOR (adaptor);
237 property_class->deprecated = GWA_DEPRECATED (adaptor);
238
239 return property_class;
240 }
241
242 /**
243 * glade_property_class_clone:
244 * @property_class: a #GladePropertyClass
245 * @reset_version: whether the introduction version should be reset in the clone
246 *
247 * Returns: a new #GladePropertyClass cloned from @property_class
248 */
249 GladePropertyClass *
glade_property_class_clone(GladePropertyClass * property_class,gboolean reset_version)250 glade_property_class_clone (GladePropertyClass *property_class,
251 gboolean reset_version)
252 {
253 GladePropertyClass *clone;
254
255 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), NULL);
256
257 clone = g_new0 (GladePropertyClass, 1);
258
259 /* copy ints over */
260 memcpy (clone, property_class, sizeof (GladePropertyClass));
261
262 if (reset_version)
263 {
264 clone->version_since_major = 0;
265 clone->version_since_minor = 0;
266 }
267
268 /* Make sure we own our strings */
269 clone->pspec = property_class->pspec;
270 clone->id = g_strdup (clone->id);
271 clone->name = g_strdup (clone->name);
272 clone->tooltip = g_strdup (clone->tooltip);
273
274 if (G_IS_VALUE (property_class->def))
275 {
276 clone->def = g_new0 (GValue, 1);
277 g_value_init (clone->def, property_class->pspec->value_type);
278 g_value_copy (property_class->def, clone->def);
279 }
280
281 if (G_IS_VALUE (property_class->orig_def))
282 {
283 clone->orig_def = g_new0 (GValue, 1);
284 g_value_init (clone->orig_def, property_class->pspec->value_type);
285 g_value_copy (property_class->orig_def, clone->orig_def);
286 }
287
288 return clone;
289 }
290
291 /**
292 * glade_property_class_free:
293 * @property_class: a #GladePropertyClass
294 *
295 * Frees @klass and its associated memory.
296 */
297 void
glade_property_class_free(GladePropertyClass * property_class)298 glade_property_class_free (GladePropertyClass * property_class)
299 {
300 if (property_class == NULL)
301 return;
302
303 g_return_if_fail (GLADE_IS_PROPERTY_CLASS (property_class));
304
305 g_free (property_class->id);
306 g_free (property_class->tooltip);
307 g_free (property_class->name);
308 if (property_class->orig_def)
309 {
310 if (G_VALUE_TYPE (property_class->orig_def) != 0)
311 g_value_unset (property_class->orig_def);
312 g_free (property_class->orig_def);
313 }
314 if (property_class->def)
315 {
316 if (G_VALUE_TYPE (property_class->def) != 0)
317 g_value_unset (property_class->def);
318 g_free (property_class->def);
319 }
320
321 g_slice_free (GladePropertyClass, property_class);
322 }
323
324
325 GValue *
glade_property_class_get_default_from_spec(GParamSpec * spec)326 glade_property_class_get_default_from_spec (GParamSpec * spec)
327 {
328 GValue *value;
329 value = g_new0 (GValue, 1);
330 g_value_init (value, spec->value_type);
331 g_param_value_set_default (spec, value);
332 return value;
333 }
334
335
336 static gchar *
glade_property_class_make_string_from_enum(GType etype,gint eval)337 glade_property_class_make_string_from_enum (GType etype, gint eval)
338 {
339 GEnumClass *eclass;
340 gchar *string = NULL;
341 guint i;
342
343 g_return_val_if_fail ((eclass = g_type_class_ref (etype)) != NULL, NULL);
344 for (i = 0; i < eclass->n_values; i++)
345 {
346 if (eval == eclass->values[i].value)
347 {
348 string = g_strdup (eclass->values[i].value_nick);
349 break;
350 }
351 }
352 g_type_class_unref (eclass);
353 return string;
354 }
355
356 static gchar *
glade_property_class_make_string_from_flags(GladePropertyClass * klass,guint fvals,gboolean displayables)357 glade_property_class_make_string_from_flags (GladePropertyClass * klass,
358 guint fvals, gboolean displayables)
359 {
360 GFlagsClass *fclass;
361 GFlagsValue *fvalue;
362 GString *string;
363 gchar *retval;
364
365 g_return_val_if_fail ((fclass =
366 g_type_class_ref (klass->pspec->value_type)) != NULL,
367 NULL);
368
369 string = g_string_new ("");
370
371 while ((fvalue = g_flags_get_first_value (fclass, fvals)) != NULL)
372 {
373 const gchar *val_str = NULL;
374
375 fvals &= ~fvalue->value;
376
377 if (displayables)
378 val_str = glade_get_displayable_value (klass->pspec->value_type,
379 fvalue->value_name);
380
381 if (string->str[0])
382 g_string_append (string, " | ");
383
384 g_string_append (string, (val_str) ? val_str : fvalue->value_name);
385
386 /* If one of the flags value is 0 this loop become infinite :) */
387 if (fvalue->value == 0)
388 break;
389 }
390
391 retval = string->str;
392
393 g_type_class_unref (fclass);
394 g_string_free (string, FALSE);
395
396 return retval;
397 }
398
399 static gchar *
glade_property_class_make_string_from_object(GladePropertyClass * property_class,GObject * object)400 glade_property_class_make_string_from_object (GladePropertyClass *
401 property_class, GObject * object)
402 {
403 GladeWidget *gwidget;
404 gchar *string = NULL, *filename;
405
406 if (!object)
407 return NULL;
408
409 if (property_class->pspec->value_type == GDK_TYPE_PIXBUF)
410 {
411 if ((filename = g_object_get_data (object, "GladeFileName")) != NULL)
412 string = g_strdup (filename);
413 }
414 else if ((gwidget = glade_widget_get_from_gobject (object)) != NULL)
415 string = g_strdup (glade_widget_get_name (gwidget));
416 else
417 g_critical ("Object type property refers to an object "
418 "outside the project");
419
420 return string;
421 }
422
423 static gchar *
glade_property_class_make_string_from_objects(GladePropertyClass * property_class,GList * objects)424 glade_property_class_make_string_from_objects (GladePropertyClass *
425 property_class, GList * objects)
426 {
427 GObject *object;
428 GList *list;
429 gchar *string = NULL, *obj_str, *tmp;
430
431 for (list = objects; list; list = list->next)
432 {
433 object = list->data;
434
435 obj_str =
436 glade_property_class_make_string_from_object (property_class, object);
437
438 if (string == NULL)
439 string = obj_str;
440 else if (obj_str != NULL)
441 {
442 tmp =
443 g_strdup_printf ("%s%s%s", string, GPC_OBJECT_DELIMITER, obj_str);
444 string = (g_free (string), tmp);
445 g_free (obj_str);
446 }
447 }
448 return string;
449 }
450
451 /**
452 * glade_property_class_make_string_from_gvalue:
453 * @property_class: A #GladePropertyClass
454 * @value: A #GValue
455 *
456 * Returns: A newly allocated string representation of @value
457 */
458 gchar *
glade_property_class_make_string_from_gvalue(GladePropertyClass * property_class,const GValue * value)459 glade_property_class_make_string_from_gvalue (GladePropertyClass *
460 property_class,
461 const GValue * value)
462 {
463 gchar *string = NULL, **strv, str[G_ASCII_DTOSTR_BUF_SIZE];
464 GObject *object;
465 GdkColor *color;
466 GdkRGBA *rgba;
467 GList *objects;
468
469 if (G_IS_PARAM_SPEC_ENUM (property_class->pspec))
470 {
471 gint eval = g_value_get_enum (value);
472 string = glade_property_class_make_string_from_enum
473 (property_class->pspec->value_type, eval);
474 }
475 else if (G_IS_PARAM_SPEC_FLAGS (property_class->pspec))
476 {
477 guint flags = g_value_get_flags (value);
478 string = glade_property_class_make_string_from_flags
479 (property_class, flags, FALSE);
480 }
481 else if (G_IS_PARAM_SPEC_VALUE_ARRAY (property_class->pspec))
482 {
483 GValueArray *value_array = g_value_get_boxed (value);
484
485 if (value_array && value_array->n_values &&
486 G_VALUE_HOLDS (&value_array->values[0], G_TYPE_STRING))
487 {
488 gint i, n_values = value_array->n_values;
489 GString *gstring = g_string_new (NULL);
490
491 for (i = 0; i < n_values; i++)
492 {
493 g_string_append (gstring,
494 g_value_get_string (&value_array->values[i]));
495 g_string_append_c (gstring, '\n');
496 }
497 string = gstring->str;
498 g_string_free (gstring, FALSE);
499 }
500 }
501 else if (G_IS_PARAM_SPEC_BOXED (property_class->pspec))
502 {
503 if (property_class->pspec->value_type == GDK_TYPE_COLOR)
504 {
505 color = g_value_get_boxed (value);
506 if (color)
507 string = g_strdup_printf ("#%04x%04x%04x",
508 color->red, color->green, color->blue);
509 }
510 else if (property_class->pspec->value_type == GDK_TYPE_RGBA)
511 {
512 rgba = g_value_get_boxed (value);
513 if (rgba)
514 string = gdk_rgba_to_string (rgba);
515 }
516 else if (property_class->pspec->value_type == G_TYPE_STRV)
517 {
518 strv = g_value_get_boxed (value);
519 if (strv)
520 string = g_strjoinv ("\n", strv);
521 }
522 }
523 else if (G_IS_PARAM_SPEC_INT (property_class->pspec))
524 string = g_strdup_printf ("%d", g_value_get_int (value));
525 else if (G_IS_PARAM_SPEC_UINT (property_class->pspec))
526 string = g_strdup_printf ("%u", g_value_get_uint (value));
527 else if (G_IS_PARAM_SPEC_LONG (property_class->pspec))
528 string = g_strdup_printf ("%ld", g_value_get_long (value));
529 else if (G_IS_PARAM_SPEC_ULONG (property_class->pspec))
530 string = g_strdup_printf ("%lu", g_value_get_ulong (value));
531 else if (G_IS_PARAM_SPEC_INT64 (property_class->pspec))
532 string = g_strdup_printf ("%" G_GINT64_FORMAT, g_value_get_int64 (value));
533 else if (G_IS_PARAM_SPEC_UINT64 (property_class->pspec))
534 string = g_strdup_printf ("%" G_GUINT64_FORMAT, g_value_get_uint64 (value));
535 else if (G_IS_PARAM_SPEC_FLOAT (property_class->pspec))
536 {
537 g_ascii_dtostr (str, sizeof (str), g_value_get_float (value));
538 string = g_strdup (str);
539 }
540 else if (G_IS_PARAM_SPEC_DOUBLE (property_class->pspec))
541 {
542 g_ascii_dtostr (str, sizeof (str), g_value_get_double (value));
543 string = g_strdup (str);
544 }
545 else if (G_IS_PARAM_SPEC_STRING (property_class->pspec))
546 {
547 string = g_value_dup_string (value);
548 }
549 else if (G_IS_PARAM_SPEC_CHAR (property_class->pspec))
550 string = g_strdup_printf ("%c", g_value_get_schar (value));
551 else if (G_IS_PARAM_SPEC_UCHAR (property_class->pspec))
552 string = g_strdup_printf ("%c", g_value_get_uchar (value));
553 else if (G_IS_PARAM_SPEC_UNICHAR (property_class->pspec))
554 {
555 int len;
556 string = g_malloc (7);
557 len = g_unichar_to_utf8 (g_value_get_uint (value), string);
558 string[len] = '\0';
559 }
560 else if (G_IS_PARAM_SPEC_BOOLEAN (property_class->pspec))
561 string = g_strdup_printf ("%s", g_value_get_boolean (value) ?
562 GLADE_TAG_TRUE : GLADE_TAG_FALSE);
563 else if (G_IS_PARAM_SPEC_OBJECT (property_class->pspec))
564 {
565 object = g_value_get_object (value);
566 string =
567 glade_property_class_make_string_from_object (property_class, object);
568 }
569 else if (GLADE_IS_PARAM_SPEC_OBJECTS (property_class->pspec))
570 {
571 objects = g_value_get_boxed (value);
572 string =
573 glade_property_class_make_string_from_objects (property_class,
574 objects);
575 }
576 else
577 g_critical ("Unsupported pspec type %s (value -> string)",
578 g_type_name (G_PARAM_SPEC_TYPE (property_class->pspec)));
579
580 return string;
581 }
582
583 /* This is copied exactly from libglade. I've just renamed the function.
584 */
585 static guint
glade_property_class_make_flags_from_string(GType type,const char * string)586 glade_property_class_make_flags_from_string (GType type, const char *string)
587 {
588 GFlagsClass *fclass;
589 gchar *endptr, *prevptr;
590 guint i, j, ret = 0;
591 char *flagstr;
592
593 ret = strtoul (string, &endptr, 0);
594 if (endptr != string) /* parsed a number */
595 return ret;
596
597 fclass = g_type_class_ref (type);
598
599
600 flagstr = g_strdup (string);
601 for (ret = i = j = 0;; i++)
602 {
603 gboolean eos;
604
605 eos = flagstr[i] == '\0';
606
607 if (eos || flagstr[i] == '|')
608 {
609 GFlagsValue *fv;
610 const char *flag;
611 gunichar ch;
612
613 flag = &flagstr[j];
614 endptr = &flagstr[i];
615
616 if (!eos)
617 {
618 flagstr[i++] = '\0';
619 j = i;
620 }
621
622 /* trim spaces */
623 for (;;)
624 {
625 ch = g_utf8_get_char (flag);
626 if (!g_unichar_isspace (ch))
627 break;
628 flag = g_utf8_next_char (flag);
629 }
630
631 while (endptr > flag)
632 {
633 prevptr = g_utf8_prev_char (endptr);
634 ch = g_utf8_get_char (prevptr);
635 if (!g_unichar_isspace (ch))
636 break;
637 endptr = prevptr;
638 }
639
640 if (endptr > flag)
641 {
642 *endptr = '\0';
643 fv = g_flags_get_value_by_name (fclass, flag);
644
645 if (!fv)
646 fv = g_flags_get_value_by_nick (fclass, flag);
647
648 if (fv)
649 ret |= fv->value;
650 else
651 g_warning ("Unknown flag: '%s'", flag);
652 }
653
654 if (eos)
655 break;
656 }
657 }
658
659 g_free (flagstr);
660
661 g_type_class_unref (fclass);
662
663 return ret;
664 }
665
666 /* This is copied exactly from libglade. I've just renamed the function.
667 */
668 static gint
glade_property_class_make_enum_from_string(GType type,const char * string)669 glade_property_class_make_enum_from_string (GType type, const char *string)
670 {
671 GEnumClass *eclass;
672 GEnumValue *ev;
673 gchar *endptr;
674 gint ret = 0;
675
676 ret = strtoul (string, &endptr, 0);
677 if (endptr != string) /* parsed a number */
678 return ret;
679
680 eclass = g_type_class_ref (type);
681 ev = g_enum_get_value_by_name (eclass, string);
682 if (!ev)
683 ev = g_enum_get_value_by_nick (eclass, string);
684 if (ev)
685 ret = ev->value;
686
687 g_type_class_unref (eclass);
688
689 return ret;
690 }
691
692 static GObject *
glade_property_class_make_object_from_string(GladePropertyClass * property_class,const gchar * string,GladeProject * project)693 glade_property_class_make_object_from_string (GladePropertyClass *
694 property_class,
695 const gchar * string,
696 GladeProject * project)
697 {
698 GObject *object = NULL;
699 gchar *fullpath;
700
701 if (string == NULL)
702 return NULL;
703
704 if (property_class->pspec->value_type == GDK_TYPE_PIXBUF && project)
705 {
706 GdkPixbuf *pixbuf;
707
708 if (*string == '\0')
709 return NULL;
710
711 fullpath = glade_project_resource_fullpath (project, string);
712
713 if ((pixbuf = gdk_pixbuf_new_from_file (fullpath, NULL)) == NULL)
714 {
715 GdkPixbuf *icon = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
716 "image-missing", 22, 0, NULL);
717 /* Use a copy, since gtk_icon_theme_load_icon() returns the same pixbuf */
718 pixbuf = gdk_pixbuf_copy (icon);
719 g_object_unref (icon);
720 }
721
722 if (pixbuf)
723 {
724 object = G_OBJECT (pixbuf);
725 g_object_set_data_full (object, "GladeFileName",
726 g_strdup (string), g_free);
727 }
728
729 g_free (fullpath);
730 }
731 else if (project)
732 {
733 GladeWidget *gwidget;
734 if ((gwidget = glade_project_get_widget_by_name (project, string)) != NULL)
735 object = glade_widget_get_object (gwidget);
736 }
737
738 return object;
739 }
740
741 static GList *
glade_property_class_make_objects_from_string(GladePropertyClass * property_class,const gchar * string,GladeProject * project)742 glade_property_class_make_objects_from_string (GladePropertyClass *
743 property_class,
744 const gchar * string,
745 GladeProject * project)
746 {
747 GList *objects = NULL;
748 GObject *object;
749 gchar **split;
750 guint i;
751
752 if ((split = g_strsplit (string, GPC_OBJECT_DELIMITER, 0)) != NULL)
753 {
754 for (i = 0; split[i]; i++)
755 {
756 if ((object =
757 glade_property_class_make_object_from_string (property_class,
758 split[i],
759 project)) != NULL)
760 objects = g_list_prepend (objects, object);
761 }
762 g_strfreev (split);
763 }
764 return g_list_reverse (objects);
765 }
766
767 /**
768 * glade_property_class_make_gvalue_from_string:
769 * @property_class: A #GladePropertyClass
770 * @string: a string representation of this property
771 * @project: the #GladeProject that the property should be resolved for
772 *
773 * Returns: A #GValue created based on the @property_class
774 * and @string criteria.
775 */
776 GValue *
glade_property_class_make_gvalue_from_string(GladePropertyClass * property_class,const gchar * string,GladeProject * project)777 glade_property_class_make_gvalue_from_string (GladePropertyClass *property_class,
778 const gchar *string,
779 GladeProject *project)
780 {
781 GValue *value = g_new0 (GValue, 1);
782 gchar **strv;
783 GdkColor color = { 0, };
784 GdkRGBA rgba = { 0, };
785
786 g_value_init (value, property_class->pspec->value_type);
787
788 if (G_IS_PARAM_SPEC_ENUM (property_class->pspec))
789 {
790 gint eval = glade_property_class_make_enum_from_string
791 (property_class->pspec->value_type, string);
792 g_value_set_enum (value, eval);
793 }
794 else if (G_IS_PARAM_SPEC_FLAGS (property_class->pspec))
795 {
796 guint flags = glade_property_class_make_flags_from_string
797 (property_class->pspec->value_type, string);
798 g_value_set_flags (value, flags);
799 }
800 else if (G_IS_PARAM_SPEC_VALUE_ARRAY (property_class->pspec))
801 {
802 GValueArray *value_array;
803 GValue str_value = { 0, };
804 gint i;
805
806 /* Require deprecated code */
807 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
808 value_array = g_value_array_new (0);
809 G_GNUC_END_IGNORE_DEPRECATIONS;
810
811 g_value_init (&str_value, G_TYPE_STRING);
812 strv = g_strsplit (string, "\n", 0);
813
814 for (i = 0; strv[i]; i++)
815 {
816 g_value_set_static_string (&str_value, strv[i]);
817
818 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
819 value_array = g_value_array_append (value_array, &str_value);
820 G_GNUC_END_IGNORE_DEPRECATIONS;
821 }
822 g_value_take_boxed (value, value_array);
823 g_strfreev (strv);
824 }
825 else if (G_IS_PARAM_SPEC_BOXED (property_class->pspec))
826 {
827 if (property_class->pspec->value_type == GDK_TYPE_COLOR)
828 {
829 if (gdk_color_parse (string, &color))
830 g_value_set_boxed (value, &color);
831 else
832 g_warning ("could not parse colour name `%s'", string);
833 }
834 else if (property_class->pspec->value_type == GDK_TYPE_RGBA)
835 {
836 if (gdk_rgba_parse (&rgba, string))
837 g_value_set_boxed (value, &rgba);
838 else
839 g_warning ("could not parse rgba colour name `%s'", string);
840 }
841 else if (property_class->pspec->value_type == G_TYPE_STRV)
842 {
843 strv = g_strsplit (string, "\n", 0);
844 g_value_take_boxed (value, strv);
845 }
846 }
847 else if (G_IS_PARAM_SPEC_INT (property_class->pspec))
848 g_value_set_int (value, g_ascii_strtoll (string, NULL, 10));
849 else if (G_IS_PARAM_SPEC_UINT (property_class->pspec))
850 g_value_set_uint (value, g_ascii_strtoull (string, NULL, 10));
851 else if (G_IS_PARAM_SPEC_LONG (property_class->pspec))
852 g_value_set_long (value, g_ascii_strtoll (string, NULL, 10));
853 else if (G_IS_PARAM_SPEC_ULONG (property_class->pspec))
854 g_value_set_ulong (value, g_ascii_strtoull (string, NULL, 10));
855 else if (G_IS_PARAM_SPEC_INT64 (property_class->pspec))
856 g_value_set_int64 (value, g_ascii_strtoll (string, NULL, 10));
857 else if (G_IS_PARAM_SPEC_UINT64 (property_class->pspec))
858 g_value_set_uint64 (value, g_ascii_strtoull (string, NULL, 10));
859 else if (G_IS_PARAM_SPEC_FLOAT (property_class->pspec))
860 g_value_set_float (value, (float) g_ascii_strtod (string, NULL));
861 else if (G_IS_PARAM_SPEC_DOUBLE (property_class->pspec))
862 g_value_set_double (value, g_ascii_strtod (string, NULL));
863 else if (G_IS_PARAM_SPEC_STRING (property_class->pspec))
864 g_value_set_string (value, string);
865 else if (G_IS_PARAM_SPEC_CHAR (property_class->pspec))
866 g_value_set_schar (value, string[0]);
867 else if (G_IS_PARAM_SPEC_UCHAR (property_class->pspec))
868 g_value_set_uchar (value, string[0]);
869 else if (G_IS_PARAM_SPEC_UNICHAR (property_class->pspec))
870 g_value_set_uint (value, g_utf8_get_char (string));
871 else if (G_IS_PARAM_SPEC_BOOLEAN (property_class->pspec))
872 {
873 gboolean val;
874 if (glade_utils_boolean_from_string (string, &val))
875 g_value_set_boolean (value, FALSE);
876 else
877 g_value_set_boolean (value, val);
878
879 }
880 else if (G_IS_PARAM_SPEC_OBJECT (property_class->pspec))
881 {
882 GObject *object =
883 glade_property_class_make_object_from_string (property_class, string, project);
884 g_value_set_object (value, object);
885 }
886 else if (GLADE_IS_PARAM_SPEC_OBJECTS (property_class->pspec))
887 {
888 GList *objects =
889 glade_property_class_make_objects_from_string (property_class, string, project);
890 g_value_take_boxed (value, objects);
891 }
892 else
893 g_critical ("Unsupported pspec type %s (string -> value)",
894 g_type_name (G_PARAM_SPEC_TYPE (property_class->pspec)));
895
896 return value;
897 }
898
899 /**
900 * glade_property_class_make_gvalue_from_vl:
901 * @property_class: A #GladePropertyClass
902 * @vl: a #va_list holding one argument of the correct type
903 * specified by @property_class
904 *
905 * Returns: A #GValue created based on the @property_class
906 * and a @vl arg of the correct type.
907 */
908 GValue *
glade_property_class_make_gvalue_from_vl(GladePropertyClass * klass,va_list vl)909 glade_property_class_make_gvalue_from_vl (GladePropertyClass * klass,
910 va_list vl)
911 {
912 GValue *value;
913
914 g_return_val_if_fail (klass != NULL, NULL);
915
916 value = g_new0 (GValue, 1);
917 g_value_init (value, klass->pspec->value_type);
918
919 if (G_IS_PARAM_SPEC_ENUM (klass->pspec))
920 g_value_set_enum (value, va_arg (vl, gint));
921 else if (G_IS_PARAM_SPEC_FLAGS (klass->pspec))
922 g_value_set_flags (value, va_arg (vl, gint));
923 else if (G_IS_PARAM_SPEC_INT (klass->pspec))
924 g_value_set_int (value, va_arg (vl, gint));
925 else if (G_IS_PARAM_SPEC_UINT (klass->pspec))
926 g_value_set_uint (value, va_arg (vl, guint));
927 else if (G_IS_PARAM_SPEC_LONG (klass->pspec))
928 g_value_set_long (value, va_arg (vl, glong));
929 else if (G_IS_PARAM_SPEC_ULONG (klass->pspec))
930 g_value_set_ulong (value, va_arg (vl, gulong));
931 else if (G_IS_PARAM_SPEC_INT64 (klass->pspec))
932 g_value_set_int64 (value, va_arg (vl, gint64));
933 else if (G_IS_PARAM_SPEC_UINT64 (klass->pspec))
934 g_value_set_uint64 (value, va_arg (vl, guint64));
935 else if (G_IS_PARAM_SPEC_FLOAT (klass->pspec))
936 g_value_set_float (value, (gfloat) va_arg (vl, gdouble));
937 else if (G_IS_PARAM_SPEC_DOUBLE (klass->pspec))
938 g_value_set_double (value, va_arg (vl, gdouble));
939 else if (G_IS_PARAM_SPEC_STRING (klass->pspec))
940 g_value_set_string (value, va_arg (vl, gchar *));
941 else if (G_IS_PARAM_SPEC_CHAR (klass->pspec))
942 g_value_set_schar (value, (gchar) va_arg (vl, gint));
943 else if (G_IS_PARAM_SPEC_UCHAR (klass->pspec))
944 g_value_set_uchar (value, (guchar) va_arg (vl, guint));
945 else if (G_IS_PARAM_SPEC_UNICHAR (klass->pspec))
946 g_value_set_uint (value, va_arg (vl, gunichar));
947 else if (G_IS_PARAM_SPEC_BOOLEAN (klass->pspec))
948 g_value_set_boolean (value, va_arg (vl, gboolean));
949 else if (G_IS_PARAM_SPEC_OBJECT (klass->pspec))
950 g_value_set_object (value, va_arg (vl, gpointer));
951 else if (G_VALUE_HOLDS_BOXED (value))
952 g_value_set_boxed (value, va_arg (vl, gpointer));
953 else
954 g_critical ("Unsupported pspec type %s (vl -> string)",
955 g_type_name (G_PARAM_SPEC_TYPE (klass->pspec)));
956
957 return value;
958 }
959
960 /**
961 * glade_property_class_make_gvalue:
962 * @klass: A #GladePropertyClass
963 * @...: an argument of the correct type specified by @property_class
964 *
965 * Returns: A #GValue created based on the @property_class
966 * and the provided argument.
967 */
968 GValue *
glade_property_class_make_gvalue(GladePropertyClass * klass,...)969 glade_property_class_make_gvalue (GladePropertyClass * klass, ...)
970 {
971 GValue *value;
972 va_list vl;
973
974 g_return_val_if_fail (klass != NULL, NULL);
975
976 va_start (vl, klass);
977 value = glade_property_class_make_gvalue_from_vl (klass, vl);
978 va_end (vl);
979
980 return value;
981 }
982
983
984 /**
985 * glade_property_class_set_vl_from_gvalue:
986 * @klass: A #GladePropertyClass
987 * @value: A #GValue to set
988 * @vl: a #va_list holding one argument of the correct type
989 * specified by @klass
990 *
991 *
992 * Sets @vl from @value based on @klass criteria.
993 */
994 void
glade_property_class_set_vl_from_gvalue(GladePropertyClass * klass,GValue * value,va_list vl)995 glade_property_class_set_vl_from_gvalue (GladePropertyClass * klass,
996 GValue * value, va_list vl)
997 {
998 g_return_if_fail (klass != NULL);
999 g_return_if_fail (value != NULL);
1000
1001 /* The argument is a pointer of the specified type, cast the pointer and assign
1002 * the value using the proper g_value_get_ variation.
1003 */
1004 if (G_IS_PARAM_SPEC_ENUM (klass->pspec))
1005 *(gint *) (va_arg (vl, gint *)) = g_value_get_enum (value);
1006 else if (G_IS_PARAM_SPEC_FLAGS (klass->pspec))
1007 *(gint *) (va_arg (vl, gint *)) = g_value_get_flags (value);
1008 else if (G_IS_PARAM_SPEC_INT (klass->pspec))
1009 *(gint *) (va_arg (vl, gint *)) = g_value_get_int (value);
1010 else if (G_IS_PARAM_SPEC_UINT (klass->pspec))
1011 *(guint *) (va_arg (vl, guint *)) = g_value_get_uint (value);
1012 else if (G_IS_PARAM_SPEC_LONG (klass->pspec))
1013 *(glong *) (va_arg (vl, glong *)) = g_value_get_long (value);
1014 else if (G_IS_PARAM_SPEC_ULONG (klass->pspec))
1015 *(gulong *) (va_arg (vl, gulong *)) = g_value_get_ulong (value);
1016 else if (G_IS_PARAM_SPEC_INT64 (klass->pspec))
1017 *(gint64 *) (va_arg (vl, gint64 *)) = g_value_get_int64 (value);
1018 else if (G_IS_PARAM_SPEC_UINT64 (klass->pspec))
1019 *(guint64 *) (va_arg (vl, guint64 *)) = g_value_get_uint64 (value);
1020 else if (G_IS_PARAM_SPEC_FLOAT (klass->pspec))
1021 *(gfloat *) (va_arg (vl, gdouble *)) = g_value_get_float (value);
1022 else if (G_IS_PARAM_SPEC_DOUBLE (klass->pspec))
1023 *(gdouble *) (va_arg (vl, gdouble *)) = g_value_get_double (value);
1024 else if (G_IS_PARAM_SPEC_STRING (klass->pspec))
1025 *(gchar **) (va_arg (vl, gchar *)) = (gchar *) g_value_get_string (value);
1026 else if (G_IS_PARAM_SPEC_CHAR (klass->pspec))
1027 *(gchar *) (va_arg (vl, gint *)) = g_value_get_schar (value);
1028 else if (G_IS_PARAM_SPEC_UCHAR (klass->pspec))
1029 *(guchar *) (va_arg (vl, guint *)) = g_value_get_uchar (value);
1030 else if (G_IS_PARAM_SPEC_UNICHAR (klass->pspec))
1031 *(guint *) (va_arg (vl, gunichar *)) = g_value_get_uint (value);
1032 else if (G_IS_PARAM_SPEC_BOOLEAN (klass->pspec))
1033 *(gboolean *) (va_arg (vl, gboolean *)) = g_value_get_boolean (value);
1034 else if (G_IS_PARAM_SPEC_OBJECT (klass->pspec))
1035 *(gpointer *) (va_arg (vl, gpointer *)) = g_value_get_object (value);
1036 else if (G_VALUE_HOLDS_BOXED (value))
1037 *(gpointer *) (va_arg (vl, gpointer *)) = g_value_get_boxed (value);
1038 else
1039 g_critical ("Unsupported pspec type %s (string -> vl)",
1040 g_type_name (G_PARAM_SPEC_TYPE (klass->pspec)));
1041 }
1042
1043 /**
1044 * glade_property_class_get_from_gvalue:
1045 * @klass: A #GladePropertyClass
1046 * @value: A #GValue to set
1047 * @...: a return location of the correct type
1048 *
1049 *
1050 * Assignes the provided return location to @value
1051 */
1052 void
glade_property_class_get_from_gvalue(GladePropertyClass * klass,GValue * value,...)1053 glade_property_class_get_from_gvalue (GladePropertyClass * klass,
1054 GValue * value, ...)
1055 {
1056 va_list vl;
1057
1058 g_return_if_fail (klass != NULL);
1059
1060 va_start (vl, value);
1061 glade_property_class_set_vl_from_gvalue (klass, value, vl);
1062 va_end (vl);
1063 }
1064
1065
1066 /* "need_adaptor": An evil trick to let us create pclasses without
1067 * adaptors and editors.
1068 */
1069 GladePropertyClass *
glade_property_class_new_from_spec_full(GladeWidgetAdaptor * adaptor,GParamSpec * spec,gboolean need_adaptor)1070 glade_property_class_new_from_spec_full (GladeWidgetAdaptor *adaptor,
1071 GParamSpec *spec,
1072 gboolean need_adaptor)
1073 {
1074 GObjectClass *gtk_widget_class;
1075 GladePropertyClass *property_class;
1076 GladeEditorProperty *eprop = NULL;
1077
1078 g_return_val_if_fail (spec != NULL, NULL);
1079 gtk_widget_class = g_type_class_ref (GTK_TYPE_WIDGET);
1080
1081 /* Only properties that are _new_from_spec() are
1082 * not virtual properties
1083 */
1084 property_class = glade_property_class_new (adaptor, spec->name);
1085 property_class->virt = FALSE;
1086 property_class->pspec = spec;
1087
1088 /* We only use the writable properties */
1089 if ((spec->flags & G_PARAM_WRITABLE) == 0)
1090 goto failed;
1091
1092 property_class->name = g_strdup (g_param_spec_get_nick (spec));
1093
1094 /* Register only editable properties.
1095 */
1096 if (need_adaptor && !(eprop = glade_widget_adaptor_create_eprop
1097 (GLADE_WIDGET_ADAPTOR (adaptor), property_class, FALSE)))
1098 goto failed;
1099
1100 /* Just created it to see if it was supported.... destroy now... */
1101 if (eprop)
1102 gtk_widget_destroy (GTK_WIDGET (eprop));
1103
1104 /* If its on the GtkWidgetClass, it goes in "common"
1105 * (unless stipulated otherwise in the xml file)
1106 */
1107 if (g_object_class_find_property (gtk_widget_class,
1108 g_param_spec_get_name (spec)) != NULL)
1109 property_class->common = TRUE;
1110
1111 /* Flag the construct only properties */
1112 if (spec->flags & G_PARAM_CONSTRUCT_ONLY)
1113 property_class->construct_only = TRUE;
1114
1115 if (!property_class->id || !property_class->name)
1116 {
1117 g_critical ("No name or id for "
1118 "glade_property_class_new_from_spec, failed.");
1119 goto failed;
1120 }
1121
1122 property_class->tooltip = g_strdup (g_param_spec_get_blurb (spec));
1123 property_class->orig_def = glade_property_class_get_default_from_spec (spec);
1124 property_class->def = glade_property_class_get_default_from_spec (spec);
1125
1126 g_type_class_unref (gtk_widget_class);
1127 return property_class;
1128
1129 failed:
1130 glade_property_class_free (property_class);
1131 g_type_class_unref (gtk_widget_class);
1132 return NULL;
1133 }
1134
1135 /**
1136 * glade_property_class_new_from_spec:
1137 * @adaptor: A generic pointer (i.e. a #GladeWidgetClass)
1138 * @spec: A #GParamSpec
1139 *
1140 * Returns: a newly created #GladePropertyClass based on @spec
1141 * or %NULL if its unsupported.
1142 */
1143 GladePropertyClass *
glade_property_class_new_from_spec(GladeWidgetAdaptor * adaptor,GParamSpec * spec)1144 glade_property_class_new_from_spec (GladeWidgetAdaptor *adaptor, GParamSpec * spec)
1145 {
1146 return glade_property_class_new_from_spec_full (adaptor, spec, TRUE);
1147 }
1148
1149 /**
1150 * glade_property_class_is_visible:
1151 * @property_class: A #GladePropertyClass
1152 *
1153 *
1154 * Returns: whether or not to show this property in the editor
1155 */
1156 gboolean
glade_property_class_is_visible(GladePropertyClass * klass)1157 glade_property_class_is_visible (GladePropertyClass * klass)
1158 {
1159 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (klass), FALSE);
1160
1161 return klass->visible;
1162 }
1163
1164 void
glade_property_class_set_adaptor(GladePropertyClass * property_class,GladeWidgetAdaptor * adaptor)1165 glade_property_class_set_adaptor (GladePropertyClass *property_class,
1166 GladeWidgetAdaptor *adaptor)
1167 {
1168 g_return_if_fail (GLADE_IS_PROPERTY_CLASS (property_class));
1169
1170 property_class->adaptor = adaptor;
1171 }
1172
1173 GladeWidgetAdaptor *
glade_property_class_get_adaptor(GladePropertyClass * property_class)1174 glade_property_class_get_adaptor (GladePropertyClass *property_class)
1175 {
1176 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), NULL);
1177
1178 return property_class->adaptor;
1179 }
1180
1181 GParamSpec *
glade_property_class_get_pspec(GladePropertyClass * property_class)1182 glade_property_class_get_pspec (GladePropertyClass *property_class)
1183 {
1184 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), NULL);
1185
1186 return property_class->pspec;
1187 }
1188
1189 void
glade_property_class_set_pspec(GladePropertyClass * property_class,GParamSpec * pspec)1190 glade_property_class_set_pspec (GladePropertyClass *property_class,
1191 GParamSpec *pspec)
1192 {
1193 g_return_if_fail (GLADE_IS_PROPERTY_CLASS (property_class));
1194
1195 property_class->pspec = pspec;
1196 }
1197
1198 void
glade_property_class_set_is_packing(GladePropertyClass * property_class,gboolean is_packing)1199 glade_property_class_set_is_packing (GladePropertyClass *property_class,
1200 gboolean is_packing)
1201 {
1202 g_return_if_fail (GLADE_IS_PROPERTY_CLASS (property_class));
1203
1204 property_class->packing = is_packing;
1205 }
1206
1207 gboolean
glade_property_class_get_is_packing(GladePropertyClass * property_class)1208 glade_property_class_get_is_packing (GladePropertyClass *property_class)
1209 {
1210 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), FALSE);
1211
1212 return property_class->packing;
1213 }
1214
1215 gboolean
glade_property_class_save(GladePropertyClass * property_class)1216 glade_property_class_save (GladePropertyClass *property_class)
1217 {
1218 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), FALSE);
1219
1220 return property_class->save;
1221 }
1222
1223 gboolean
glade_property_class_save_always(GladePropertyClass * property_class)1224 glade_property_class_save_always (GladePropertyClass *property_class)
1225 {
1226 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), FALSE);
1227
1228 return property_class->save_always;
1229 }
1230
1231 void
glade_property_class_set_virtual(GladePropertyClass * property_class,gboolean value)1232 glade_property_class_set_virtual (GladePropertyClass *property_class,
1233 gboolean value)
1234 {
1235 g_return_if_fail (GLADE_IS_PROPERTY_CLASS (property_class));
1236
1237 property_class->virt = value;
1238 }
1239
1240 gboolean
glade_property_class_get_virtual(GladePropertyClass * property_class)1241 glade_property_class_get_virtual (GladePropertyClass *property_class)
1242 {
1243 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), FALSE);
1244
1245 return property_class->virt;
1246 }
1247
1248 void
glade_property_class_set_ignore(GladePropertyClass * property_class,gboolean ignore)1249 glade_property_class_set_ignore (GladePropertyClass *property_class,
1250 gboolean ignore)
1251 {
1252 g_return_if_fail (GLADE_IS_PROPERTY_CLASS (property_class));
1253
1254 property_class->ignore = ignore;
1255 }
1256
1257 gboolean
glade_property_class_get_ignore(GladePropertyClass * property_class)1258 glade_property_class_get_ignore (GladePropertyClass *property_class)
1259 {
1260 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), FALSE);
1261
1262 return property_class->ignore;
1263 }
1264
1265 /**
1266 * glade_property_class_is_object:
1267 * @property_class: A #GladePropertyClass
1268 *
1269 * Returns: whether or not this is an object property
1270 * that refers to another object in this project.
1271 */
1272 gboolean
glade_property_class_is_object(GladePropertyClass * klass)1273 glade_property_class_is_object (GladePropertyClass * klass)
1274 {
1275 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (klass), FALSE);
1276
1277 return (GLADE_IS_PARAM_SPEC_OBJECTS (klass->pspec) ||
1278 (G_IS_PARAM_SPEC_OBJECT (klass->pspec) &&
1279 klass->pspec->value_type != GDK_TYPE_PIXBUF));
1280 }
1281
1282 void
glade_property_class_set_name(GladePropertyClass * property_class,const gchar * name)1283 glade_property_class_set_name (GladePropertyClass *property_class,
1284 const gchar *name)
1285 {
1286 g_return_if_fail (GLADE_IS_PROPERTY_CLASS (property_class));
1287
1288 g_free (property_class->name);
1289 property_class->name = g_strdup (name);
1290 }
1291
1292 G_CONST_RETURN gchar *
glade_property_class_get_name(GladePropertyClass * property_class)1293 glade_property_class_get_name (GladePropertyClass *property_class)
1294 {
1295 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), NULL);
1296
1297 return property_class->name;
1298 }
1299
1300 void
glade_property_class_set_tooltip(GladePropertyClass * property_class,const gchar * tooltip)1301 glade_property_class_set_tooltip (GladePropertyClass *property_class,
1302 const gchar *tooltip)
1303 {
1304 g_return_if_fail (GLADE_IS_PROPERTY_CLASS (property_class));
1305
1306 g_free (property_class->tooltip);
1307 property_class->tooltip = g_strdup (tooltip);
1308 }
1309
1310 G_CONST_RETURN gchar *
glade_property_class_get_tooltip(GladePropertyClass * property_class)1311 glade_property_class_get_tooltip (GladePropertyClass *property_class)
1312 {
1313 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), NULL);
1314
1315 return property_class->tooltip;
1316 }
1317
1318 void
glade_property_class_set_construct_only(GladePropertyClass * property_class,gboolean construct_only)1319 glade_property_class_set_construct_only (GladePropertyClass *property_class,
1320 gboolean construct_only)
1321 {
1322 g_return_if_fail (GLADE_IS_PROPERTY_CLASS (property_class));
1323
1324 property_class->construct_only = construct_only;
1325 }
1326
1327 gboolean
glade_property_class_get_construct_only(GladePropertyClass * property_class)1328 glade_property_class_get_construct_only (GladePropertyClass *property_class)
1329 {
1330 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), FALSE);
1331
1332 return property_class->construct_only;
1333 }
1334
1335 G_CONST_RETURN GValue *
glade_property_class_get_default(GladePropertyClass * property_class)1336 glade_property_class_get_default (GladePropertyClass *property_class)
1337 {
1338 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), NULL);
1339
1340 return property_class->def;
1341 }
1342
1343 G_CONST_RETURN GValue *
glade_property_class_get_original_default(GladePropertyClass * property_class)1344 glade_property_class_get_original_default (GladePropertyClass *property_class)
1345 {
1346 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), NULL);
1347
1348 return property_class->orig_def;
1349 }
1350
1351 gboolean
glade_property_class_translatable(GladePropertyClass * property_class)1352 glade_property_class_translatable (GladePropertyClass *property_class)
1353 {
1354 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), FALSE);
1355
1356 return property_class->translatable;
1357 }
1358
1359 gboolean
glade_property_class_needs_sync(GladePropertyClass * property_class)1360 glade_property_class_needs_sync (GladePropertyClass *property_class)
1361 {
1362 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), FALSE);
1363
1364 return property_class->needs_sync;
1365 }
1366
1367 gboolean
glade_property_class_query(GladePropertyClass * property_class)1368 glade_property_class_query (GladePropertyClass *property_class)
1369 {
1370 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), FALSE);
1371
1372 return property_class->query;
1373 }
1374
1375 gboolean
glade_property_class_atk(GladePropertyClass * property_class)1376 glade_property_class_atk (GladePropertyClass *property_class)
1377 {
1378 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), FALSE);
1379
1380 return property_class->atk;
1381 }
1382
1383 gboolean
glade_property_class_common(GladePropertyClass * property_class)1384 glade_property_class_common (GladePropertyClass *property_class)
1385 {
1386 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), FALSE);
1387
1388 return property_class->common;
1389 }
1390
1391 gboolean
glade_property_class_parentless_widget(GladePropertyClass * property_class)1392 glade_property_class_parentless_widget (GladePropertyClass *property_class)
1393 {
1394 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), FALSE);
1395
1396 return property_class->parentless_widget;
1397 }
1398
1399 gboolean
glade_property_class_optional(GladePropertyClass * property_class)1400 glade_property_class_optional (GladePropertyClass *property_class)
1401 {
1402 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), FALSE);
1403
1404 return property_class->optional;
1405 }
1406
1407 gboolean
glade_property_class_optional_default(GladePropertyClass * property_class)1408 glade_property_class_optional_default (GladePropertyClass *property_class)
1409 {
1410 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), FALSE);
1411
1412 return property_class->optional_default;
1413 }
1414
1415 gboolean
glade_property_class_multiline(GladePropertyClass * property_class)1416 glade_property_class_multiline (GladePropertyClass *property_class)
1417 {
1418 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), FALSE);
1419
1420 return property_class->multiline;
1421 }
1422
1423 gboolean
glade_property_class_stock(GladePropertyClass * property_class)1424 glade_property_class_stock (GladePropertyClass *property_class)
1425 {
1426 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), FALSE);
1427
1428 return property_class->stock;
1429 }
1430
1431 gboolean
glade_property_class_stock_icon(GladePropertyClass * property_class)1432 glade_property_class_stock_icon (GladePropertyClass *property_class)
1433 {
1434 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), FALSE);
1435
1436 return property_class->stock_icon;
1437 }
1438
1439 gboolean
glade_property_class_transfer_on_paste(GladePropertyClass * property_class)1440 glade_property_class_transfer_on_paste (GladePropertyClass *property_class)
1441 {
1442 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), FALSE);
1443
1444 return property_class->transfer_on_paste;
1445 }
1446
1447 gboolean
glade_property_class_custom_layout(GladePropertyClass * property_class)1448 glade_property_class_custom_layout (GladePropertyClass *property_class)
1449 {
1450 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), FALSE);
1451
1452 return property_class->custom_layout;
1453 }
1454
1455 gdouble
glade_property_class_weight(GladePropertyClass * property_class)1456 glade_property_class_weight (GladePropertyClass *property_class)
1457 {
1458 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), -1.0);
1459
1460 return property_class->weight;
1461 }
1462
1463 G_CONST_RETURN gchar *
glade_property_class_create_type(GladePropertyClass * property_class)1464 glade_property_class_create_type (GladePropertyClass *property_class)
1465 {
1466 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), NULL);
1467
1468 return property_class->create_type;
1469 }
1470
1471 guint16
glade_property_class_since_major(GladePropertyClass * property_class)1472 glade_property_class_since_major (GladePropertyClass *property_class)
1473 {
1474 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), 0);
1475
1476 return property_class->version_since_major;
1477 }
1478
1479 guint16
glade_property_class_since_minor(GladePropertyClass * property_class)1480 glade_property_class_since_minor (GladePropertyClass *property_class)
1481 {
1482 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), 0);
1483
1484 return property_class->version_since_minor;
1485 }
1486
1487 gboolean
glade_property_class_deprecated(GladePropertyClass * property_class)1488 glade_property_class_deprecated (GladePropertyClass *property_class)
1489 {
1490 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), FALSE);
1491
1492 return property_class->deprecated;
1493 }
1494
1495 G_CONST_RETURN gchar *
glade_property_class_id(GladePropertyClass * property_class)1496 glade_property_class_id (GladePropertyClass *property_class)
1497 {
1498 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), NULL);
1499
1500 return property_class->id;
1501 }
1502
1503 gboolean
glade_property_class_themed_icon(GladePropertyClass * property_class)1504 glade_property_class_themed_icon (GladePropertyClass *property_class)
1505 {
1506 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (property_class), FALSE);
1507
1508 return property_class->themed_icon;
1509 }
1510
1511 /**
1512 * gpc_read_displayable_values_from_node:
1513 * @node: a GLADE_TAG_DISPLAYABLE_VALUES node
1514 * @values: an array of the values wich node overrides.
1515 * @n_values: the size of @values
1516 *
1517 * Reads and caches displayable values from the catalog
1518 */
1519 static void
gpc_read_displayable_values_from_node(GladeXmlNode * node,GladePropertyClass * klass,const gchar * domain)1520 gpc_read_displayable_values_from_node (GladeXmlNode * node,
1521 GladePropertyClass * klass,
1522 const gchar * domain)
1523 {
1524 gpointer the_class = g_type_class_ref (klass->pspec->value_type);
1525 GladeXmlNode *child;
1526 GEnumValue *enum_values = NULL;
1527 GFlagsValue *flags_values = NULL;
1528 gint n_values, registered_values = 0;
1529
1530 if (G_IS_PARAM_SPEC_ENUM (klass->pspec))
1531 {
1532 GEnumClass *eclass = the_class;
1533 enum_values = eclass->values;
1534 n_values = eclass->n_values;
1535 }
1536 else
1537 {
1538 GFlagsClass *fclass = the_class;
1539 flags_values = fclass->values;
1540 n_values = fclass->n_values;
1541 }
1542
1543 if ((child = glade_xml_search_child (node, GLADE_TAG_VALUE)) == NULL)
1544 return;
1545
1546 for (child = glade_xml_node_get_children (node); child; child = glade_xml_node_next (child))
1547 {
1548 gint i;
1549 gchar *id, *name;
1550 GEnumValue *enum_val;
1551 GFlagsValue *flags_val;
1552 gboolean disabled;
1553
1554 id = glade_xml_get_property_string_required (child, GLADE_TAG_ID, NULL);
1555 if (!id) continue;
1556
1557 disabled = glade_xml_get_property_boolean (child, GLADE_TAG_DISABLED, FALSE);
1558
1559 if (!disabled)
1560 {
1561 name = glade_xml_get_property_string_required (child, GLADE_TAG_NAME, NULL);
1562 if (!name) continue;
1563 }
1564 else
1565 name = NULL;
1566
1567 for (i = 0; i < n_values; i++)
1568 {
1569 /* is it a match ?? */
1570 if ((G_IS_PARAM_SPEC_ENUM (klass->pspec) &&
1571 (strcmp (id, enum_values[i].value_name) == 0 ||
1572 strcmp (id, enum_values[i].value_nick) == 0)) ||
1573 (G_IS_PARAM_SPEC_FLAGS (klass->pspec) &&
1574 (strcmp (id, flags_values[i].value_name) == 0 ||
1575 strcmp (id, flags_values[i].value_nick) == 0)))
1576 {
1577 registered_values++;
1578
1579 if (G_IS_PARAM_SPEC_ENUM (klass->pspec))
1580 {
1581 enum_val = &enum_values[i];
1582 glade_register_displayable_value (klass->pspec->value_type,
1583 enum_val->value_nick,
1584 domain, name);
1585 if (disabled)
1586 glade_displayable_value_set_disabled (klass->pspec->value_type,
1587 enum_val->value_nick,
1588 TRUE);
1589 }
1590 else
1591 {
1592 flags_val = &flags_values[i];
1593 glade_register_displayable_value (klass->pspec->value_type,
1594 flags_val->value_nick,
1595 domain, name);
1596 if (disabled)
1597 glade_displayable_value_set_disabled (klass->pspec->value_type,
1598 flags_val->value_nick,
1599 TRUE);
1600 }
1601 break;
1602 }
1603 }
1604
1605 g_free (id);
1606 g_free (name);
1607 }
1608
1609 if (n_values != registered_values)
1610 g_message ("%d missing displayable value for %s::%s",
1611 n_values - registered_values,
1612 glade_widget_adaptor_get_name (klass->adaptor), klass->id);
1613
1614 g_type_class_unref (the_class);
1615
1616 }
1617
1618 /**
1619 * glade_property_class_make_adjustment:
1620 * @property_class: a pointer to the property class
1621 *
1622 * Creates and appropriate GtkAdjustment for use in the editor
1623 *
1624 * Returns: An appropriate #GtkAdjustment for use in the Property editor
1625 */
1626 GtkAdjustment *
glade_property_class_make_adjustment(GladePropertyClass * property_class)1627 glade_property_class_make_adjustment (GladePropertyClass * property_class)
1628 {
1629 GtkAdjustment *adjustment;
1630 gdouble min = 0, max = 0, def = 0;
1631 gboolean float_range = FALSE;
1632
1633 g_return_val_if_fail (property_class != NULL, NULL);
1634 g_return_val_if_fail (property_class->pspec != NULL, NULL);
1635
1636 if (G_IS_PARAM_SPEC_INT (property_class->pspec))
1637 {
1638 min = (gdouble) ((GParamSpecInt *) property_class->pspec)->minimum;
1639 max = (gdouble) ((GParamSpecInt *) property_class->pspec)->maximum;
1640 def = (gdouble) ((GParamSpecInt *) property_class->pspec)->default_value;
1641 }
1642 else if (G_IS_PARAM_SPEC_UINT (property_class->pspec))
1643 {
1644 min = (gdouble) ((GParamSpecUInt *) property_class->pspec)->minimum;
1645 max = (gdouble) ((GParamSpecUInt *) property_class->pspec)->maximum;
1646 def = (gdouble) ((GParamSpecUInt *) property_class->pspec)->default_value;
1647 }
1648 else if (G_IS_PARAM_SPEC_LONG (property_class->pspec))
1649 {
1650 min = (gdouble) ((GParamSpecLong *) property_class->pspec)->minimum;
1651 max = (gdouble) ((GParamSpecLong *) property_class->pspec)->maximum;
1652 def = (gdouble) ((GParamSpecLong *) property_class->pspec)->default_value;
1653 }
1654 else if (G_IS_PARAM_SPEC_ULONG (property_class->pspec))
1655 {
1656 min = (gdouble) ((GParamSpecULong *) property_class->pspec)->minimum;
1657 max = (gdouble) ((GParamSpecULong *) property_class->pspec)->maximum;
1658 def =
1659 (gdouble) ((GParamSpecULong *) property_class->pspec)->default_value;
1660 }
1661 else if (G_IS_PARAM_SPEC_INT64 (property_class->pspec))
1662 {
1663 min = (gdouble) ((GParamSpecInt64 *) property_class->pspec)->minimum;
1664 max = (gdouble) ((GParamSpecInt64 *) property_class->pspec)->maximum;
1665 def =
1666 (gdouble) ((GParamSpecInt64 *) property_class->pspec)->default_value;
1667 }
1668 else if (G_IS_PARAM_SPEC_UINT64 (property_class->pspec))
1669 {
1670 min = (gdouble) ((GParamSpecUInt64 *) property_class->pspec)->minimum;
1671 max = (gdouble) ((GParamSpecUInt64 *) property_class->pspec)->maximum;
1672 def =
1673 (gdouble) ((GParamSpecUInt64 *) property_class->pspec)->default_value;
1674 }
1675 else if (G_IS_PARAM_SPEC_FLOAT (property_class->pspec))
1676 {
1677 float_range = TRUE;
1678 min = ((GParamSpecFloat *) property_class->pspec)->minimum;
1679 max = ((GParamSpecFloat *) property_class->pspec)->maximum;
1680 def = ((GParamSpecFloat *) property_class->pspec)->default_value;
1681 }
1682 else if (G_IS_PARAM_SPEC_DOUBLE (property_class->pspec))
1683 {
1684 float_range = TRUE;
1685 min = (gdouble) ((GParamSpecDouble *) property_class->pspec)->minimum;
1686 max = (gdouble) ((GParamSpecDouble *) property_class->pspec)->maximum;
1687 def =
1688 (gdouble) ((GParamSpecDouble *) property_class->pspec)->default_value;
1689 }
1690 else
1691 {
1692 g_critical ("Can't make adjustment for pspec type %s",
1693 g_type_name (G_PARAM_SPEC_TYPE (property_class->pspec)));
1694 }
1695
1696 adjustment = (GtkAdjustment *) gtk_adjustment_new (def, min, max,
1697 float_range ?
1698 FLOATING_STEP_INCREMENT :
1699 NUMERICAL_STEP_INCREMENT,
1700 float_range ?
1701 FLOATING_PAGE_INCREMENT :
1702 NUMERICAL_PAGE_INCREMENT,
1703 float_range ?
1704 FLOATING_PAGE_SIZE :
1705 NUMERICAL_PAGE_SIZE);
1706 return adjustment;
1707 }
1708
1709
1710 static GParamSpec *
glade_property_class_parse_specifications(GladePropertyClass * klass,GladeXmlNode * spec_node)1711 glade_property_class_parse_specifications (GladePropertyClass * klass,
1712 GladeXmlNode * spec_node)
1713 {
1714 gchar *string;
1715 GType spec_type = 0, value_type = 0;
1716 GParamSpec *pspec = NULL;
1717
1718 if ((string = glade_xml_get_value_string_required
1719 (spec_node, GLADE_TAG_TYPE,
1720 "Need a type of GParamSpec to define")) != NULL)
1721 spec_type = glade_util_get_type_from_name (string, FALSE);
1722
1723 g_free (string);
1724
1725 g_return_val_if_fail (spec_type != 0, NULL);
1726
1727 if (spec_type == G_TYPE_PARAM_ENUM ||
1728 spec_type == G_TYPE_PARAM_FLAGS ||
1729 spec_type == G_TYPE_PARAM_BOXED ||
1730 spec_type == G_TYPE_PARAM_OBJECT || spec_type == GLADE_TYPE_PARAM_OBJECTS)
1731 {
1732 if ((string = glade_xml_get_value_string_required
1733 (spec_node, GLADE_TAG_VALUE_TYPE,
1734 "Need a value type to define enums flags boxed and object specs"))
1735 != NULL)
1736 value_type = glade_util_get_type_from_name (string, FALSE);
1737
1738 g_free (string);
1739
1740 g_return_val_if_fail (value_type != 0, NULL);
1741
1742 if (spec_type == G_TYPE_PARAM_ENUM)
1743 {
1744 GEnumClass *eclass = g_type_class_ref (value_type);
1745 pspec = g_param_spec_enum ("dummy", "dummy", "dummy",
1746 value_type, eclass->minimum,
1747 G_PARAM_READABLE | G_PARAM_WRITABLE);
1748 g_type_class_unref (eclass);
1749 }
1750 else if (spec_type == G_TYPE_PARAM_FLAGS)
1751 pspec = g_param_spec_flags ("dummy", "dummy", "dummy",
1752 value_type, 0,
1753 G_PARAM_READABLE | G_PARAM_WRITABLE);
1754 else if (spec_type == G_TYPE_PARAM_OBJECT)
1755 pspec = g_param_spec_object ("dummy", "dummy", "dummy",
1756 value_type,
1757 G_PARAM_READABLE | G_PARAM_WRITABLE);
1758 else if (spec_type == GLADE_TYPE_PARAM_OBJECTS)
1759 pspec = glade_param_spec_objects ("dummy", "dummy", "dummy",
1760 value_type,
1761 G_PARAM_READABLE | G_PARAM_WRITABLE);
1762 else /* if (spec_type == G_TYPE_PARAM_BOXED) */
1763 pspec = g_param_spec_boxed ("dummy", "dummy", "dummy",
1764 value_type,
1765 G_PARAM_READABLE | G_PARAM_WRITABLE);
1766 }
1767 else if (spec_type == G_TYPE_PARAM_STRING)
1768 pspec = g_param_spec_string ("dummy", "dummy", "dummy",
1769 NULL, G_PARAM_READABLE | G_PARAM_WRITABLE);
1770 else if (spec_type == G_TYPE_PARAM_BOOLEAN)
1771 pspec = g_param_spec_boolean ("dummy", "dummy", "dummy",
1772 FALSE, G_PARAM_READABLE | G_PARAM_WRITABLE);
1773 else
1774 {
1775 gchar *minstr, *maxstr;
1776
1777 minstr = glade_xml_get_value_string (spec_node, GLADE_TAG_MIN_VALUE);
1778 maxstr = glade_xml_get_value_string (spec_node, GLADE_TAG_MAX_VALUE);
1779
1780 if (spec_type == G_TYPE_PARAM_CHAR)
1781 {
1782 gint8 min = minstr ? minstr[0] : G_MININT8;
1783 gint8 max = maxstr ? maxstr[0] : G_MAXINT8;
1784
1785 pspec = g_param_spec_char ("dummy", "dummy", "dummy",
1786 min, max, CLAMP (0, min, max),
1787 G_PARAM_READABLE | G_PARAM_WRITABLE);
1788 }
1789 else if (spec_type == G_TYPE_PARAM_UCHAR)
1790 {
1791 guint8 min = minstr ? minstr[0] : 0;
1792 guint8 max = maxstr ? maxstr[0] : G_MAXUINT8;
1793
1794 pspec = g_param_spec_uchar ("dummy", "dummy", "dummy",
1795 min, max, 0,
1796 G_PARAM_READABLE | G_PARAM_WRITABLE);
1797 }
1798 else if (spec_type == G_TYPE_PARAM_INT)
1799 {
1800 gint min = minstr ? g_ascii_strtoll (minstr, NULL, 10) : G_MININT;
1801 gint max = maxstr ? g_ascii_strtoll (maxstr, NULL, 10) : G_MAXINT;
1802
1803 pspec = g_param_spec_int ("dummy", "dummy", "dummy",
1804 min, max, CLAMP (0, min, max),
1805 G_PARAM_READABLE | G_PARAM_WRITABLE);
1806 }
1807 else if (spec_type == G_TYPE_PARAM_UINT)
1808 {
1809 guint min = minstr ? g_ascii_strtoll (minstr, NULL, 10) : 0;
1810 guint max = maxstr ? g_ascii_strtoll (maxstr, NULL, 10) : G_MAXUINT;
1811
1812 pspec = g_param_spec_uint ("dummy", "dummy", "dummy",
1813 min, max, CLAMP (0, min, max),
1814 G_PARAM_READABLE | G_PARAM_WRITABLE);
1815 }
1816 else if (spec_type == G_TYPE_PARAM_LONG)
1817 {
1818 glong min = minstr ? g_ascii_strtoll (minstr, NULL, 10) : G_MINLONG;
1819 glong max = maxstr ? g_ascii_strtoll (maxstr, NULL, 10) : G_MAXLONG;
1820
1821 pspec = g_param_spec_long ("dummy", "dummy", "dummy",
1822 min, max, CLAMP (0, min, max),
1823 G_PARAM_READABLE | G_PARAM_WRITABLE);
1824 }
1825 else if (spec_type == G_TYPE_PARAM_ULONG)
1826 {
1827 gulong min = minstr ? g_ascii_strtoll (minstr, NULL, 10) : 0;
1828 gulong max = maxstr ? g_ascii_strtoll (maxstr, NULL, 10) : G_MAXULONG;
1829
1830 pspec = g_param_spec_ulong ("dummy", "dummy", "dummy",
1831 min, max, CLAMP (0, min, max),
1832 G_PARAM_READABLE | G_PARAM_WRITABLE);
1833 }
1834 else if (spec_type == G_TYPE_PARAM_INT64)
1835 {
1836 gint64 min = minstr ? g_ascii_strtoll (minstr, NULL, 10) : G_MININT64;
1837 gint64 max = maxstr ? g_ascii_strtoll (maxstr, NULL, 10) : G_MAXINT64;
1838
1839 pspec = g_param_spec_int64 ("dummy", "dummy", "dummy",
1840 min, max, CLAMP (0, min, max),
1841 G_PARAM_READABLE | G_PARAM_WRITABLE);
1842 }
1843 else if (spec_type == G_TYPE_PARAM_UINT64)
1844 {
1845 guint64 min = minstr ? g_ascii_strtoll (minstr, NULL, 10) : 0;
1846 guint64 max =
1847 maxstr ? g_ascii_strtoll (maxstr, NULL, 10) : G_MAXUINT64;
1848
1849 pspec = g_param_spec_uint64 ("dummy", "dummy", "dummy",
1850 min, max, CLAMP (0, min, max),
1851 G_PARAM_READABLE | G_PARAM_WRITABLE);
1852 }
1853 else if (spec_type == G_TYPE_PARAM_FLOAT)
1854 {
1855 gfloat min =
1856 minstr ? (float) g_ascii_strtod (minstr, NULL) : G_MINFLOAT;
1857 gfloat max =
1858 maxstr ? (float) g_ascii_strtod (maxstr, NULL) : G_MAXFLOAT;
1859
1860 pspec = g_param_spec_float ("dummy", "dummy", "dummy",
1861 min, max, CLAMP (0, min, max),
1862 G_PARAM_READABLE | G_PARAM_WRITABLE);
1863 }
1864 else if (spec_type == G_TYPE_PARAM_DOUBLE)
1865 {
1866 gdouble min = minstr ? g_ascii_strtod (minstr, NULL) : G_MINFLOAT;
1867 gdouble max = maxstr ? g_ascii_strtod (maxstr, NULL) : G_MAXFLOAT;
1868
1869 pspec = g_param_spec_float ("dummy", "dummy", "dummy",
1870 min, max, CLAMP (0, min, max),
1871 G_PARAM_READABLE | G_PARAM_WRITABLE);
1872 }
1873 else
1874 g_critical ("Unsupported pspec type %s (value -> string)",
1875 g_type_name (spec_type));
1876
1877 g_free (minstr);
1878 g_free (maxstr);
1879 }
1880 return pspec;
1881 }
1882
1883
1884 /**
1885 * glade_property_class_update_from_node:
1886 * @node: the property node
1887 * @object_type: the #GType of the owning object
1888 * @property_class: a pointer to the property class
1889 * @domain: the domain to translate catalog strings from
1890 *
1891 * Updates the @property_class with the contents of the node in the xml
1892 * file. Only the values found in the xml file are overridden.
1893 *
1894 * Returns: %TRUE on success. @property_class is set to NULL if the property
1895 * has Disabled="TRUE".
1896 */
1897 gboolean
glade_property_class_update_from_node(GladeXmlNode * node,GType object_type,GladePropertyClass ** property_class,const gchar * domain)1898 glade_property_class_update_from_node (GladeXmlNode * node,
1899 GType object_type,
1900 GladePropertyClass ** property_class,
1901 const gchar * domain)
1902 {
1903 GladePropertyClass *klass;
1904 GParamSpec *pspec = NULL;
1905 gchar *buf, *translated;
1906 GladeXmlNode *child, *spec_node;
1907
1908 g_return_val_if_fail (property_class != NULL, FALSE);
1909
1910 /* for code cleanliness... */
1911 klass = *property_class;
1912
1913 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (klass), FALSE);
1914 g_return_val_if_fail (glade_xml_node_verify (node, GLADE_TAG_PROPERTY),
1915 FALSE);
1916
1917 /* check the id */
1918 buf = glade_xml_get_property_string_required (node, GLADE_TAG_ID, NULL);
1919 if (!buf)
1920 return FALSE;
1921 g_free (buf);
1922
1923 if (glade_xml_get_property_boolean (node, GLADE_TAG_DISABLED, FALSE))
1924 {
1925 /* Its easier for us to keep disabled properties around and
1926 * only virtually disable them */
1927 klass->query = FALSE;
1928 klass->ignore = TRUE;
1929 klass->save = FALSE;
1930 klass->visible = FALSE;
1931 }
1932
1933 if ((spec_node =
1934 glade_xml_search_child (node, GLADE_TAG_SPECIFICATIONS)) != NULL)
1935 pspec = glade_property_class_parse_specifications (klass, spec_node);
1936 else if ((buf = glade_xml_get_value_string (node, GLADE_TAG_SPEC)) != NULL)
1937 {
1938 pspec = glade_utils_get_pspec_from_funcname (buf);
1939 g_free (buf);
1940 }
1941
1942 /* ... get the tooltip from the pspec ... */
1943 if (pspec != NULL)
1944 {
1945 klass->pspec = pspec;
1946
1947 /* Make sure we can tell properties apart by there
1948 * owning class.
1949 */
1950 klass->pspec->owner_type = object_type;
1951
1952 /* We overrode the pspec, now it *is* a virtual property. */
1953 klass->virt = TRUE;
1954
1955 if (strcmp (g_param_spec_get_blurb (klass->pspec), "dummy") != 0)
1956 {
1957 g_free (klass->tooltip);
1958 klass->tooltip = g_strdup (g_param_spec_get_blurb (klass->pspec));
1959 }
1960
1961 if (klass->name == NULL ||
1962 strcmp (g_param_spec_get_nick (klass->pspec), "dummy") != 0)
1963 {
1964 g_free (klass->name);
1965 klass->name = g_strdup (g_param_spec_get_nick (klass->pspec));
1966 }
1967
1968 if (klass->pspec->flags & G_PARAM_CONSTRUCT_ONLY)
1969 klass->construct_only = TRUE;
1970
1971 if (klass->orig_def)
1972 {
1973 g_value_unset (klass->orig_def);
1974 g_free (klass->orig_def);
1975 }
1976 klass->orig_def =
1977 glade_property_class_get_default_from_spec (klass->pspec);
1978
1979 if (klass->def)
1980 {
1981 g_value_unset (klass->def);
1982 g_free (klass->def);
1983 }
1984 klass->def = glade_property_class_get_default_from_spec (klass->pspec);
1985
1986 }
1987 else if (!klass->pspec)
1988 {
1989 /* If catalog file didn't specify a pspec function
1990 * and this property isn't found by introspection
1991 * we simply delete it from the list always.
1992 */
1993 glade_property_class_free (klass);
1994 *property_class = NULL;
1995 return TRUE;
1996 }
1997
1998 /* Get the default */
1999 if ((buf = glade_xml_get_property_string (node, GLADE_TAG_DEFAULT)) != NULL)
2000 {
2001 if (klass->def)
2002 {
2003 g_value_unset (klass->def);
2004 g_free (klass->def);
2005 }
2006 klass->def =
2007 glade_property_class_make_gvalue_from_string (klass, buf, NULL);
2008
2009 if (klass->virt)
2010 {
2011 g_value_unset (klass->orig_def);
2012 g_free (klass->orig_def);
2013 klass->orig_def =
2014 glade_property_class_make_gvalue_from_string (klass, buf, NULL);
2015 }
2016
2017 g_free (buf);
2018 }
2019
2020 /* If needed, update the name... */
2021 if ((buf = glade_xml_get_property_string (node, GLADE_TAG_NAME)) != NULL)
2022 {
2023 g_free (klass->name);
2024
2025 translated = dgettext (domain, buf);
2026 if (buf != translated)
2027 {
2028 /* translated is owned by gettext */
2029 klass->name = g_strdup (translated);
2030 g_free (buf);
2031 }
2032 else
2033 {
2034 klass->name = buf;
2035 }
2036 }
2037
2038 /* ...and the tooltip */
2039 if ((buf = glade_xml_get_value_string (node, GLADE_TAG_TOOLTIP)) != NULL)
2040 {
2041 g_free (klass->tooltip);
2042
2043 translated = dgettext (domain, buf);
2044 if (buf != translated)
2045 {
2046 /* translated is owned by gettext */
2047 klass->tooltip = g_strdup (translated);
2048 g_free (buf);
2049 }
2050 else
2051 {
2052 klass->tooltip = buf;
2053 }
2054 }
2055
2056 klass->multiline =
2057 glade_xml_get_property_boolean (node, GLADE_TAG_MULTILINE,
2058 klass->multiline);
2059 klass->construct_only =
2060 glade_xml_get_property_boolean (node, GLADE_TAG_CONSTRUCT_ONLY,
2061 klass->construct_only);
2062 klass->translatable =
2063 glade_xml_get_property_boolean (node, GLADE_TAG_TRANSLATABLE,
2064 klass->translatable);
2065 klass->common =
2066 glade_xml_get_property_boolean (node, GLADE_TAG_COMMON, klass->common);
2067 klass->optional =
2068 glade_xml_get_property_boolean (node, GLADE_TAG_OPTIONAL,
2069 klass->optional);
2070 klass->query =
2071 glade_xml_get_property_boolean (node, GLADE_TAG_QUERY, klass->query);
2072 klass->save =
2073 glade_xml_get_property_boolean (node, GLADE_TAG_SAVE, klass->save);
2074 klass->visible =
2075 glade_xml_get_property_boolean (node, GLADE_TAG_VISIBLE, klass->visible);
2076 klass->custom_layout =
2077 glade_xml_get_property_boolean (node, GLADE_TAG_CUSTOM_LAYOUT,
2078 klass->custom_layout);
2079 klass->ignore =
2080 glade_xml_get_property_boolean (node, GLADE_TAG_IGNORE, klass->ignore);
2081 klass->needs_sync =
2082 glade_xml_get_property_boolean (node, GLADE_TAG_NEEDS_SYNC,
2083 klass->needs_sync);
2084 klass->themed_icon =
2085 glade_xml_get_property_boolean (node, GLADE_TAG_THEMED_ICON,
2086 klass->themed_icon);
2087 klass->stock =
2088 glade_xml_get_property_boolean (node, GLADE_TAG_STOCK, klass->stock);
2089 klass->stock_icon =
2090 glade_xml_get_property_boolean (node, GLADE_TAG_STOCK_ICON,
2091 klass->stock_icon);
2092 klass->weight =
2093 glade_xml_get_property_double (node, GLADE_TAG_WEIGHT, klass->weight);
2094 klass->transfer_on_paste =
2095 glade_xml_get_property_boolean (node, GLADE_TAG_TRANSFER_ON_PASTE,
2096 klass->transfer_on_paste);
2097 klass->save_always =
2098 glade_xml_get_property_boolean (node, GLADE_TAG_SAVE_ALWAYS,
2099 klass->save_always);
2100 klass->parentless_widget =
2101 glade_xml_get_property_boolean (node, GLADE_TAG_PARENTLESS_WIDGET,
2102 klass->parentless_widget);
2103
2104
2105 glade_xml_get_property_version (node, GLADE_TAG_VERSION_SINCE,
2106 &klass->version_since_major,
2107 &klass->version_since_minor);
2108
2109 klass->deprecated =
2110 glade_xml_get_property_boolean (node,
2111 GLADE_TAG_DEPRECATED,
2112 klass->deprecated);
2113
2114
2115 if ((buf = glade_xml_get_property_string
2116 (node, GLADE_TAG_CREATE_TYPE)) != NULL)
2117 {
2118 if (klass->create_type)
2119 g_free (klass->create_type);
2120 klass->create_type = buf;
2121 }
2122
2123 /* If this property's value is an enumeration or flag then we try to get the displayable values */
2124 if ((G_IS_PARAM_SPEC_ENUM (klass->pspec) ||
2125 G_IS_PARAM_SPEC_FLAGS (klass->pspec)) &&
2126 (child = glade_xml_search_child (node, GLADE_TAG_DISPLAYABLE_VALUES)))
2127 gpc_read_displayable_values_from_node (child, klass, domain);
2128
2129 /* Right now allowing the backend to specify that some properties
2130 * go in the atk tab, ideally this shouldnt be needed.
2131 */
2132 klass->atk =
2133 glade_xml_get_property_boolean (node, GLADE_TAG_ATK_PROPERTY, klass->atk);
2134
2135 if (klass->optional)
2136 klass->optional_default =
2137 glade_xml_get_property_boolean (node, GLADE_TAG_OPTIONAL_DEFAULT,
2138 klass->optional_default);
2139
2140 /* notify that we changed the property class */
2141 klass->is_modified = TRUE;
2142
2143 return TRUE;
2144 }
2145
2146
2147
2148 /**
2149 * glade_property_class_match:
2150 * @klass: a #GladePropertyClass
2151 * @comp: a #GladePropertyClass
2152 *
2153 * Returns: whether @klass and @comp are a match or not
2154 * (properties in seperate decendant heirarchies that
2155 * have the same name are not matches).
2156 */
2157 gboolean
glade_property_class_match(GladePropertyClass * klass,GladePropertyClass * comp)2158 glade_property_class_match (GladePropertyClass * klass,
2159 GladePropertyClass * comp)
2160 {
2161 g_return_val_if_fail (klass != NULL, FALSE);
2162 g_return_val_if_fail (comp != NULL, FALSE);
2163
2164 return (strcmp (klass->id, comp->id) == 0 &&
2165 klass->packing == comp->packing &&
2166 klass->pspec->owner_type == comp->pspec->owner_type);
2167 }
2168
2169
2170 /**
2171 * glade_property_class_void_value:
2172 * @klass: a #GladePropertyClass
2173 *
2174 * Returns: Whether @value for this @klass is voided; a voided value
2175 * can be a %NULL value for boxed or object type param specs.
2176 */
2177 gboolean
glade_property_class_void_value(GladePropertyClass * klass,GValue * value)2178 glade_property_class_void_value (GladePropertyClass * klass, GValue * value)
2179 {
2180 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (klass), FALSE);
2181
2182 if (G_IS_PARAM_SPEC_OBJECT (klass->pspec) &&
2183 g_value_get_object (value) == NULL)
2184 return TRUE;
2185 else if (G_IS_PARAM_SPEC_BOXED (klass->pspec) &&
2186 g_value_get_boxed (value) == NULL)
2187 return TRUE;
2188
2189 return FALSE;
2190 }
2191
2192 /**
2193 * glade_property_class_compare:
2194 * @klass: a #GladePropertyClass
2195 * @value1: a GValue of correct type for @klass
2196 * @value2: a GValue of correct type for @klass
2197 *
2198 * Compares value1 with value2 according to @klass.
2199 *
2200 * Returns: -1, 0 or +1, if value1 is found to be less than,
2201 * equal to or greater than value2, respectively.
2202 */
2203 gint
glade_property_class_compare(GladePropertyClass * klass,const GValue * value1,const GValue * value2)2204 glade_property_class_compare (GladePropertyClass * klass,
2205 const GValue * value1, const GValue * value2)
2206 {
2207 gint retval;
2208
2209 g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (klass), -1);
2210
2211 /* GLib does not know how to compare a boxed real value */
2212 if (G_VALUE_HOLDS_BOXED (value1) || G_VALUE_HOLDS_BOXED (value2))
2213 {
2214 gchar *val1, *val2;
2215
2216 /* So boxed types are compared by string and the backend is required to generate
2217 * unique strings for values for this purpose.
2218 *
2219 * NOTE: We could add a pclass option to use the string compare vs. boxed compare...
2220 */
2221 val1 =
2222 glade_widget_adaptor_string_from_value (klass->adaptor, klass, value1);
2223 val2 =
2224 glade_widget_adaptor_string_from_value (klass->adaptor, klass, value2);
2225
2226 if (val1 && val2)
2227 retval = strcmp (val1, val2);
2228 else
2229 retval = val1 - val2;
2230
2231 g_free (val1);
2232 g_free (val2);
2233 }
2234 else
2235 {
2236 if (G_IS_PARAM_SPEC_STRING (klass->pspec))
2237 {
2238 const gchar *value_str1, *value_str2;
2239
2240 /* in string specs; NULL and '\0' are
2241 * treated as equivalent.
2242 */
2243 value_str1 = g_value_get_string (value1);
2244 value_str2 = g_value_get_string (value2);
2245
2246 if (value_str1 == NULL && value_str2 && value_str2[0] == '\0')
2247 return 0;
2248 else if (value_str2 == NULL && value_str1 && value_str1[0] == '\0')
2249 return 0;
2250 }
2251 retval = g_param_values_cmp (klass->pspec, value1, value2);
2252 }
2253
2254 return retval;
2255 }
2256
2257 /*
2258 This function assignes "weight" to each property in its natural order staring from 1.
2259 If parent is 0 weight will be set for every GladePropertyClass in the list.
2260 This function will not override weight if it is already set (weight >= 0.0)
2261 */
2262 void
glade_property_class_set_weights(GList ** properties,GType parent)2263 glade_property_class_set_weights (GList ** properties, GType parent)
2264 {
2265 gint normal = 0, common = 0, packing = 0;
2266 GList *l;
2267
2268 for (l = *properties; l && l->data; l = g_list_next (l))
2269 {
2270 GladePropertyClass *klass = l->data;
2271
2272 if (klass->visible &&
2273 (parent) ? parent == klass->pspec->owner_type : TRUE && !klass->atk)
2274 {
2275 /* Use a different counter for each tab (common, packing and normal) */
2276 if (klass->common)
2277 common++;
2278 else if (klass->packing)
2279 packing++;
2280 else
2281 normal++;
2282
2283 /* Skip if it is already set */
2284 if (klass->weight >= 0.0)
2285 continue;
2286
2287 /* Special-casing weight of properties for seperate tabs */
2288 if (klass->common)
2289 klass->weight = common;
2290 else if (klass->packing)
2291 klass->weight = packing;
2292 else
2293 klass->weight = normal;
2294 }
2295 }
2296 }
2297
2298 void
glade_property_class_load_defaults_from_spec(GladePropertyClass * property_class)2299 glade_property_class_load_defaults_from_spec (GladePropertyClass *property_class)
2300 {
2301 property_class->orig_def =
2302 glade_property_class_get_default_from_spec (property_class->pspec);
2303
2304 property_class->def =
2305 glade_property_class_get_default_from_spec (property_class->pspec);
2306 }
2307