source: trunk/third/bonobo/bonobo/bonobo-property-bag.c @ 16754

Revision 16754, 24.5 KB checked in by ghudson, 23 years ago (diff)
Merge with bonobo 1.0.14; remove ATHTOOLROOT support.
Line 
1/*
2 * bonobo-property-bag.c: property bag object implementation.
3 *
4 * Authors:
5 *   Nat Friedman  (nat@helixcode.com)
6 *   Michael Meeks (michael@helixcode.com)
7 *
8 * Copyright 1999, 2000 Helix Code, Inc.
9 */
10#include <config.h>
11#include <bonobo/Bonobo.h>
12#include <bonobo/bonobo-main.h>
13#include <bonobo/bonobo-exception.h>
14#include <bonobo/bonobo-property-bag.h>
15#include <bonobo/bonobo-property.h>
16#include <bonobo/bonobo-persist-stream.h>
17#include <bonobo/bonobo-transient.h>
18
19#define PARENT_TYPE BONOBO_X_OBJECT_TYPE
20
21static GtkObjectClass *parent_class = NULL;
22         
23
24/*
25 * Internal data structures.
26 */
27struct _BonoboPropertyBagPrivate {
28        GHashTable         *props;
29
30        BonoboPropertySetFn set_prop;
31        BonoboPropertyGetFn get_prop;
32        gpointer            user_data;
33
34        BonoboTransient    *transient;
35};
36
37
38/* BonoboPropertyBag CORBA methods.*/
39static void
40bonobo_property_bag_foreach_create_list (gpointer key,
41                                         gpointer value,
42                                         gpointer data)
43{
44        GList **l = (GList **) data;
45
46        *l = g_list_prepend (*l, value);
47}
48
49
50/**
51 * bonobo_property_bag_get_prop_list:
52 * @pb: A #BonoboPropertyBag.
53 *
54 * Returns a #GList of #BonoboProperty structures.  This function is
55 * private and should only be used internally, or in a PropertyBag
56 * persistence implementation.  You should not touch the
57 * #BonoboProperty structure unless you know what you're doing.
58 */
59GList *
60bonobo_property_bag_get_prop_list (BonoboPropertyBag *pb)
61{
62        GList *l;
63
64        g_return_val_if_fail (pb != NULL, NULL);
65        g_return_val_if_fail (BONOBO_IS_PROPERTY_BAG (pb), NULL);
66
67        l = NULL;
68
69        g_hash_table_foreach (pb->priv->props,
70                              bonobo_property_bag_foreach_create_list,
71                              &l);
72
73        return l;
74}
75
76static Bonobo_EventSource
77impl_Bonobo_PropertyBag_getEventSource (PortableServer_Servant servant,
78                                        CORBA_Environment      *ev)
79{
80        BonoboPropertyBag   *pb = BONOBO_PROPERTY_BAG (bonobo_object_from_servant (servant));
81
82        return bonobo_object_dup_ref (BONOBO_OBJREF (pb->es), ev);
83}
84
85static Bonobo_PropertyList *
86impl_Bonobo_PropertyBag_getProperties (PortableServer_Servant  servant,
87                                       CORBA_Environment      *ev)
88{
89        BonoboPropertyBag   *pb = BONOBO_PROPERTY_BAG (bonobo_object_from_servant (servant));
90        Bonobo_PropertyList *prop_list;
91        GList              *props;
92        GList              *curr;
93        int                 len;
94        int                 i;
95
96        /*
97         * Create the PropertyList and allocate space for the
98         * properties.
99         */
100        len = g_hash_table_size (pb->priv->props);
101
102        prop_list = Bonobo_PropertyList__alloc ();
103        prop_list->_length = len;
104
105        if (len == 0)
106                return prop_list;
107
108        prop_list->_buffer = CORBA_sequence_Bonobo_Property_allocbuf (len);
109
110        /*
111         * Create a list of Object references for the properties.
112         */
113        props = bonobo_property_bag_get_prop_list (pb);
114
115        i = 0;
116        for (curr = props; curr != NULL; curr = curr->next) {
117                BonoboProperty *prop = curr->data;
118
119                prop_list->_buffer [i] =  bonobo_transient_create_objref (
120                        pb->priv->transient, "IDL:Bonobo/Property:1.0",
121                        prop->name, ev);
122
123                if (BONOBO_EX (ev)) {
124                        g_warning ("BonoboPropertyBag: Could not create property objref!");
125                        g_list_free (props);
126                        CORBA_free (prop_list);
127                        return CORBA_OBJECT_NIL;
128                }
129
130                i++;
131               
132        }
133
134        g_list_free (props);
135
136        return prop_list;
137}
138
139static Bonobo_Property
140impl_Bonobo_PropertyBag_getPropertyByName (PortableServer_Servant servant,
141                                           const CORBA_char      *name,
142                                           CORBA_Environment     *ev)
143{
144        BonoboPropertyBag *pb = BONOBO_PROPERTY_BAG (bonobo_object_from_servant (servant));
145        Bonobo_Property    prop;
146
147        if (g_hash_table_lookup (pb->priv->props, name) == NULL) {
148
149                CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
150                                     ex_Bonobo_PropertyBag_NotFound,
151                                     NULL);
152
153                return CORBA_OBJECT_NIL;
154        }
155
156        prop = bonobo_transient_create_objref (pb->priv->transient,
157                                               "IDL:Bonobo/Property:1.0",
158                                                name, ev);
159
160        return prop;
161}
162
163static Bonobo_PropertyNames *
164impl_Bonobo_PropertyBag_getPropertyNames (PortableServer_Servant servant,
165                                          CORBA_Environment     *ev)
166{
167        BonoboPropertyBag        *pb = BONOBO_PROPERTY_BAG (bonobo_object_from_servant (servant));
168        Bonobo_PropertyNames    *name_list;
169        GList                   *props;
170        GList                   *curr;
171        int                      len;
172        int                      i;
173
174        /*
175         * Create the PropertyNames list and allocate space for the
176         * names.
177         */
178        len = g_hash_table_size (pb->priv->props);
179
180        name_list = Bonobo_PropertyNames__alloc ();
181        name_list->_length = len;
182
183        if (len == 0)
184                return name_list;
185
186        name_list->_buffer = CORBA_sequence_CORBA_string_allocbuf (len);
187
188        /*
189         * Create the list of property names.
190         */
191        props = bonobo_property_bag_get_prop_list (pb);
192
193        i = 0;
194        for (curr = props; curr != NULL; curr = curr->next) {
195                BonoboProperty *prop = curr->data;
196
197                name_list->_buffer [i] = CORBA_string_dup (prop->name);
198                i ++;
199        }
200
201        g_list_free (props);
202
203        return name_list;
204}
205
206static Bonobo_PropertySet *
207impl_Bonobo_PropertyBag_getValues (PortableServer_Servant  servant,
208                                   CORBA_Environment      *ev)
209{
210        BonoboPropertyBag   *pb = BONOBO_PROPERTY_BAG (bonobo_object_from_servant (servant));
211        Bonobo_PropertySet *set;
212        GList              *props;
213        GList              *curr;
214        int                 len;
215        int                 i;
216
217        /*
218         * Create the PropertyList and allocate space for the
219         * properties.
220         */
221        len = g_hash_table_size (pb->priv->props);
222
223        set = Bonobo_PropertySet__alloc ();
224        set->_length = len;
225
226        if (len == 0)
227                return set;
228
229        set->_buffer = CORBA_sequence_Bonobo_Pair_allocbuf (len);
230        CORBA_sequence_set_release (set, TRUE);
231
232        /*
233         * Create a list of Object references for the properties.
234         */
235        props = bonobo_property_bag_get_prop_list (pb);
236
237        i = 0;
238        for (curr = props; curr != NULL; curr = curr->next) {
239                BonoboProperty *prop = curr->data;
240                BonoboArg *arg;
241
242                set->_buffer [i].name =  CORBA_string_dup (prop->name);
243
244                arg = bonobo_arg_new (prop->type);
245       
246                prop->get_prop (pb, arg, prop->idx, ev,
247                                prop->user_data);
248
249                set->_buffer [i].value = *arg;
250
251                i++;           
252        }
253
254        g_list_free (props);
255
256        return set;
257}
258
259static void
260impl_Bonobo_PropertyBag_setValues (PortableServer_Servant    servant,
261                                   const Bonobo_PropertySet *set,
262                                   CORBA_Environment        *ev)
263{
264        BonoboPropertyBag   *pb = BONOBO_PROPERTY_BAG (bonobo_object_from_servant (servant));
265        int i;
266
267        for (i = 0; i < set->_length; i++) {
268
269                bonobo_property_bag_set_value (pb, set->_buffer [i].name,
270                                               &set->_buffer [i].value, ev);
271        }
272}
273
274
275/*
276 * BonoboPropertyBag construction/deconstruction functions.
277 */
278
279/**
280 * bonobo_property_bag_construct:
281 * @pb: #BonoboPropertyBag to construct
282 * @get_prop: the property get callback
283 * @set_prop: the property set callback
284 * @es: an event source to aggregate
285 * @user_data: user data for the callbacks
286 *
287 * Constructor, only for use in wrappers and object derivation, please
288 * refer to the #bonobo_property_bag_new for normal use.
289 *
290 * This function returns @pb, or %NULL in case of error.  If it returns %NULL,
291 * the passed in @pb is unrefed.
292 *
293 * Returns:  #BonoboPropertyBag pointer or %NULL.
294 */
295BonoboPropertyBag *
296bonobo_property_bag_construct (BonoboPropertyBag   *pb,
297                               BonoboPropertyGetFn  get_prop,
298                               BonoboPropertySetFn  set_prop,
299                               BonoboEventSource   *es,
300                               gpointer             user_data)
301{
302        pb->es              = es;
303        pb->priv->set_prop  = set_prop;
304        pb->priv->get_prop  = get_prop;
305        pb->priv->user_data = user_data;
306
307        bonobo_object_add_interface (BONOBO_OBJECT (pb), BONOBO_OBJECT (es));
308
309        if (!(pb->priv->transient = bonobo_transient_new (NULL, bonobo_property_servant_new, bonobo_property_servant_destroy, pb))) {
310                bonobo_object_unref (BONOBO_OBJECT (pb));
311                return NULL;
312        }
313       
314        return pb;
315}
316
317/**
318 * bonobo_property_bag_new_full:
319 * @get_prop: the property get callback
320 * @set_prop: the property set callback
321 * @es: an event source to aggregate
322 * @user_data: user data for the callbacks
323 *
324 * Creates a new property bag with the specified callbacks.
325 *
326 * Returns: A new #BonoboPropertyBag object.
327 */
328BonoboPropertyBag *
329bonobo_property_bag_new_full (BonoboPropertyGetFn  get_prop,
330                              BonoboPropertySetFn  set_prop,
331                              BonoboEventSource   *es,
332                              gpointer             user_data)
333{
334        BonoboPropertyBag *pb;
335
336        g_return_val_if_fail (es != NULL, NULL);
337
338        pb = gtk_type_new (BONOBO_PROPERTY_BAG_TYPE);
339
340        return bonobo_property_bag_construct (pb, get_prop, set_prop, es,
341                                              user_data);
342}
343
344/**
345 * bonobo_property_bag_new:
346 * @get_prop: the property get callback
347 * @set_prop: the property set callback
348 * @user_data: user data for the callbacks
349 *
350 * Creates a new property bag with the specified callbacks.
351 *
352 * Returns: A new #BonoboPropertyBag object.
353 */
354BonoboPropertyBag *
355bonobo_property_bag_new (BonoboPropertyGetFn get_prop,
356                         BonoboPropertySetFn set_prop,
357                         gpointer            user_data)
358{
359        BonoboEventSource *es;
360
361        es = bonobo_event_source_new ();
362
363        return bonobo_property_bag_new_full (get_prop, set_prop, es,
364                                             user_data);
365}
366
367static void
368bonobo_property_destroy (BonoboProperty *prop)
369{
370        g_free (prop->name);
371        prop->idx = -1;
372
373        bonobo_arg_release (prop->default_value);
374
375        g_free (prop->docstring);
376
377        g_free (prop);
378}
379
380static gboolean
381bonobo_property_bag_foreach_remove_prop (gpointer key,
382                                         gpointer value,
383                                         gpointer user_data)
384{
385        bonobo_property_destroy (value);
386
387        return TRUE;
388}
389
390static void
391bonobo_property_bag_destroy (GtkObject *object)
392{
393        BonoboPropertyBag *pb = BONOBO_PROPERTY_BAG (object);
394       
395        /* Destroy the transient POA */
396        gtk_object_unref (GTK_OBJECT (pb->priv->transient));
397
398        /* Destroy all properties. */
399        g_hash_table_foreach_remove (pb->priv->props,
400                                     bonobo_property_bag_foreach_remove_prop,
401                                     NULL);
402        g_hash_table_destroy (pb->priv->props);
403
404        g_free (pb->priv);
405
406        parent_class->destroy (object);
407}
408
409
410/*
411 * BonoboPropertyBag property manipulation API.
412 */
413
414/**
415 * bonobo_property_bag_add_full:
416 * @pb: property bag to add to
417 * @name: name of new property
418 * @idx: integer index for fast callback switch statement - NB.
419 * this value is opaque to the implementation, and is not used
420 * for keying properties.
421 * @type: the CORBA type eg. TC_long
422 * @default_value: the default value or NULL
423 * @docstring: the translated documentation string
424 * @flags: various flags
425 * @get_prop: a per property get callback
426 * @set_prop: a per property set callback
427 * @user_data: user data for the callbacks
428 *
429 * This adds a property to @pb at the full tilt of complexity.
430 **/
431void
432bonobo_property_bag_add_full (BonoboPropertyBag  *pb,
433                              const char         *name,
434                              int                 idx,
435                              BonoboArgType       type,
436                              BonoboArg          *default_value,
437                              const char         *docstring,
438                              BonoboPropertyFlags flags,
439                              BonoboPropertyGetFn get_prop,
440                              BonoboPropertySetFn set_prop,
441                              gpointer            user_data)
442{
443        BonoboProperty *prop;
444
445        g_return_if_fail (pb != NULL);
446        g_return_if_fail (BONOBO_IS_PROPERTY_BAG (pb));
447        g_return_if_fail (name != NULL);
448        g_return_if_fail (type != NULL);
449        g_return_if_fail (g_hash_table_lookup (pb->priv->props, name) == NULL);
450
451        if (flags == 0) { /* Compatibility hack */
452                flags = BONOBO_PROPERTY_READABLE |
453                        BONOBO_PROPERTY_WRITEABLE;
454        }
455                           
456        if (((flags & BONOBO_PROPERTY_READABLE)  && !get_prop) ||
457            ((flags & BONOBO_PROPERTY_WRITEABLE) && !set_prop)) {
458                g_warning ("Serious property error, missing get/set fn. "
459                           "on %s", name);
460                return;
461        }
462
463        if (!(flags & BONOBO_PROPERTY_READABLE) && default_value)
464                g_warning ("Assigning a default value to a non readable "
465                           "property '%s'", name);
466
467        prop = g_new0 (BonoboProperty, 1);
468
469        prop->name          = g_strdup (name);
470        prop->idx           = idx;
471        prop->type          = type;
472        prop->docstring     = g_strdup (docstring);
473        prop->flags         = flags;
474        prop->get_prop      = get_prop;
475        prop->set_prop      = set_prop;
476        prop->user_data     = user_data;
477
478        if (default_value)
479                prop->default_value = bonobo_arg_copy (default_value);
480
481        g_hash_table_insert (pb->priv->props, prop->name, prop);
482}
483
484static BonoboPropertyFlags
485flags_gtk_to_bonobo (guint flags)
486{
487        BonoboPropertyFlags f = 0;
488
489        if (!flags & GTK_ARG_READABLE)
490                f |= BONOBO_PROPERTY_READABLE;
491
492        if (!flags & GTK_ARG_WRITABLE)
493                f |= BONOBO_PROPERTY_WRITEABLE;
494
495        return f;
496}
497
498#define BONOBO_GTK_MAP_KEY "BonoboGtkMapKey"
499
500static void
501get_prop (BonoboPropertyBag *bag,
502          BonoboArg         *arg,
503          guint              arg_id,
504          CORBA_Environment *ev,
505          gpointer           user_data)
506{
507        GtkArg *gtk_arg = user_data;
508        GtkArg  new;
509        GtkObject *obj;
510
511        if (!(obj = gtk_object_get_data (GTK_OBJECT (bag),
512                                         BONOBO_GTK_MAP_KEY))) {
513                bonobo_exception_set (ev, ex_Bonobo_PropertyBag_NotFound);
514                return;
515        }
516       
517/*      g_warning ("Get prop ... %d: %s", arg_id, gtk_arg->name);*/
518
519        new.type = gtk_arg->type;
520        new.name = gtk_arg->name;
521        gtk_object_getv (obj, 1, &new);
522
523        bonobo_arg_from_gtk (arg, &new);
524
525        if (new.type == GTK_TYPE_STRING &&
526            GTK_VALUE_STRING (new))
527                g_free (GTK_VALUE_STRING (new));
528}
529
530static void
531set_prop (BonoboPropertyBag *bag,
532          const BonoboArg   *arg,
533          guint              arg_id,
534          CORBA_Environment *ev,
535          gpointer           user_data)
536{
537        GtkArg *gtk_arg = user_data;
538        GtkArg  new;
539        GtkObject *obj;
540
541        if (!(obj = gtk_object_get_data (GTK_OBJECT (bag),
542                                         BONOBO_GTK_MAP_KEY))) {
543                bonobo_exception_set (ev, ex_Bonobo_PropertyBag_NotFound);
544                return;
545        }
546               
547/*      g_warning ("Set prop ... %d: %s", arg_id, gtk_arg->name);*/
548
549        new.type = gtk_arg->type;
550        new.name = gtk_arg->name;
551        bonobo_arg_to_gtk (&new, arg);
552
553        gtk_object_setv (obj, 1, &new);
554}
555
556/**
557 * bonobo_property_bag_add_gtk_args:
558 * @pb: destination property bag
559 * @object: a generic Gtk Object
560 *
561 * Transfers GtkArgs from the object to the property bag,
562 * and maps between the two objects property systems.
563 **/
564void
565bonobo_property_bag_add_gtk_args (BonoboPropertyBag  *pb,
566                                  GtkObject          *object)
567{
568        GtkArg  *args, *arg;
569        guint32 *arg_flags;
570        guint    nargs = 0;
571        int      i;
572
573        g_return_if_fail (pb != NULL);
574        g_return_if_fail (BONOBO_IS_PROPERTY_BAG (pb));
575        g_return_if_fail (object != NULL);
576        g_return_if_fail (GTK_IS_OBJECT (object));
577
578        if (gtk_object_get_data (GTK_OBJECT (pb),
579                                 BONOBO_GTK_MAP_KEY)) {
580                g_warning ("Cannot proxy two gtk objects in the same bag yet");
581                return;
582        }
583
584        gtk_object_set_data (GTK_OBJECT (pb),
585                             BONOBO_GTK_MAP_KEY, object);
586        /*
587         * FIXME: we should do this on a per class basis perhaps.
588         */
589        args = gtk_object_query_args (GTK_OBJECT_TYPE (object),
590                                      &arg_flags, &nargs);
591       
592        if (!nargs) {
593                g_warning ("Strange, no Gtk arguments to map to Bonobo");
594                return;
595        }
596
597        arg = args;
598        /* Setup types, and names */
599        for (i = 0; i < nargs; arg++, i++) {
600                BonoboPropertyFlags flags;
601                BonoboArgType       type;
602                char               *desc;
603
604                type = bonobo_arg_type_from_gtk (arg->type);
605                if (!type) {
606                        g_warning ("Can't handle type '%s' on arg '%s'",
607                                   gtk_type_name (arg->type),
608                                   arg->name);
609                        continue;
610                }
611
612                flags = flags_gtk_to_bonobo (arg_flags [i]);
613
614                desc = g_strconcat (arg->name, " is a ",
615                                    gtk_type_name (arg->type), NULL);
616
617                g_warning ("Mapping '%s'", desc);
618                bonobo_property_bag_add_full (pb, arg->name, i, type,
619                                              NULL, desc, flags,
620                                              get_prop, set_prop, arg);
621                g_free (desc);
622        }
623
624/* FIXME: leaks like a privatised water company */
625/*      g_free (args);*/
626        g_free (arg_flags);
627}
628
629/**
630 * bonobo_property_bag_add:
631 * @pb: property bag to add to
632 * @name: name of new property
633 * @idx: integer index for fast callback switch statement
634 * this value is opaque to the implementation, and is not used
635 * for keying properties.
636 * @type: the CORBA type eg. TC_long
637 * @default_value: the default value or NULL
638 * @docstring: the translated documentation string
639 * @flags: various flags
640 *
641 *  Adds a property to the property bag.
642 **/
643void
644bonobo_property_bag_add (BonoboPropertyBag  *pb,
645                         const char         *name,
646                         int                 idx,
647                         BonoboArgType       type,
648                         BonoboArg          *default_value,
649                         const char         *docstring,
650                         BonoboPropertyFlags flags)
651{
652        g_return_if_fail (pb != NULL);
653
654        bonobo_property_bag_add_full (pb, name, idx, type,
655                                             default_value, docstring, flags,
656                                             pb->priv->get_prop,
657                                             pb->priv->set_prop,
658                                             pb->priv->user_data);
659}
660
661static void
662notify_listeners (BonoboPropertyBag *pb,
663                  BonoboProperty    *prop,
664                  const BonoboArg   *new_value,
665                  CORBA_Environment *opt_ev)
666{
667        if (prop->flags & BONOBO_PROPERTY_NO_LISTENING)
668                return;
669       
670        bonobo_event_source_notify_listeners_full (pb->es,
671                                                   "Bonobo/Property",
672                                                   "change", prop->name,
673                                                   new_value, opt_ev);
674}
675
676/**
677 * bonobo_property_bag_notify_listeners:
678 * @pb: the property bag
679 * @name: the name of the property that changed value
680 * @new_value: the new value
681 * @opt_ev: optional CORBA exception environment or NULL
682 *
683 * This function is used by the implementation of the property
684 * proper, to signal to the property bag that the value of the
685 * property has changed.
686 * NB. There is no need to call this when you do a set_value.
687 **/
688void
689bonobo_property_bag_notify_listeners (BonoboPropertyBag *pb,
690                                      const char        *name,
691                                      const BonoboArg   *new_value,
692                                      CORBA_Environment *opt_ev)
693{
694        BonoboProperty *prop;
695
696        bonobo_return_if_fail (pb != NULL, opt_ev);
697        bonobo_return_if_fail (BONOBO_IS_PROPERTY_BAG (pb), opt_ev);
698        bonobo_return_if_fail (name != NULL, opt_ev);
699        bonobo_return_if_fail (pb->priv != NULL, opt_ev);
700        bonobo_return_if_fail (new_value != NULL, opt_ev);
701
702        if (!(prop = g_hash_table_lookup (pb->priv->props, name))) {
703                bonobo_exception_set (opt_ev, ex_Bonobo_PropertyBag_NotFound);
704                return;
705        }
706
707        if (!bonobo_arg_type_is_equal (prop->type, new_value->_type, opt_ev)) {
708                bonobo_exception_set (opt_ev, ex_Bonobo_Property_InvalidValue);
709                return;
710        }
711
712        notify_listeners (pb, prop, new_value, opt_ev);
713}
714
715/**
716 * bonobo_property_bag_set_value:
717 * @pb: the property bag
718 * @name: the name of the property
719 * @value: the new value to set to
720 * @opt_ev: optional CORBA exception environment or NULL
721 *
722 * This method sets the value of the property with @name
723 * to @value.
724 **/
725void
726bonobo_property_bag_set_value (BonoboPropertyBag *pb,
727                               const char        *name,
728                               const BonoboArg   *value,
729                               CORBA_Environment *opt_ev)
730{
731        BonoboProperty *prop;
732        CORBA_Environment ev, *my_ev;
733
734        bonobo_return_if_fail (pb != NULL, opt_ev);
735        bonobo_return_if_fail (BONOBO_IS_PROPERTY_BAG (pb), opt_ev);
736        bonobo_return_if_fail (name != NULL, opt_ev);
737        bonobo_return_if_fail (pb->priv != NULL, opt_ev);
738        bonobo_return_if_fail (value != NULL, opt_ev);
739       
740        prop = g_hash_table_lookup (pb->priv->props, name);
741
742        if (!prop || !prop->set_prop) {
743                bonobo_exception_set (opt_ev, ex_Bonobo_PropertyBag_NotFound);
744                return;
745        }
746
747        if (!(prop->flags & BONOBO_PROPERTY_WRITEABLE)) {
748                bonobo_exception_set (opt_ev, ex_Bonobo_Property_ReadOnlyProperty);
749                return;
750        }
751
752        if (!bonobo_arg_type_is_equal (prop->type, value->_type, opt_ev)) {
753                bonobo_exception_set (opt_ev, ex_Bonobo_Property_InvalidValue);
754                return;
755        }
756
757        if (!opt_ev) {
758                CORBA_exception_init (&ev);
759                my_ev = &ev;
760        } else
761                my_ev = opt_ev;
762
763        prop->set_prop (pb, value, prop->idx, my_ev, prop->user_data);
764
765        if (!BONOBO_EX (my_ev))
766                notify_listeners (pb, prop, value, my_ev);
767
768        if (!opt_ev)
769                CORBA_exception_free (&ev);
770}
771
772/**
773 * bonobo_property_bag_get_value:
774 * @pb: the property bag
775 * @name: the name of the property
776 * @opt_ev: optional CORBA exception environment or NULL
777 *
778 * Return value: the value of the property with name @name or NULL
779 * on exception.
780 **/
781BonoboArg *
782bonobo_property_bag_get_value (BonoboPropertyBag *pb,
783                               const char        *name,
784                               CORBA_Environment *opt_ev)
785{
786        BonoboProperty    *prop;
787        BonoboArg         *arg;
788        CORBA_Environment  ev, *my_ev;
789
790        bonobo_return_val_if_fail (pb != NULL, NULL, opt_ev);
791        bonobo_return_val_if_fail (BONOBO_IS_PROPERTY_BAG (pb), NULL, opt_ev);
792        bonobo_return_val_if_fail (name != NULL, NULL, opt_ev);
793        bonobo_return_val_if_fail (pb->priv != NULL, NULL, opt_ev);
794
795        prop = g_hash_table_lookup (pb->priv->props, name);
796
797        if (!prop || !prop->get_prop) {
798                bonobo_exception_set (opt_ev, ex_Bonobo_PropertyBag_NotFound);
799                return NULL;
800        }
801
802        if (!opt_ev) {
803                CORBA_exception_init (&ev);
804                my_ev = &ev;
805        } else
806                my_ev = opt_ev;
807
808        arg = bonobo_arg_new (prop->type);
809
810        prop->get_prop (pb, arg, prop->idx, my_ev, prop->user_data);
811
812        if (!opt_ev)
813                CORBA_exception_free (&ev);
814
815        return arg;
816}
817
818/**
819 * bonobo_property_bag_get_property_type:
820 * @pb: the property bag
821 * @name: the name of the property
822 * @opt_ev: optional CORBA exception environment or NULL
823 *
824 * Return value: the type of the property with name @name
825 **/
826BonoboArgType
827bonobo_property_bag_get_property_type (BonoboPropertyBag *pb,
828                                       const char        *name,
829                                       CORBA_Environment *opt_ev)
830{
831        BonoboProperty *prop;
832
833        bonobo_return_val_if_fail (pb != NULL, NULL, opt_ev);
834        bonobo_return_val_if_fail (BONOBO_IS_PROPERTY_BAG (pb), NULL, opt_ev);
835        bonobo_return_val_if_fail (name != NULL, NULL, opt_ev);
836        bonobo_return_val_if_fail (pb->priv != NULL, NULL, opt_ev);
837
838        if (!(prop = g_hash_table_lookup (pb->priv->props, name))) {
839                bonobo_exception_set (opt_ev, ex_Bonobo_PropertyBag_NotFound);
840                return NULL;
841        }
842
843        return prop->type;
844}
845
846/**
847 * bonobo_property_bag_get_default:
848 * @pb: the property bag
849 * @name: the name of the property
850 * @opt_ev: optional CORBA exception environment or NULL
851 *
852 * Return value: the default value of the property with name @name
853 **/
854BonoboArg *
855bonobo_property_bag_get_default (BonoboPropertyBag *pb,
856                                 const char        *name,
857                                 CORBA_Environment *opt_ev)
858{
859        BonoboProperty *prop;
860
861        bonobo_return_val_if_fail (pb != NULL, NULL, opt_ev);
862        bonobo_return_val_if_fail (BONOBO_IS_PROPERTY_BAG (pb), NULL, opt_ev);
863        bonobo_return_val_if_fail (name != NULL, NULL, opt_ev);
864        bonobo_return_val_if_fail (pb->priv != NULL, NULL, opt_ev);
865
866        if (!(prop = g_hash_table_lookup (pb->priv->props, name))) {
867                bonobo_exception_set (opt_ev, ex_Bonobo_PropertyBag_NotFound);
868                return NULL;
869        }
870
871        if (prop->default_value)
872                return bonobo_arg_copy (prop->default_value);
873        else {
874                BonoboArg *a = bonobo_arg_new (prop->type);
875                return a;
876        }
877}
878
879/**
880 * bonobo_property_bag_get_default:
881 * @pb: the property bag
882 * @name: the name of the property
883 *
884 * Return value: TRUE if the bag has a property of this name
885 **/
886gboolean
887bonobo_property_bag_has_property (BonoboPropertyBag *pb,
888                                  const char        *name)
889{
890        g_return_val_if_fail (pb != NULL, FALSE);
891        g_return_val_if_fail (BONOBO_IS_PROPERTY_BAG (pb), FALSE);
892        g_return_val_if_fail (name != NULL, FALSE);
893        g_return_val_if_fail (pb->priv != NULL, FALSE);
894
895        if (g_hash_table_lookup (pb->priv->props, name) == NULL)
896                return FALSE;
897
898        return TRUE;
899}
900
901/**
902 * bonobo_property_bag_get_docstring:
903 * @pb: the property bag
904 * @name: the name of the property
905 * @opt_ev: optional CORBA exception environment or NULL
906 *
907 * Return value: the documentation string for this property.
908 **/
909const char *
910bonobo_property_bag_get_docstring (BonoboPropertyBag *pb,
911                                   const char        *name,
912                                   CORBA_Environment *opt_ev)
913{
914        BonoboProperty *prop;
915
916        bonobo_return_val_if_fail (pb != NULL, NULL, opt_ev);
917        bonobo_return_val_if_fail (BONOBO_IS_PROPERTY_BAG (pb), NULL, opt_ev);
918        bonobo_return_val_if_fail (name != NULL, NULL, opt_ev);
919        bonobo_return_val_if_fail (pb->priv != NULL, NULL, opt_ev);
920
921        if (!(prop = g_hash_table_lookup (pb->priv->props, name))) {
922                bonobo_exception_set (opt_ev, ex_Bonobo_PropertyBag_NotFound);
923                return NULL;
924        }
925
926        return prop->docstring;
927}
928
929/**
930 * bonobo_property_bag_get_flags:
931 */
932const BonoboPropertyFlags
933bonobo_property_bag_get_flags (BonoboPropertyBag *pb,
934                               const char        *name,
935                               CORBA_Environment *opt_ev)
936{
937        BonoboProperty *prop;
938
939        bonobo_return_val_if_fail (pb != NULL, 0, opt_ev);
940        bonobo_return_val_if_fail (BONOBO_IS_PROPERTY_BAG (pb), 0, opt_ev);
941        bonobo_return_val_if_fail (name != NULL, 0, opt_ev);
942        bonobo_return_val_if_fail (pb->priv != NULL, 0, opt_ev);
943
944        if (!(prop = g_hash_table_lookup (pb->priv->props, name))) {
945                bonobo_exception_set (opt_ev, ex_Bonobo_PropertyBag_NotFound);
946                return 0;
947        }
948
949        return prop->flags;
950}
951
952
953/* Class/object initialization functions. */
954
955static void
956bonobo_property_bag_class_init (BonoboPropertyBagClass *klass)
957{
958        GtkObjectClass *object_class = (GtkObjectClass *) klass;
959        POA_Bonobo_PropertyBag__epv *epv = &klass->epv;
960
961        parent_class = gtk_type_class (PARENT_TYPE);
962
963        object_class->destroy = bonobo_property_bag_destroy;
964
965        epv->getProperties        = impl_Bonobo_PropertyBag_getProperties;
966        epv->getPropertyByName    = impl_Bonobo_PropertyBag_getPropertyByName;
967        epv->getPropertyNames     = impl_Bonobo_PropertyBag_getPropertyNames;
968        epv->getEventSource       = impl_Bonobo_PropertyBag_getEventSource;
969        epv->getValues            = impl_Bonobo_PropertyBag_getValues;
970        epv->setValues            = impl_Bonobo_PropertyBag_setValues;
971}
972
973static void
974bonobo_property_bag_init (BonoboPropertyBag *pb)
975{
976        pb->priv = g_new0 (BonoboPropertyBagPrivate, 1);
977
978        pb->priv->props = g_hash_table_new (g_str_hash, g_str_equal);
979}
980
981BONOBO_X_TYPE_FUNC_FULL (BonoboPropertyBag,
982                         Bonobo_PropertyBag,
983                         PARENT_TYPE,
984                         bonobo_property_bag);
Note: See TracBrowser for help on using the repository browser.