1 /*
2  * Copyright (C) 2001 Ximian, Inc.
3  * Copyright (C) 2006 The GNOME Foundation.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  *
19  * Authors:
20  *   Chema Celorio <chema@celorio.com>
21  *   Tristan Van Berkom <tvb@gnome.org>
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 /**
29  * SECTION:glade-property
30  * @Title: GladeProperty
31  * @Short_Description: An interface to properties on the #GladeWidget.
32  *
33  * Every object property of every #GladeWidget in every #GladeProject has
34  * a #GladeProperty to interface with, #GladeProperty provides a means
35  * to handle properties in the runtime environment.
36  *
37  * A #GladeProperty can be seen as an instance of a #GladePropertyClass,
38  * the #GladePropertyClass describes how a #GladeProperty will function.
39  */
40 
41 #include <stdio.h>
42 #include <stdlib.h>             /* for atoi and atof */
43 #include <string.h>
44 
45 #include <glib/gi18n-lib.h>
46 
47 #include "glade.h"
48 #include "glade-widget.h"
49 #include "glade-property.h"
50 #include "glade-property-class.h"
51 #include "glade-project.h"
52 #include "glade-widget-adaptor.h"
53 #include "glade-debug.h"
54 #include "glade-app.h"
55 #include "glade-editor.h"
56 #include "glade-marshallers.h"
57 
58 struct _GladePropertyPrivate {
59 
60   GladePropertyClass *klass;     /* A pointer to the GladeProperty that this
61 				  * setting specifies
62 				  */
63   GladeWidget        *widget;    /* A pointer to the GladeWidget that this
64 				  * GladeProperty is modifying
65 				  */
66 
67   GladePropertyState  state;     /* Current property state, used by editing widgets.
68 				  */
69 
70   GValue             *value;     /* The value of the property
71 				  */
72 
73   gchar              *insensitive_tooltip; /* Tooltip to display when in insensitive state
74 					    * (used to explain why the property is
75 					    *  insensitive)
76 					    */
77 
78   gchar              *support_warning; /* Tooltip to display when the property
79 					* has format problems
80 					* (used to explain why the property is
81 					*  insensitive)
82 					*/
83   guint               support_disabled : 1; /* Whether this property is disabled due
84 					     * to format conflicts
85 					     */
86 
87   guint               sensitive : 1; /* Whether this property is sensitive (if the
88 				      * property is "optional" this takes precedence).
89 				      */
90 
91   guint               enabled : 1;   /* Enabled is a flag that is used for GladeProperties
92 				      * that have the optional flag set to let us know
93 				      * if this widget has this setting enabled or
94 				      * not. (Like default size, it can be specified or
95 				      * unspecified). This flag also sets the state
96 				      * of the property->input state for the loaded
97 				      * widget.
98 				      */
99 
100   guint               save_always : 1; /* Used to make a special case exception and always
101 					* save this property regardless of what the default
102 					* value is (used for some special cases like properties
103 					* that are assigned initial values in composite widgets
104 					* or derived widget code).
105 					*/
106 
107   /* Used only for translatable strings. */
108   guint     i18n_translatable : 1;
109   gchar    *i18n_context;
110   gchar    *i18n_comment;
111 
112   gint      syncing;  /* Avoid recursion while synchronizing object with value */
113   gint      sync_tolerance;
114 };
115 
116 enum
117 {
118   VALUE_CHANGED,
119   TOOLTIP_CHANGED,
120   LAST_SIGNAL
121 };
122 
123 enum
124 {
125   PROP_0,
126   PROP_CLASS,
127   PROP_ENABLED,
128   PROP_SENSITIVE,
129   PROP_I18N_TRANSLATABLE,
130   PROP_I18N_CONTEXT,
131   PROP_I18N_COMMENT,
132   PROP_STATE,
133   N_PROPERTIES
134 };
135 
136 static GParamSpec *properties[N_PROPERTIES];
137 static guint glade_property_signals[LAST_SIGNAL] = { 0 };
138 
139 static GObjectClass *glade_property_parent_class = NULL;
140 
141 /*******************************************************************************
142                            GladeProperty class methods
143  *******************************************************************************/
144 static GladeProperty *
glade_property_dup_impl(GladeProperty * template_prop,GladeWidget * widget)145 glade_property_dup_impl (GladeProperty *template_prop, GladeWidget *widget)
146 {
147   GladeProperty *property;
148 
149   property = g_object_new (GLADE_TYPE_PROPERTY,
150                            "class", template_prop->priv->klass,
151                            "i18n-translatable", template_prop->priv->i18n_translatable,
152 			   "i18n-context", template_prop->priv->i18n_context,
153 			   "i18n-comment", template_prop->priv->i18n_comment,
154 			   NULL);
155   property->priv->widget = widget;
156   property->priv->value = g_new0 (GValue, 1);
157 
158   g_value_init (property->priv->value, template_prop->priv->value->g_type);
159 
160   /* Cannot duplicate parentless_widget property */
161   if (glade_property_class_parentless_widget (template_prop->priv->klass))
162     {
163       if (!G_IS_PARAM_SPEC_OBJECT (glade_property_class_get_pspec (template_prop->priv->klass)))
164         g_warning ("Parentless widget property should be of object type");
165 
166       g_value_set_object (property->priv->value, NULL);
167     }
168   else
169     g_value_copy (template_prop->priv->value, property->priv->value);
170 
171   property->priv->enabled = template_prop->priv->enabled;
172   property->priv->state   = template_prop->priv->state;
173 
174   glade_property_set_sensitive (property, template_prop->priv->sensitive,
175                                 template_prop->priv->insensitive_tooltip);
176 
177   return property;
178 }
179 
180 static gboolean
glade_property_equals_value_impl(GladeProperty * property,const GValue * value)181 glade_property_equals_value_impl (GladeProperty *property,
182                                   const GValue  *value)
183 {
184   return !glade_property_class_compare (property->priv->klass, property->priv->value,
185                                         value);
186 }
187 
188 
189 static void
glade_property_update_prop_refs(GladeProperty * property,const GValue * old_value,const GValue * new_value)190 glade_property_update_prop_refs (GladeProperty *property,
191                                  const GValue  *old_value,
192                                  const GValue  *new_value)
193 {
194   GladeWidget *gold, *gnew;
195   GObject *old_object, *new_object;
196   GList *old_list, *new_list, *list, *removed, *added;
197 
198   if (GLADE_IS_PARAM_SPEC_OBJECTS (glade_property_class_get_pspec (property->priv->klass)))
199     {
200       /* Make our own copies incase we're walking an
201        * unstable list
202        */
203       old_list = g_value_dup_boxed (old_value);
204       new_list = g_value_dup_boxed (new_value);
205 
206       /* Diff up the GList */
207       removed = glade_util_removed_from_list (old_list, new_list);
208       added = glade_util_added_in_list (old_list, new_list);
209 
210       /* Adjust the appropriate prop refs */
211       for (list = removed; list; list = list->next)
212         {
213           old_object = list->data;
214           gold = glade_widget_get_from_gobject (old_object);
215           if (gold != NULL)
216             glade_widget_remove_prop_ref (gold, property);
217         }
218       for (list = added; list; list = list->next)
219         {
220           new_object = list->data;
221           gnew = glade_widget_get_from_gobject (new_object);
222           if (gnew != NULL)
223             glade_widget_add_prop_ref (gnew, property);
224         }
225 
226       g_list_free (removed);
227       g_list_free (added);
228       g_list_free (old_list);
229       g_list_free (new_list);
230     }
231   else
232     {
233       if ((old_object = g_value_get_object (old_value)) != NULL)
234         {
235           gold = glade_widget_get_from_gobject (old_object);
236           g_return_if_fail (gold != NULL);
237           glade_widget_remove_prop_ref (gold, property);
238         }
239 
240       if ((new_object = g_value_get_object (new_value)) != NULL)
241         {
242           gnew = glade_widget_get_from_gobject (new_object);
243           g_return_if_fail (gnew != NULL);
244           glade_widget_add_prop_ref (gnew, property);
245         }
246     }
247 }
248 
249 static gboolean
glade_property_verify(GladeProperty * property,const GValue * value)250 glade_property_verify (GladeProperty *property, const GValue *value)
251 {
252   gboolean ret = FALSE;
253   GladeWidget *parent;
254 
255   parent = glade_widget_get_parent (property->priv->widget);
256 
257   if (glade_property_class_get_is_packing (property->priv->klass) && parent)
258     ret =
259       glade_widget_adaptor_child_verify_property (glade_widget_get_adaptor (parent),
260 						  glade_widget_get_object (parent),
261 						  glade_widget_get_object (property->priv->widget),
262 						  glade_property_class_id (property->priv->klass),
263 						  value);
264   else if (!glade_property_class_get_is_packing (property->priv->klass))
265     ret = glade_widget_adaptor_verify_property (glade_widget_get_adaptor (property->priv->widget),
266                                                 glade_widget_get_object (property->priv->widget),
267                                                 glade_property_class_id (property->priv->klass), value);
268 
269   return ret;
270 }
271 
272 static void
glade_property_fix_state(GladeProperty * property)273 glade_property_fix_state (GladeProperty *property)
274 {
275   property->priv->state = GLADE_STATE_NORMAL;
276 
277   /* Properties are 'changed' state if they are not default, or if
278    * they are optional and enabled, optional enabled properties
279    * are saved regardless of default value
280    */
281   if (glade_property_class_optional (property->priv->klass))
282     {
283       if (glade_property_get_enabled (property))
284 	property->priv->state |= GLADE_STATE_CHANGED;
285     }
286   else if (!glade_property_original_default (property))
287     property->priv->state |= GLADE_STATE_CHANGED;
288 
289   if (property->priv->support_warning)
290     property->priv->state |= GLADE_STATE_UNSUPPORTED;
291 
292   if (property->priv->support_disabled)
293     property->priv->state |= GLADE_STATE_SUPPORT_DISABLED;
294 
295   g_object_notify_by_pspec (G_OBJECT (property), properties[PROP_STATE]);
296 }
297 
298 
299 static gboolean
glade_property_set_value_impl(GladeProperty * property,const GValue * value)300 glade_property_set_value_impl (GladeProperty *property, const GValue *value)
301 {
302   GladeProject *project = property->priv->widget ?
303       glade_widget_get_project (property->priv->widget) : NULL;
304   gboolean changed = FALSE;
305   GValue old_value = { 0, };
306   gboolean warn_before, warn_after;
307 
308 #ifdef GLADE_ENABLE_DEBUG
309   if (glade_get_debug_flags () & GLADE_DEBUG_PROPERTIES)
310     {
311       g_print ("PROPERTY: Setting %s property %s on %s ",
312 	       glade_property_class_get_is_packing (property->priv->klass) ? "packing" : "normal",
313 	       glade_property_class_id (property->priv->klass),
314 	       property->priv->widget ? glade_widget_get_name (property->priv->widget) : "unknown");
315 
316       gchar *str1 =
317 	glade_widget_adaptor_string_from_value (glade_property_class_get_adaptor (property->priv->klass),
318 						property->priv->klass, property->priv->value);
319       gchar *str2 =
320 	glade_widget_adaptor_string_from_value (glade_property_class_get_adaptor (property->priv->klass),
321 						property->priv->klass, value);
322       g_print ("from %s to %s\n", str1, str2);
323       g_free (str1);
324       g_free (str2);
325     }
326 #endif /* GLADE_ENABLE_DEBUG */
327 
328   if (!g_value_type_compatible (G_VALUE_TYPE (property->priv->value), G_VALUE_TYPE (value)))
329     {
330       g_warning ("Trying to assign an incompatible value to property %s\n",
331                  glade_property_class_id (property->priv->klass));
332       return FALSE;
333     }
334 
335   /* Check if the backend doesnt give us permission to
336    * set this value.
337    */
338   if (glade_property_superuser () == FALSE && property->priv->widget &&
339       project && glade_project_is_loading (project) == FALSE &&
340       glade_property_verify (property, value) == FALSE)
341     {
342       return FALSE;
343     }
344 
345   /* save "changed" state.
346    */
347   changed = !glade_property_equals_value (property, value);
348 
349   /* Add/Remove references from widget ref stacks here
350    * (before assigning the value)
351    */
352   if (property->priv->widget && changed &&
353       glade_property_class_is_object (property->priv->klass))
354     glade_property_update_prop_refs (property, property->priv->value, value);
355 
356   /* Check pre-changed warning state */
357   warn_before = glade_property_warn_usage (property);
358 
359   /* Make a copy of the old value */
360   g_value_init (&old_value, G_VALUE_TYPE (property->priv->value));
361   g_value_copy (property->priv->value, &old_value);
362 
363   /* Assign property first so that; if the object need be
364    * rebuilt, it will reflect the new value
365    */
366   g_value_reset (property->priv->value);
367   g_value_copy (value, property->priv->value);
368 
369   GLADE_PROPERTY_GET_KLASS (property)->sync (property);
370 
371   glade_property_fix_state (property);
372 
373   if (changed && property->priv->widget)
374     {
375       g_signal_emit (G_OBJECT (property),
376                      glade_property_signals[VALUE_CHANGED],
377                      0, &old_value, property->priv->value);
378 
379       glade_project_verify_property (property);
380 
381       /* Check post change warning state */
382       warn_after = glade_property_warn_usage (property);
383 
384       /* Update owning widget's warning state if need be */
385       if (property->priv->widget != NULL && warn_before != warn_after)
386 	glade_widget_verify (property->priv->widget);
387     }
388 
389   /* Special case parentless widget properties */
390   if (glade_property_class_parentless_widget (property->priv->klass))
391     {
392       GladeWidget *gobj;
393       GObject *obj;
394 
395       if ((obj = g_value_get_object (&old_value)) &&
396           (gobj = glade_widget_get_from_gobject (obj)))
397         glade_widget_show (gobj);
398 
399       if ((obj = g_value_get_object (value)) &&
400           (gobj = glade_widget_get_from_gobject (obj)))
401         glade_widget_hide (gobj);
402     }
403 
404   g_value_unset (&old_value);
405   return TRUE;
406 }
407 
408 static void
glade_property_get_value_impl(GladeProperty * property,GValue * value)409 glade_property_get_value_impl (GladeProperty *property, GValue *value)
410 {
411   GParamSpec *pspec;
412 
413   pspec = glade_property_class_get_pspec (property->priv->klass);
414 
415   g_value_init (value, pspec->value_type);
416   g_value_copy (property->priv->value, value);
417 }
418 
419 static void
glade_property_sync_impl(GladeProperty * property)420 glade_property_sync_impl (GladeProperty *property)
421 {
422   GladePropertyPrivate *priv = property->priv;
423   GladePropertyClass *klass = priv->klass;
424   const GValue *value;
425   const gchar *id;
426 
427   /* Heh, here are the many reasons not to
428    * sync a property ;-)
429    */
430   if (/* the class can be NULL during object,
431        * construction this is just a temporary state */
432        klass == NULL ||
433        /* explicit "never sync" flag */
434        glade_property_class_get_ignore (klass) ||
435        /* recursion guards */
436        priv->syncing >= priv->sync_tolerance ||
437        /* No widget owns this property yet */
438        priv->widget == NULL)
439     return;
440 
441   id = glade_property_class_id (klass);
442 
443   /* Only the properties from widget->properties should affect the runtime widget.
444    * (other properties may be used for convenience in the plugin).
445    */
446   if ((glade_property_class_get_is_packing (klass) &&
447        !glade_widget_get_pack_property (priv->widget, id))
448       || !glade_widget_get_property (priv->widget, id))
449     return;
450 
451   priv->syncing++;
452 
453   /* optional properties that are disabled get the default runtime value */
454   value = (priv->enabled) ? priv->value : glade_property_class_get_default (klass);
455 
456   /* In the case of construct_only, the widget instance must be rebuilt
457    * to apply the property
458    */
459   if (glade_property_class_get_construct_only (klass) && priv->syncing == 1)
460     {
461       /* Virtual properties can be construct only, in which
462        * case they are allowed to trigger a rebuild, and in
463        * the process are allowed to get "synced" after the
464        * instance is rebuilt.
465        */
466       if (glade_property_class_get_virtual (klass))
467         priv->sync_tolerance++;
468 
469       glade_widget_rebuild (priv->widget);
470 
471       if (glade_property_class_get_virtual (klass))
472         priv->sync_tolerance--;
473     }
474   else if (glade_property_class_get_is_packing (klass))
475     glade_widget_child_set_property (glade_widget_get_parent (priv->widget),
476                                      priv->widget, id, value);
477   else
478     glade_widget_object_set_property (priv->widget, id, value);
479 
480   priv->syncing--;
481 }
482 
483 static void
glade_property_load_impl(GladeProperty * property)484 glade_property_load_impl (GladeProperty *property)
485 {
486   GObject *object;
487   GObjectClass *oclass;
488   GParamSpec *pspec;
489 
490   pspec = glade_property_class_get_pspec (property->priv->klass);
491 
492   if (property->priv->widget == NULL ||
493       glade_property_class_get_virtual (property->priv->klass) ||
494       glade_property_class_get_is_packing (property->priv->klass) ||
495       glade_property_class_get_ignore (property->priv->klass) ||
496       !(pspec->flags & G_PARAM_READABLE) || G_IS_PARAM_SPEC_OBJECT (pspec))
497     return;
498 
499   object = glade_widget_get_object (property->priv->widget);
500   oclass = G_OBJECT_GET_CLASS (object);
501 
502   if (g_object_class_find_property (oclass, glade_property_class_id (property->priv->klass)))
503     glade_widget_object_get_property (property->priv->widget,
504 				      glade_property_class_id (property->priv->klass),
505                                       property->priv->value);
506 }
507 
508 /*******************************************************************************
509                       GObjectClass & Object Construction
510  *******************************************************************************/
511 static void
glade_property_set_real_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)512 glade_property_set_real_property (GObject      *object,
513                                   guint         prop_id,
514                                   const GValue *value,
515                                   GParamSpec   *pspec)
516 {
517   GladeProperty *property = GLADE_PROPERTY (object);
518 
519   switch (prop_id)
520     {
521       case PROP_CLASS:
522         property->priv->klass = g_value_get_pointer (value);
523         break;
524       case PROP_ENABLED:
525         glade_property_set_enabled (property, g_value_get_boolean (value));
526         break;
527       case PROP_SENSITIVE:
528         property->priv->sensitive = g_value_get_boolean (value);
529         break;
530       case PROP_I18N_TRANSLATABLE:
531         glade_property_i18n_set_translatable (property,
532                                               g_value_get_boolean (value));
533         break;
534       case PROP_I18N_CONTEXT:
535         glade_property_i18n_set_context (property, g_value_get_string (value));
536         break;
537       case PROP_I18N_COMMENT:
538         glade_property_i18n_set_comment (property, g_value_get_string (value));
539         break;
540       default:
541         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
542         break;
543     }
544 }
545 
546 static void
glade_property_get_real_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)547 glade_property_get_real_property (GObject    *object,
548                                   guint       prop_id,
549                                   GValue     *value,
550                                   GParamSpec *pspec)
551 {
552   GladeProperty *property = GLADE_PROPERTY (object);
553 
554   switch (prop_id)
555     {
556       case PROP_CLASS:
557         g_value_set_pointer (value, property->priv->klass);
558         break;
559       case PROP_ENABLED:
560         g_value_set_boolean (value, glade_property_get_enabled (property));
561         break;
562       case PROP_SENSITIVE:
563         g_value_set_boolean (value, glade_property_get_sensitive (property));
564         break;
565       case PROP_I18N_TRANSLATABLE:
566         g_value_set_boolean (value,
567                              glade_property_i18n_get_translatable (property));
568         break;
569       case PROP_I18N_CONTEXT:
570         g_value_set_string (value, glade_property_i18n_get_context (property));
571         break;
572       case PROP_I18N_COMMENT:
573         g_value_set_string (value, glade_property_i18n_get_comment (property));
574         break;
575       case PROP_STATE:
576         g_value_set_int (value, property->priv->state);
577         break;
578       default:
579         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
580         break;
581     }
582 }
583 
584 static void
glade_property_finalize(GObject * object)585 glade_property_finalize (GObject *object)
586 {
587   GladeProperty *property = GLADE_PROPERTY (object);
588 
589   if (property->priv->value)
590     {
591       g_value_unset (property->priv->value);
592       g_free (property->priv->value);
593     }
594   if (property->priv->i18n_comment)
595     g_free (property->priv->i18n_comment);
596   if (property->priv->i18n_context)
597     g_free (property->priv->i18n_context);
598   if (property->priv->support_warning)
599     g_free (property->priv->support_warning);
600   if (property->priv->insensitive_tooltip)
601     g_free (property->priv->insensitive_tooltip);
602 
603   G_OBJECT_CLASS (glade_property_parent_class)->finalize (object);
604 }
605 
606 static void
glade_property_init(GladeProperty * property)607 glade_property_init (GladeProperty *property)
608 {
609   property->priv = G_TYPE_INSTANCE_GET_PRIVATE (property,
610 						GLADE_TYPE_PROPERTY,
611 						GladePropertyPrivate);
612 
613   property->priv->enabled = TRUE;
614   property->priv->sensitive = TRUE;
615   property->priv->i18n_translatable = TRUE;
616   property->priv->i18n_comment = NULL;
617   property->priv->sync_tolerance = 1;
618 }
619 
620 static void
glade_property_klass_init(GladePropertyKlass * prop_class)621 glade_property_klass_init (GladePropertyKlass * prop_class)
622 {
623   GObjectClass *object_class;
624   g_return_if_fail (prop_class != NULL);
625 
626   glade_property_parent_class = g_type_class_peek_parent (prop_class);
627   object_class = G_OBJECT_CLASS (prop_class);
628 
629   /* GObjectClass */
630   object_class->set_property = glade_property_set_real_property;
631   object_class->get_property = glade_property_get_real_property;
632   object_class->finalize = glade_property_finalize;
633 
634   /* Class methods */
635   prop_class->dup = glade_property_dup_impl;
636   prop_class->equals_value = glade_property_equals_value_impl;
637   prop_class->set_value = glade_property_set_value_impl;
638   prop_class->get_value = glade_property_get_value_impl;
639   prop_class->sync = glade_property_sync_impl;
640   prop_class->load = glade_property_load_impl;
641   prop_class->value_changed = NULL;
642   prop_class->tooltip_changed = NULL;
643 
644   /* Properties */
645   properties[PROP_CLASS] =
646     g_param_spec_pointer ("class",
647                           _("Class"),
648                           _("The GladePropertyClass for this property"),
649                           G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
650 
651   properties[PROP_ENABLED] =
652     g_param_spec_boolean ("enabled",
653                           _("Enabled"),
654                           _("If the property is optional, this is its enabled state"),
655                           TRUE, G_PARAM_READWRITE);
656 
657   properties[PROP_SENSITIVE] =
658     g_param_spec_boolean ("sensitive",
659                           _("Sensitive"),
660                           _("This gives backends control to set property sensitivity"),
661                           TRUE, G_PARAM_READWRITE);
662 
663   properties[PROP_I18N_CONTEXT] =
664     g_param_spec_string ("i18n-context",
665                          _("Context"),
666                          _("Context for translation"),
667                          NULL,
668                          G_PARAM_READWRITE);
669 
670   properties[PROP_I18N_COMMENT] =
671     g_param_spec_string ("i18n-comment",
672                          _("Comment"),
673                          _("Comment for translators"),
674                          NULL,
675                          G_PARAM_READWRITE);
676 
677   properties[PROP_I18N_TRANSLATABLE] =
678     g_param_spec_boolean ("i18n-translatable",
679                           _("Translatable"),
680                           _("Whether this property is translatable"),
681                           TRUE,
682                           G_PARAM_READWRITE);
683 
684   properties[PROP_STATE] =
685     g_param_spec_int ("state",
686                       _("Visual State"),
687                       _("Priority information for the property editor to act on"),
688                       GLADE_STATE_NORMAL,
689                       G_MAXINT,
690                       GLADE_STATE_NORMAL,
691                       G_PARAM_READABLE);
692 
693   /* Install all properties */
694   g_object_class_install_properties (object_class, N_PROPERTIES, properties);
695 
696   /* Signal */
697   glade_property_signals[VALUE_CHANGED] =
698       g_signal_new ("value-changed",
699                     G_TYPE_FROM_CLASS (object_class),
700                     G_SIGNAL_RUN_LAST,
701                     G_STRUCT_OFFSET (GladePropertyKlass,
702                                      value_changed),
703                     NULL, NULL,
704                     _glade_marshal_VOID__POINTER_POINTER,
705                     G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
706 
707   glade_property_signals[TOOLTIP_CHANGED] =
708       g_signal_new ("tooltip-changed",
709                     G_TYPE_FROM_CLASS (object_class),
710                     G_SIGNAL_RUN_LAST,
711                     G_STRUCT_OFFSET (GladePropertyKlass,
712                                      tooltip_changed),
713                     NULL, NULL,
714                     _glade_marshal_VOID__STRING_STRING_STRING,
715                     G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING,
716                     G_TYPE_STRING);
717 
718   g_type_class_add_private (prop_class, sizeof (GladePropertyPrivate));
719 }
720 
721 GType
glade_property_get_type(void)722 glade_property_get_type (void)
723 {
724   static GType property_type = 0;
725 
726   if (!property_type)
727     {
728       static const GTypeInfo property_info = {
729         sizeof (GladePropertyKlass),    /* Klass is our class */
730         (GBaseInitFunc) NULL,
731         (GBaseFinalizeFunc) NULL,
732         (GClassInitFunc) glade_property_klass_init,
733         (GClassFinalizeFunc) NULL,
734         NULL,                   /* class_data */
735         sizeof (GladeProperty),
736         0,                      /* n_preallocs */
737         (GInstanceInitFunc) glade_property_init,
738       };
739       property_type =
740           g_type_register_static (G_TYPE_OBJECT,
741                                   "GladeProperty", &property_info, 0);
742     }
743   return property_type;
744 }
745 
746 /*******************************************************************************
747                                      API
748  *******************************************************************************/
749 /**
750  * glade_property_new:
751  * @klass: A #GladePropertyClass defining this property
752  * @widget: The #GladeWidget this property is created for
753  * @value: The initial #GValue of the property or %NULL
754  *         (the #GladeProperty will assume ownership of @value)
755  *
756  * Creates a #GladeProperty of type @klass for @widget with @value; if
757  * @value is %NULL, then the introspected default value for that property
758  * will be used.
759  *
760  * Returns: The newly created #GladeProperty
761  */
762 GladeProperty *
glade_property_new(GladePropertyClass * klass,GladeWidget * widget,GValue * value)763 glade_property_new (GladePropertyClass *klass,
764                     GladeWidget        *widget,
765                     GValue             *value)
766 {
767   GladeProperty *property;
768 
769   g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (klass), NULL);
770 
771   property = (GladeProperty *) g_object_new (GLADE_TYPE_PROPERTY, NULL);
772   property->priv->klass = klass;
773   property->priv->widget = widget;
774   property->priv->value = value;
775 
776   if (glade_property_class_optional (klass))
777     property->priv->enabled = glade_property_class_optional_default (klass);
778 
779   if (property->priv->value == NULL)
780     {
781       const GValue *orig_def =
782 	glade_property_class_get_original_default (klass);
783 
784       property->priv->value = g_new0 (GValue, 1);
785       g_value_init (property->priv->value, orig_def->g_type);
786       g_value_copy (orig_def, property->priv->value);
787     }
788 
789   return property;
790 }
791 
792 /**
793  * glade_property_dup:
794  * @template_prop: A #GladeProperty
795  * @widget: A #GladeWidget
796  *
797  * Returns: A newly duplicated property based on the new widget
798  */
799 GladeProperty *
glade_property_dup(GladeProperty * template_prop,GladeWidget * widget)800 glade_property_dup (GladeProperty *template_prop, GladeWidget *widget)
801 {
802   g_return_val_if_fail (GLADE_IS_PROPERTY (template_prop), NULL);
803   return GLADE_PROPERTY_GET_KLASS (template_prop)->dup (template_prop, widget);
804 }
805 
806 static void
glade_property_reset_common(GladeProperty * property,gboolean original)807 glade_property_reset_common (GladeProperty *property, gboolean original)
808 {
809   const GValue *value;
810 
811   g_return_if_fail (GLADE_IS_PROPERTY (property));
812 
813   if (original)
814     value = glade_property_class_get_original_default (property->priv->klass);
815   else
816     value = glade_property_class_get_default (property->priv->klass);
817 
818   GLADE_PROPERTY_GET_KLASS (property)->set_value (property, value);
819 }
820 
821 /**
822  * glade_property_reset:
823  * @property: A #GladeProperty
824  *
825  * Resets this property to its default value
826  */
827 void
glade_property_reset(GladeProperty * property)828 glade_property_reset (GladeProperty *property)
829 {
830   glade_property_reset_common (property, FALSE);
831 }
832 
833 /**
834  * glade_property_original_reset:
835  * @property: A #GladeProperty
836  *
837  * Resets this property to its original default value
838  */
839 void
glade_property_original_reset(GladeProperty * property)840 glade_property_original_reset (GladeProperty *property)
841 {
842   glade_property_reset_common (property, TRUE);
843 }
844 
845 static gboolean
glade_property_default_common(GladeProperty * property,gboolean orig)846 glade_property_default_common (GladeProperty *property, gboolean orig)
847 {
848   const GValue *value;
849 
850   g_return_val_if_fail (GLADE_IS_PROPERTY (property), FALSE);
851 
852   if (orig)
853     value = glade_property_class_get_original_default (property->priv->klass);
854   else
855     value = glade_property_class_get_default (property->priv->klass);
856 
857   return GLADE_PROPERTY_GET_KLASS (property)->equals_value (property, value);
858 }
859 
860 /**
861  * glade_property_default:
862  * @property: A #GladeProperty
863  *
864  * Returns: Whether this property is at its default value
865  */
866 gboolean
glade_property_default(GladeProperty * property)867 glade_property_default (GladeProperty *property)
868 {
869   return glade_property_default_common (property, FALSE);
870 }
871 
872 /**
873  * glade_property_original_default:
874  * @property: A #GladeProperty
875  *
876  * Returns: Whether this property is at its original default value
877  */
878 gboolean
glade_property_original_default(GladeProperty * property)879 glade_property_original_default (GladeProperty *property)
880 {
881   return glade_property_default_common (property, TRUE);
882 }
883 
884 /**
885  * glade_property_equals_value:
886  * @property: a #GladeProperty
887  * @value: a #GValue
888  *
889  * Returns: Whether this property is equal to the value provided
890  */
891 gboolean
glade_property_equals_value(GladeProperty * property,const GValue * value)892 glade_property_equals_value (GladeProperty *property, const GValue *value)
893 {
894   g_return_val_if_fail (GLADE_IS_PROPERTY (property), FALSE);
895   return GLADE_PROPERTY_GET_KLASS (property)->equals_value (property, value);
896 }
897 
898 /**
899  * glade_property_equals_va_list:
900  * @property: a #GladeProperty
901  * @vl: a va_list
902  *
903  * Returns: Whether this property is equal to the value provided
904  */
905 static gboolean
glade_property_equals_va_list(GladeProperty * property,va_list vl)906 glade_property_equals_va_list (GladeProperty *property, va_list vl)
907 {
908   GValue *value;
909   gboolean ret;
910 
911   g_return_val_if_fail (GLADE_IS_PROPERTY (property), FALSE);
912 
913   value = glade_property_class_make_gvalue_from_vl (property->priv->klass, vl);
914 
915   ret = GLADE_PROPERTY_GET_KLASS (property)->equals_value (property, value);
916 
917   g_value_unset (value);
918   g_free (value);
919   return ret;
920 }
921 
922 /**
923  * glade_property_equals:
924  * @property: a #GladeProperty
925  * @...: a provided property value
926  *
927  * Returns: Whether this property is equal to the value provided
928  */
929 gboolean
glade_property_equals(GladeProperty * property,...)930 glade_property_equals (GladeProperty *property, ...)
931 {
932   va_list vl;
933   gboolean ret;
934 
935   g_return_val_if_fail (GLADE_IS_PROPERTY (property), FALSE);
936 
937   va_start (vl, property);
938   ret = glade_property_equals_va_list (property, vl);
939   va_end (vl);
940 
941   return ret;
942 }
943 
944 /**
945  * glade_property_set_value:
946  * @property: a #GladeProperty
947  * @value: a #GValue
948  *
949  * Sets the property's value
950  *
951  * Returns: Whether the property was successfully set.
952  */
953 gboolean
glade_property_set_value(GladeProperty * property,const GValue * value)954 glade_property_set_value (GladeProperty *property, const GValue *value)
955 {
956   g_return_val_if_fail (GLADE_IS_PROPERTY (property), FALSE);
957   g_return_val_if_fail (value != NULL, FALSE);
958   return GLADE_PROPERTY_GET_KLASS (property)->set_value (property, value);
959 }
960 
961 /**
962  * glade_property_set_va_list:
963  * @property: a #GladeProperty
964  * @vl: a va_list with value to set
965  *
966  * Sets the property's value
967  */
968 gboolean
glade_property_set_va_list(GladeProperty * property,va_list vl)969 glade_property_set_va_list (GladeProperty *property, va_list vl)
970 {
971   GValue *value;
972   gboolean success;
973 
974   g_return_val_if_fail (GLADE_IS_PROPERTY (property), FALSE);
975 
976   value = glade_property_class_make_gvalue_from_vl (property->priv->klass, vl);
977 
978   success = GLADE_PROPERTY_GET_KLASS (property)->set_value (property, value);
979 
980   g_value_unset (value);
981   g_free (value);
982 
983   return success;
984 }
985 
986 /**
987  * glade_property_set:
988  * @property: a #GladeProperty
989  * @...: the value to set
990  *
991  * Sets the property's value (in a convenient way)
992  */
993 gboolean
glade_property_set(GladeProperty * property,...)994 glade_property_set (GladeProperty *property, ...)
995 {
996   va_list vl;
997   gboolean success;
998 
999   g_return_val_if_fail (GLADE_IS_PROPERTY (property), FALSE);
1000 
1001   va_start (vl, property);
1002   success = glade_property_set_va_list (property, vl);
1003   va_end (vl);
1004 
1005   return success;
1006 }
1007 
1008 /**
1009  * glade_property_get_value:
1010  * @property: a #GladeProperty
1011  * @value: a #GValue
1012  *
1013  * Retrieve the property value
1014  */
1015 void
glade_property_get_value(GladeProperty * property,GValue * value)1016 glade_property_get_value (GladeProperty *property, GValue *value)
1017 {
1018   g_return_if_fail (GLADE_IS_PROPERTY (property));
1019   g_return_if_fail (value != NULL);
1020   GLADE_PROPERTY_GET_KLASS (property)->get_value (property, value);
1021 }
1022 
1023 /**
1024  * glade_property_get_default:
1025  * @property: a #GladeProperty
1026  * @value: a #GValue
1027  *
1028  * Retrieve the default property value
1029  */
1030 void
glade_property_get_default(GladeProperty * property,GValue * value)1031 glade_property_get_default (GladeProperty *property, GValue *value)
1032 {
1033   GParamSpec *pspec;
1034 
1035   g_return_if_fail (GLADE_IS_PROPERTY (property));
1036   g_return_if_fail (value != NULL);
1037 
1038   pspec = glade_property_class_get_pspec (property->priv->klass);
1039   g_value_init (value, pspec->value_type);
1040   g_value_copy (glade_property_class_get_default (property->priv->klass), value);
1041 }
1042 
1043 /**
1044  * glade_property_get_va_list:
1045  * @property: a #GladeProperty
1046  * @vl: a va_list
1047  *
1048  * Retrieve the property value
1049  */
1050 void
glade_property_get_va_list(GladeProperty * property,va_list vl)1051 glade_property_get_va_list (GladeProperty *property, va_list vl)
1052 {
1053   g_return_if_fail (GLADE_IS_PROPERTY (property));
1054   glade_property_class_set_vl_from_gvalue (property->priv->klass, property->priv->value,
1055                                            vl);
1056 }
1057 
1058 /**
1059  * glade_property_get:
1060  * @property: a #GladeProperty
1061  * @...: An address to store the value
1062  *
1063  * Retrieve the property value
1064  */
1065 void
glade_property_get(GladeProperty * property,...)1066 glade_property_get (GladeProperty *property, ...)
1067 {
1068   va_list vl;
1069 
1070   g_return_if_fail (GLADE_IS_PROPERTY (property));
1071 
1072   va_start (vl, property);
1073   glade_property_get_va_list (property, vl);
1074   va_end (vl);
1075 }
1076 
1077 /**
1078  * glade_property_sync:
1079  * @property: a #GladeProperty
1080  *
1081  * Synchronize the object with this property
1082  */
1083 void
glade_property_sync(GladeProperty * property)1084 glade_property_sync (GladeProperty *property)
1085 {
1086   g_return_if_fail (GLADE_IS_PROPERTY (property));
1087   GLADE_PROPERTY_GET_KLASS (property)->sync (property);
1088 }
1089 
1090 /**
1091  * glade_property_load:
1092  * @property: a #GladeProperty
1093  *
1094  * Loads the value of @property from the coresponding object instance
1095  */
1096 void
glade_property_load(GladeProperty * property)1097 glade_property_load (GladeProperty *property)
1098 {
1099   g_return_if_fail (GLADE_IS_PROPERTY (property));
1100   GLADE_PROPERTY_GET_KLASS (property)->load (property);
1101 }
1102 
1103 /**
1104  * glade_property_read:
1105  * @property: a #GladeProperty or #NULL
1106  * @project: the #GladeProject
1107  * @node: the #GladeXmlNode to read, will either be a 'widget'
1108  *        node or a 'child' node for packing properties.
1109  *
1110  * Read the value and any attributes for @property from @node, assumes
1111  * @property is being loaded for @project
1112  *
1113  * Note that object values will only be resolved after the project is
1114  * completely loaded
1115  */
1116 void
glade_property_read(GladeProperty * property,GladeProject * project,GladeXmlNode * prop)1117 glade_property_read (GladeProperty *property,
1118                      GladeProject  *project,
1119                      GladeXmlNode  *prop)
1120 {
1121   GValue *gvalue = NULL;
1122   gchar /* *id, *name, */  * value;
1123   gint translatable = FALSE;
1124   gchar *comment = NULL, *context = NULL;
1125 
1126   g_return_if_fail (GLADE_IS_PROPERTY (property));
1127   g_return_if_fail (GLADE_IS_PROJECT (project));
1128   g_return_if_fail (prop != NULL);
1129 
1130   if (!glade_xml_node_verify (prop, GLADE_XML_TAG_PROPERTY))
1131     return;
1132 
1133   if (!(value = glade_xml_get_content (prop)))
1134     return;
1135 
1136   /* If an optional property is specified in the
1137    * glade file, its enabled
1138    */
1139   property->priv->enabled = TRUE;
1140 
1141   if (glade_property_class_is_object (property->priv->klass))
1142     {
1143       /* we must synchronize this directly after loading this project
1144        * (i.e. lookup the actual objects after they've been parsed and
1145        * are present).
1146        */
1147       g_object_set_data_full (G_OBJECT (property),
1148                               "glade-loaded-object", g_strdup (value), g_free);
1149     }
1150   else
1151     {
1152       gvalue =
1153 	glade_property_class_make_gvalue_from_string (property->priv->klass, value, project);
1154 
1155       GLADE_PROPERTY_GET_KLASS (property)->set_value (property, gvalue);
1156 
1157       g_value_unset (gvalue);
1158       g_free (gvalue);
1159     }
1160 
1161   translatable =
1162       glade_xml_get_property_boolean (prop, GLADE_TAG_TRANSLATABLE, FALSE);
1163   comment = glade_xml_get_property_string (prop, GLADE_TAG_COMMENT);
1164   context = glade_xml_get_property_string (prop, GLADE_TAG_CONTEXT);
1165 
1166   glade_property_i18n_set_translatable (property, translatable);
1167   glade_property_i18n_set_comment (property, comment);
1168   glade_property_i18n_set_context (property, context);
1169 
1170   g_free (comment);
1171   g_free (context);
1172   g_free (value);
1173 }
1174 
1175 
1176 /**
1177  * glade_property_write:
1178  * @property: a #GladeProperty
1179  * @context: A #GladeXmlContext
1180  * @node: A #GladeXmlNode
1181  *
1182  * Write @property to @node
1183  */
1184 void
glade_property_write(GladeProperty * property,GladeXmlContext * context,GladeXmlNode * node)1185 glade_property_write (GladeProperty   *property,
1186                       GladeXmlContext *context,
1187                       GladeXmlNode    *node)
1188 {
1189   GladeXmlNode *prop_node;
1190   gchar *name, *value;
1191   gboolean save_always;
1192 
1193   g_return_if_fail (GLADE_IS_PROPERTY (property));
1194   g_return_if_fail (node != NULL);
1195 
1196   /* This code should work the same for <packing>, <widget> and <template> */
1197   if (!(glade_xml_node_verify_silent (node, GLADE_XML_TAG_PACKING) ||
1198         glade_xml_node_verify_silent (node, GLADE_XML_TAG_WIDGET) ||
1199 	glade_xml_node_verify_silent (node, GLADE_XML_TAG_TEMPLATE)))
1200     return;
1201 
1202   /* There can be a couple of reasons to forcefully save a property */
1203   save_always = (glade_property_class_save_always (property->priv->klass) || property->priv->save_always);
1204   save_always = save_always || (glade_property_class_optional (property->priv->klass) && property->priv->enabled);
1205 
1206   /* Skip properties that are default by original pspec default
1207    * (excepting those that specified otherwise).
1208    */
1209   if (!save_always && glade_property_original_default (property))
1210     return;
1211 
1212   /* Escape our string and save with underscores */
1213   name = g_strdup (glade_property_class_id (property->priv->klass));
1214   glade_util_replace (name, '-', '_');
1215 
1216   /* convert the value of this property to a string */
1217   if (!(value = glade_widget_adaptor_string_from_value
1218         (glade_property_class_get_adaptor (property->priv->klass), property->priv->klass,
1219          property->priv->value)))
1220     /* make sure we keep the empty string, also... upcomming
1221      * funcs that may not like NULL.
1222      */
1223     value = g_strdup ("");
1224 
1225   /* Now dump the node values... */
1226   prop_node = glade_xml_node_new (context, GLADE_XML_TAG_PROPERTY);
1227   glade_xml_node_append_child (node, prop_node);
1228 
1229   /* Name and value */
1230   glade_xml_node_set_property_string (prop_node, GLADE_XML_TAG_NAME, name);
1231   glade_xml_set_content (prop_node, value);
1232 
1233   /* i18n stuff */
1234   if (glade_property_class_translatable (property->priv->klass))
1235     {
1236       if (property->priv->i18n_translatable)
1237         glade_xml_node_set_property_string (prop_node,
1238                                             GLADE_TAG_TRANSLATABLE,
1239                                             GLADE_XML_TAG_I18N_TRUE);
1240 
1241       if (property->priv->i18n_context)
1242         glade_xml_node_set_property_string (prop_node,
1243                                             GLADE_TAG_CONTEXT,
1244                                             property->priv->i18n_context);
1245 
1246       if (property->priv->i18n_comment)
1247         glade_xml_node_set_property_string (prop_node,
1248                                             GLADE_TAG_COMMENT,
1249                                             property->priv->i18n_comment);
1250     }
1251   g_free (name);
1252   g_free (value);
1253 }
1254 
1255 /**
1256  * glade_property_add_object:
1257  * @property: a #GladeProperty
1258  * @object: The #GObject to add
1259  *
1260  * Adds @object to the object list in @property.
1261  *
1262  * Note: This function expects @property to be a #GladeParamSpecObjects
1263  * or #GParamSpecObject type property.
1264  */
1265 void
glade_property_add_object(GladeProperty * property,GObject * object)1266 glade_property_add_object (GladeProperty *property, GObject *object)
1267 {
1268   GList *list = NULL, *new_list = NULL;
1269   GParamSpec *pspec;
1270 
1271   g_return_if_fail (GLADE_IS_PROPERTY (property));
1272   g_return_if_fail (G_IS_OBJECT (object));
1273 
1274   pspec = glade_property_class_get_pspec (property->priv->klass);
1275 
1276   g_return_if_fail (GLADE_IS_PARAM_SPEC_OBJECTS (pspec) ||
1277                     G_IS_PARAM_SPEC_OBJECT (pspec));
1278 
1279   if (GLADE_IS_PARAM_SPEC_OBJECTS (pspec))
1280     {
1281       glade_property_get (property, &list);
1282       new_list = g_list_copy (list);
1283 
1284       new_list = g_list_append (new_list, object);
1285       glade_property_set (property, new_list);
1286 
1287       /* ownership of the list is not passed
1288        * through glade_property_set()
1289        */
1290       g_list_free (new_list);
1291     }
1292   else
1293     {
1294       glade_property_set (property, object);
1295     }
1296 }
1297 
1298 /**
1299  * glade_property_remove_object:
1300  * @property: a #GladeProperty
1301  * @object: The #GObject to add
1302  *
1303  * Removes @object from the object list in @property.
1304  *
1305  * Note: This function expects @property to be a #GladeParamSpecObjects
1306  * or #GParamSpecObject type property.
1307  */
1308 void
glade_property_remove_object(GladeProperty * property,GObject * object)1309 glade_property_remove_object (GladeProperty *property, GObject *object)
1310 {
1311   GList *list = NULL, *new_list = NULL;
1312   GParamSpec *pspec;
1313 
1314   g_return_if_fail (GLADE_IS_PROPERTY (property));
1315   g_return_if_fail (G_IS_OBJECT (object));
1316 
1317   pspec = glade_property_class_get_pspec (property->priv->klass);
1318 
1319   g_return_if_fail (GLADE_IS_PARAM_SPEC_OBJECTS (pspec) ||
1320                     G_IS_PARAM_SPEC_OBJECT (pspec));
1321 
1322   if (GLADE_IS_PARAM_SPEC_OBJECTS (pspec))
1323     {
1324       /* If object isnt in list; list should stay in tact.
1325        * not bothering to check for now.
1326        */
1327       glade_property_get (property, &list);
1328       new_list = g_list_copy (list);
1329 
1330       new_list = g_list_remove (new_list, object);
1331       glade_property_set (property, new_list);
1332 
1333       /* ownership of the list is not passed
1334        * through glade_property_set()
1335        */
1336       g_list_free (new_list);
1337     }
1338   else
1339     {
1340       glade_property_set (property, NULL);
1341     }
1342 }
1343 
1344 GladePropertyClass *
glade_property_get_class(GladeProperty * property)1345 glade_property_get_class (GladeProperty *property)
1346 {
1347   g_return_val_if_fail (GLADE_IS_PROPERTY (property), NULL);
1348 
1349   return property->priv->klass;
1350 }
1351 
1352 
1353 /* Parameters for translatable properties. */
1354 void
glade_property_i18n_set_comment(GladeProperty * property,const gchar * str)1355 glade_property_i18n_set_comment (GladeProperty *property, const gchar *str)
1356 {
1357   g_return_if_fail (GLADE_IS_PROPERTY (property));
1358   if (property->priv->i18n_comment)
1359     g_free (property->priv->i18n_comment);
1360 
1361   property->priv->i18n_comment = g_strdup (str);
1362   g_object_notify_by_pspec (G_OBJECT (property), properties[PROP_I18N_COMMENT]);
1363 }
1364 
1365 G_CONST_RETURN gchar *
glade_property_i18n_get_comment(GladeProperty * property)1366 glade_property_i18n_get_comment (GladeProperty * property)
1367 {
1368   g_return_val_if_fail (GLADE_IS_PROPERTY (property), NULL);
1369   return property->priv->i18n_comment;
1370 }
1371 
1372 void
glade_property_i18n_set_context(GladeProperty * property,const gchar * str)1373 glade_property_i18n_set_context (GladeProperty *property, const gchar *str)
1374 {
1375   g_return_if_fail (GLADE_IS_PROPERTY (property));
1376   if (property->priv->i18n_context)
1377     g_free (property->priv->i18n_context);
1378 
1379   property->priv->i18n_context = g_strdup (str);
1380   g_object_notify_by_pspec (G_OBJECT (property), properties[PROP_I18N_CONTEXT]);
1381 }
1382 
1383 G_CONST_RETURN gchar *
glade_property_i18n_get_context(GladeProperty * property)1384 glade_property_i18n_get_context (GladeProperty *property)
1385 {
1386   g_return_val_if_fail (GLADE_IS_PROPERTY (property), NULL);
1387   return property->priv->i18n_context;
1388 }
1389 
1390 void
glade_property_i18n_set_translatable(GladeProperty * property,gboolean translatable)1391 glade_property_i18n_set_translatable (GladeProperty *property,
1392                                       gboolean      translatable)
1393 {
1394   g_return_if_fail (GLADE_IS_PROPERTY (property));
1395   property->priv->i18n_translatable = translatable;
1396   g_object_notify_by_pspec (G_OBJECT (property), properties[PROP_I18N_TRANSLATABLE]);
1397 }
1398 
1399 gboolean
glade_property_i18n_get_translatable(GladeProperty * property)1400 glade_property_i18n_get_translatable (GladeProperty *property)
1401 {
1402   g_return_val_if_fail (GLADE_IS_PROPERTY (property), FALSE);
1403   return property->priv->i18n_translatable;
1404 }
1405 
1406 void
glade_property_set_sensitive(GladeProperty * property,gboolean sensitive,const gchar * reason)1407 glade_property_set_sensitive (GladeProperty *property,
1408                               gboolean       sensitive,
1409                               const gchar   *reason)
1410 {
1411   g_return_if_fail (GLADE_IS_PROPERTY (property));
1412 
1413   /* reason is only why we're disableing it */
1414   if (sensitive == FALSE)
1415     {
1416       if (property->priv->insensitive_tooltip)
1417         g_free (property->priv->insensitive_tooltip);
1418       property->priv->insensitive_tooltip = g_strdup (reason);
1419     }
1420 
1421   if (property->priv->sensitive != sensitive)
1422     {
1423       property->priv->sensitive = sensitive;
1424 
1425       /* Clear it */
1426       if (sensitive)
1427         property->priv->insensitive_tooltip =
1428             (g_free (property->priv->insensitive_tooltip), NULL);
1429 
1430       g_signal_emit (G_OBJECT (property),
1431                      glade_property_signals[TOOLTIP_CHANGED],
1432                      0,
1433                      glade_property_class_get_tooltip (property->priv->klass),
1434                      property->priv->insensitive_tooltip,
1435 		     property->priv->support_warning);
1436     }
1437   g_object_notify_by_pspec (G_OBJECT (property), properties[PROP_SENSITIVE]);
1438 }
1439 
1440 G_CONST_RETURN gchar *
glade_propert_get_insensitive_tooltip(GladeProperty * property)1441 glade_propert_get_insensitive_tooltip (GladeProperty *property)
1442 {
1443   g_return_val_if_fail (GLADE_IS_PROPERTY (property), NULL);
1444 
1445   return property->priv->insensitive_tooltip;
1446 }
1447 
1448 gboolean
glade_property_get_sensitive(GladeProperty * property)1449 glade_property_get_sensitive (GladeProperty *property)
1450 {
1451   g_return_val_if_fail (GLADE_IS_PROPERTY (property), FALSE);
1452   return property->priv->sensitive;
1453 }
1454 
1455 void
glade_property_set_support_warning(GladeProperty * property,gboolean disable,const gchar * reason)1456 glade_property_set_support_warning (GladeProperty *property,
1457                                     gboolean       disable,
1458                                     const gchar   *reason)
1459 {
1460   gboolean warn_before, warn_after;
1461 
1462   g_return_if_fail (GLADE_IS_PROPERTY (property));
1463 
1464   /* Check pre-changed warning state */
1465   warn_before = glade_property_warn_usage (property);
1466 
1467   if (property->priv->support_warning)
1468     g_free (property->priv->support_warning);
1469   property->priv->support_warning = g_strdup (reason);
1470 
1471   property->priv->support_disabled = disable;
1472 
1473   g_signal_emit (G_OBJECT (property),
1474                  glade_property_signals[TOOLTIP_CHANGED],
1475                  0,
1476                  glade_property_class_get_tooltip (property->priv->klass),
1477                  property->priv->insensitive_tooltip,
1478 		 property->priv->support_warning);
1479 
1480   glade_property_fix_state (property);
1481 
1482   /* Check post-changed warning state */
1483   warn_after = glade_property_warn_usage (property);
1484 
1485   /* Update owning widget's warning state if need be */
1486   if (property->priv->widget != NULL && warn_before != warn_after)
1487     glade_widget_verify (property->priv->widget);
1488 }
1489 
1490 G_CONST_RETURN gchar *
glade_property_get_support_warning(GladeProperty * property)1491 glade_property_get_support_warning (GladeProperty *property)
1492 {
1493   g_return_val_if_fail (GLADE_IS_PROPERTY (property), NULL);
1494 
1495   return property->priv->support_warning;
1496 }
1497 
1498 gboolean
glade_property_warn_usage(GladeProperty * property)1499 glade_property_warn_usage (GladeProperty *property)
1500 {
1501   g_return_val_if_fail (GLADE_IS_PROPERTY (property), FALSE);
1502 
1503   if (!property->priv->support_warning)
1504     return FALSE;
1505 
1506   return ((property->priv->state & GLADE_STATE_CHANGED) != 0);
1507 }
1508 
1509 /**
1510  * glade_property_set_save_always:
1511  * @property: A #GladeProperty
1512  * @setting: the value to set
1513  *
1514  * Sets whether this property should be special cased
1515  * to always be saved regardless of its default value.
1516  * (used for some special cases like properties
1517  * that are assigned initial values in composite widgets
1518  * or derived widget code).
1519  */
1520 void
glade_property_set_save_always(GladeProperty * property,gboolean setting)1521 glade_property_set_save_always (GladeProperty *property, gboolean setting)
1522 {
1523   g_return_if_fail (GLADE_IS_PROPERTY (property));
1524 
1525   property->priv->save_always = setting;
1526 }
1527 
1528 /**
1529  * glade_property_get_save_always:
1530  * @property: A #GladeProperty
1531  *
1532  * Returns: whether this property is special cased
1533  * to always be saved regardless of its default value.
1534  */
1535 gboolean
glade_property_get_save_always(GladeProperty * property)1536 glade_property_get_save_always (GladeProperty *property)
1537 {
1538   g_return_val_if_fail (GLADE_IS_PROPERTY (property), FALSE);
1539 
1540   return property->priv->save_always;
1541 }
1542 
1543 void
glade_property_set_enabled(GladeProperty * property,gboolean enabled)1544 glade_property_set_enabled (GladeProperty *property, gboolean enabled)
1545 {
1546   gboolean warn_before, warn_after;
1547 
1548   g_return_if_fail (GLADE_IS_PROPERTY (property));
1549 
1550   /* Check pre-changed warning state */
1551   warn_before = glade_property_warn_usage (property);
1552 
1553   property->priv->enabled = enabled;
1554   glade_property_sync (property);
1555 
1556   glade_property_fix_state (property);
1557 
1558   /* Check post-changed warning state */
1559   warn_after = glade_property_warn_usage (property);
1560 
1561   /* Update owning widget's warning state if need be */
1562   if (property->priv->widget != NULL && warn_before != warn_after)
1563     glade_widget_verify (property->priv->widget);
1564 
1565   g_object_notify_by_pspec (G_OBJECT (property), properties[PROP_ENABLED]);
1566 }
1567 
1568 gboolean
glade_property_get_enabled(GladeProperty * property)1569 glade_property_get_enabled (GladeProperty * property)
1570 {
1571   g_return_val_if_fail (GLADE_IS_PROPERTY (property), FALSE);
1572   return property->priv->enabled;
1573 }
1574 
1575 gchar *
glade_property_make_string(GladeProperty * property)1576 glade_property_make_string (GladeProperty *property)
1577 {
1578   g_return_val_if_fail (GLADE_IS_PROPERTY (property), NULL);
1579 
1580   return glade_property_class_make_string_from_gvalue (property->priv->klass,
1581 						       property->priv->value);
1582 }
1583 
1584 void
glade_property_set_widget(GladeProperty * property,GladeWidget * widget)1585 glade_property_set_widget (GladeProperty *property,
1586 			   GladeWidget   *widget)
1587 {
1588   g_return_if_fail (GLADE_IS_PROPERTY (property));
1589 
1590   property->priv->widget = widget;
1591 }
1592 
1593 GladeWidget *
glade_property_get_widget(GladeProperty * property)1594 glade_property_get_widget (GladeProperty *property)
1595 {
1596   g_return_val_if_fail (GLADE_IS_PROPERTY (property), NULL);
1597 
1598   return property->priv->widget;
1599 }
1600 
1601 GValue *
glade_property_inline_value(GladeProperty * property)1602 glade_property_inline_value (GladeProperty *property)
1603 {
1604   g_return_val_if_fail (GLADE_IS_PROPERTY (property), NULL);
1605 
1606   return property->priv->value;
1607 }
1608 
1609 GladePropertyState
glade_property_get_state(GladeProperty * property)1610 glade_property_get_state (GladeProperty *property)
1611 {
1612   g_return_val_if_fail (GLADE_IS_PROPERTY (property), 0);
1613 
1614   return property->priv->state;
1615 }
1616 
1617 
1618 static gint glade_property_su_stack = 0;
1619 
1620 void
glade_property_push_superuser(void)1621 glade_property_push_superuser (void)
1622 {
1623   glade_property_su_stack++;
1624 }
1625 
1626 void
glade_property_pop_superuser(void)1627 glade_property_pop_superuser (void)
1628 {
1629   if (--glade_property_su_stack < 0)
1630     {
1631       g_critical ("Bug: property super user stack is corrupt.\n");
1632     }
1633 }
1634 
1635 gboolean
glade_property_superuser(void)1636 glade_property_superuser (void)
1637 {
1638   return glade_property_su_stack > 0;
1639 }
1640