summaryrefslogtreecommitdiff
path: root/glib/glibmm/property.h
blob: dadc0f29a5267153e7e83b6d82ab54728e3f3aa7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
// -*- c++ -*-
#ifndef _GLIBMM_PROPERTY_H
#define _GLIBMM_PROPERTY_H

/* Copyright 2002 The gtkmm Development Team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <glibmmconfig.h>
#include <glibmm/propertyproxy.h>


#include <glibmm/value.h>

namespace Glib
{

#ifndef DOXYGEN_SHOULD_SKIP_THIS

#ifdef GLIBMM_CXX_CAN_USE_NAMESPACES_INSIDE_EXTERNC
//For the AIX xlC compiler, I can not find a way to do this without putting the functions in the global namespace. murrayc
extern "C"
{
#endif //GLIBMM_CXX_CAN_USE_NAMESPACES_INSIDE_EXTERNC

void custom_get_property_callback(GObject* object, unsigned int property_id,
                                  GValue* value, GParamSpec* param_spec);

void custom_set_property_callback(GObject* object, unsigned int property_id,
                                  const GValue* value, GParamSpec* param_spec);

#ifdef GLIBMM_CXX_CAN_USE_NAMESPACES_INSIDE_EXTERNC
} //extern "C"
#endif //GLIBMM_CXX_CAN_USE_NAMESPACES_INSIDE_EXTERNC

#endif /* DOXYGEN_SHOULD_SKIP_THIS */

/** This is the base class for Glib::Object properties.
 *
 * This class manages the generic parts of the object properties.
 * Derived (templated) classes handle the specific value types.
 */
class PropertyBase
{
public:

  // noncopyable
  PropertyBase(const PropertyBase&) = delete;
  PropertyBase& operator=(const PropertyBase&) = delete;

  /** Returns the name of the property.
   */
  Glib::ustring get_name() const;

  /** Notifies the object containing the property that the property has changed.
   * This emits the "notify" signal, passing the property name.
   */
  void notify();

protected:
  Glib::Object*   object_;
  Glib::ValueBase value_;
  GParamSpec*     param_spec_;

  /** This constructs a property of type @a value_type for the @a object.
   * The property is not registered in the GObject object system
   * until install_property() has been called. Derived classes do this in
   * their constructors.
   *
   * The properties are usually installed during the initialization of the
   * first instance of an object.
   */
  PropertyBase(Glib::Object& object, GType value_type);
  ~PropertyBase();

  /**
   * Checks if the property has already been installed.
   */
  bool lookup_property(const Glib::ustring& name);

  /**
   * Installs the property specified by the given @a param_spec.
   */
  void install_property(GParamSpec* param_spec);

  /**
   * Returns the name of the property.
   */
  const char* get_name_internal() const;

private:

#ifndef DOXYGEN_SHOULD_SKIP_THIS

  friend void Glib::custom_get_property_callback(GObject* object, unsigned int property_id,
                                                 GValue* value, GParamSpec* param_spec);

  friend void Glib::custom_set_property_callback(GObject* object, unsigned int property_id,
                                                 const GValue* value, GParamSpec* param_spec);

#endif /* DOXYGEN_SHOULD_SKIP_THIS */
};

