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