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