/** A Glib::Object property.
 *
 * This class wraps a GObject property, providing a C++ API to the GObject property
 * system, for use with classes derived from Glib::Object or Glib::Interface.
 *
 * A property is a value associated with each instance of a type and some
 * class data for each property:
 *  * Its unique name, used to identify the property.
 *  * A human-readable nick name.
 *  * A short description.
 *  * The default value and the minimum and maximum bounds (depending on the type of the property).
 *  * Flags, defining, among other things, whether the property can be read or written.
 *
 * This Property class currently supports only the name and default value. The
 * minimum and maximum bounds are set to the full range of the value. The nick
 * and the explanation are set to empty. The flags are set to indicate that the
 * property can be both read from and written to.
 *
 * The class information must be installed into the GObject system once per
 * property, but this is handled automatically.
 *
 * A property can be used only as direct data member of a type, inheriting from
 * Glib::Object. A reference to the object must be passed to the constructor of
 * the property.
 *
 * You may register new properties for your class (actually for the underlying GType)
 * simply by adding a Property instance as a class member.
 * However, your constructor must call the Glib::ObjectBase constructor with a new GType name,
 * in order to register a new GType.
 *
 * Example:
 * @code
 * class MyCellRenderer : public Gtk::CellRenderer
 * {
 * public:
 *   MyCellRenderer()
 *   :
 *   Glib::ObjectBase (typeid(MyCellRenderer)),
 *   Gtk::CellRenderer(),
 *   property_mybool  (*this, "mybool", true),
 *   property_myint_  (*this, "myint",    42)
 *   {}
 *
 *   virtual ~MyCellRenderer() {}
 *
 *   // Glib::Property<> can be public,
 *   Glib::Property<bool> property_mybool;
 *   // or private, and combined with Glib::PropertyProxy<>.
 *   Glib::PropertyProxy<int> property_myint() { return property_myint_.get_proxy(); }
 *
 * private:
 *   Glib::Property<int> property_myint_;
 * };
 * @endcode
 */
template <class T>
class Property : public PropertyBase
{
public:
  typedef T PropertyType;
  typedef Glib::Value<T> ValueType;

  /**  Constructs a property of the @a object with the specified @a name.
   * For each instance of the object, the same property must be constructed with the same name.
   */
  Property(Glib::Object& object, const Glib::ustring& name);

  /** Constructs a property of the @a object with the specified @a name and @a default_value.
   * For  each instance of the object, the same property must be constructed with the same name.
   */
  Property(Glib::Object& object, const Glib::ustring& name, const PropertyType& default_value);

  /** Sets the value of the property to @a data.
   * The object containing the property will be notified about the change.
   */
  inline void set_value(const PropertyType& data);

  /** Returns the value of the property.
   */
  inline PropertyType get_value() const;

  /** Sets the value of the property to @a data.
   * The object containing the property will be notified about the change.
   */
  inline Property<T>& operator=(const PropertyType& data);

  /** Returns the value of the property.
   */
  inline operator PropertyType() const;

  /** Returns a proxy object that can be used to manipulate this property.
   */
  inline Glib::PropertyProxy<T> get_proxy();
};


#ifndef DOXYGEN_SHOULD_SKIP_THIS

/**** Glib::Property<T> ****************************************************/

template <class T>
Property<T>::Property(Glib::Object& object, const Glib::ustring& name)
:
  PropertyBase(object, ValueType::value_type())
{
  if(!lookup_property(name))
    install_property(static_cast<ValueType&>(value_).create_param_spec(name));
}

template <class T>
Property<T>::Property(Glib::Object& object, const Glib::ustring& name,
                      const typename Property<T>::PropertyType& default_value)
:
  PropertyBase(object, ValueType::value_type())
{
  static_cast<ValueType&>(value_).set(default_value);

  if(!lookup_property(name))
    install_property(static_cast<ValueType&>(value_).create_param_spec(name));
}

template <class T> inline
void Property<T>::set_value(const typename Property<T>::PropertyType& data)
{
  static_cast<ValueType&>(value_).set(data);
  this->notify();
}

template <class T> inline
typename Property<T>::PropertyType Property<T>::get_value() const
{
  return static_cast<const ValueType&>(value_).get();
}

template <class T> inline
Property<T>& Property<T>::operator=(const typename Property<T>::PropertyType& data)
{
  static_cast<ValueType&>(value_).set(data);
  this->notify();
  return *this;
}

template <class T> inline
Property<T>::operator T() const
{
  return static_cast<const ValueType&>(value_).get();
}

template <class T> inline
Glib::PropertyProxy<T> Property<T>::get_proxy()
{
  return Glib::PropertyProxy<T>(object_, get_name_internal());
}

#endif /* DOXYGEN_SHOULD_SKIP_THIS */

} // namespace Glib


#endif /* _GLIBMM_PROPERTY_H */