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
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
|
/*
kopeteproperties.h - Kopete Properties
Copyright (c) 2004 by Richard Smith <kde@metafoo.co.uk>
Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org>
*************************************************************************
* *
* 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 of the License, or (at your option) any later version. *
* *
*************************************************************************
*/
#ifndef KOPETEPROPERTIES_H
#define KOPETEPROPERTIES_H
#include <qasciidict.h>
#include <typeinfo>
class QString;
class QVariant;
class QDomElement;
namespace Kopete
{
/**
* Contains the classes forming Kopete's Properties system.
*
* @todo Explain more, give examples.
*
* @author Richard Smith <kde@metafoo.co.uk>
*/
namespace Properties
{
//BEGIN core functionality
/**
* @brief Property-type-independent base class for properties
*
* The base class for all properties of any type which can be set or got for @p Parent
* objects. It is rare to need to use this class directly. Usually you will want to use
* the @ref Property derived class, or dynamic_cast the PropertyBase object to another interface.
*
* @see Property UserVisible XMLSerializable StringSerializable
*
* @author Richard Smith <kde@metafoo.co.uk>
*/
template<class Parent>
class PropertyBase
{
public:
/**
* Returns the name of the property. This name should uniquely identify this property
* within the type Parent, and will be used for persistently identifying this property.
*
* For core properties, the chosen name should not contain any slash characters. For
* properties defined in plugins kept in Kopete's CVS, the name should be of the form
* pluginName/propertyName. For third-party plugins, please use a URL with a host which
* you own, such as "http://my-host.com/kopete/properties/groupId".
*
* @return the name of this property.
*/
virtual const char *name() const = 0;
};
/**
* @brief Property-type-dependent base class for properties
*
* This class represents a property of type @p Type applicable to @p Parent objects. Usage
* of this class is usually as simple as:
*
* \code
* SomeParent *propertyContainer = ...
* Property<SomeParent,QString> &myProperty = ...
* QString value = propertyContainer->property(myProperty);
* propertyContainer->setProperty(myProperty, "hello");
* \endcode
*
* You should never need to call functions in this class directly.
*/
template<class Parent, typename Type>
class Property : public PropertyBase<Parent>
{
public:
/**
* Returns the value of this property in the object @p parent.
*/
virtual Type get( const Parent *parent ) const = 0;
/**
* Sets the value of this property in the object @p parent.
*/
virtual void set( Parent *, const Type & ) const = 0;
};
/**
* @brief Base class for property data objects
*
* Some property objects want to store property-specific data in their parent objects.
* To support that, subclasses of this class are permitted to be stored. Once passed
* to the @ref PropertyStorage object via @ref PropertyStorage::setCustomPropertyData,
* the @ref PropertyStorage object owns the PropertyData, and will delete it when it
* is no longer needed.
*/
struct PropertyData
{
virtual ~PropertyData() {}
};
/**
* @brief Storage object for PropertyData objects
*
* This class is responsible for storing PropertyData-derived data objects for properties.
* This is the non-templated part of the @ref WithProperties class, split out into its own
* class to eliminate the template bloat.
*/
class PropertyStorage
{
typedef QAsciiDict<PropertyData> PropertyDict;
// setCustomPropertyData can be called on a const object, allowing the
// guarantee that DataProperty::data() never returns 0.
mutable PropertyDict _storage;
public:
PropertyStorage() { _storage.setAutoDelete( true ); }
/**
* Sets the stored property data with name @p name to be @p data.
*
* @note The @p name argument should usually be the name of the property which the data
* is being stored for. However, if properties wish to share data, they may choose to
* name their custom data differently. Names are bound by the same rules as are laid out
* for naming properties in PropertyBase<Parent>::name.
*/
void setCustomPropertyData( const char *name, PropertyData *data ) const { _storage.replace( name, data ); }
/**
* Gets the stored property data with name @p name. Returns a null
* pointer if no data has been stored for that property.
*/
PropertyData *getCustomPropertyData( const char *name ) const { return _storage[name]; }
};
/**
* @brief Base class for classes to which properties can be applied
*
* This class provides support for properties to another class. If you want your class
* to support properties, derive from this passing your class as the Parent parameter:
*
* \code
* class YourClass : public WithProperties<YourClass> { ... };
* \endcode
*
* You will also need to explicitly specialise the propertyCreated() member function to
* load property data upon creation of a new property object.
*/
template<class Parent>
class WithProperties : public PropertyStorage
{
public:
/**
* Get the value of property @p prop in this object.
* @param prop the Property object representing the property to get
*/
template<typename T>
T property( Property<Parent,T> const &prop ) { return prop.get( static_cast<Parent*>(this) ); }
/**
* Set the value of property @p prop in this object.
* @param prop the Property object representing the property to get
* @param value the value to set the property to
*/
template<typename T>
void setProperty( Property<Parent,T> const &prop, const T &value ) { prop.set( static_cast<Parent*>(this), value ); }
/**
* Called when a property is created; loads the Parent object's data into the property.
*
* @note Derived classes must explicitly specialize this to load the property's data into
* every object of this type.
*/
static void propertyCreated( const PropertyBase<Parent> &property );
};
//END core functionality
//BEGIN interfaces
/**
* @brief An interface for user-visible properties
* @todo document
*/
template<class Parent>
struct UserVisible
{
virtual QString userText( Parent * ) = 0;
virtual QString label() = 0;
virtual QString icon() = 0;
};
/**
* @brief An interface for properties which can be serialized as XML
* @todo document
*/
template<class Parent>
struct XMLSerializable
{
virtual void fromXML( Parent *, const QDomElement & ) = 0;
virtual void toXML( const Parent *, QDomElement & ) = 0;
};
/**
* @brief An interface for properties which can be serialized as strings
* @todo document
*/
template<class Parent>
struct StringSerializable
{
virtual void fromString( Parent *, const QString & ) = 0;
virtual QString toString( const Parent * ) = 0;
};
//END interfaces
//BEGIN convenience classes
/**
* @internal Display a warning message when the wrong type of property data is found
*/
void customPropertyDataIncorrectType( const char *name, const std::type_info &found, const std::type_info &expected );
/**
* @brief Convenience implementation of a Property that stores PropertyData
*
* A property for objects of type @p Parent, that stores data in the class @p Data.
* @p Data must be derived from @ref PropertyBase, or your code will not compile.
*/
template<class Parent, typename Type, class Data>
class DataProperty : public Property<Parent,Type>
{
public:
Data *data( const Parent *c ) const
{
PropertyData *pd = c->getCustomPropertyData( this->name() );
Data *data = dynamic_cast<Data*>(pd);
if ( !data )
{
if ( pd )
customPropertyDataIncorrectType( this->name(), typeid(*pd), typeid(Data) );
data = new Data;
c->setCustomPropertyData( this->name(), data );
}
return data;
}
};
/**
* @brief Convenience implementation of a PropertyData subclass which stores a single datum
*
* If a @ref Property needs to store only a single value in an object, using this
* class is simpler than deriving from @ref PropertyData yourself. The value will
* be default-constructed (which means for numeric types and pointers it will be
* set to 0).
*/
template<typename T>
struct SimplePropertyData : public PropertyData
{
SimplePropertyData() : value() {}
T value;
};
/**
* @brief Convenience implementation of a Property which stores a single datum as PropertyData
*
* This convenience class implements the @ref Property interface by simply storing and
* retrieving the datum from PropertyData. This class does not provide any serialization
* of the data.
*
* @note You will need to derive from this class to use it; the @ref name function is
* still pure virtual.
*/
template<class Parent, typename Type>
class SimpleDataProperty : public DataProperty<Parent,Type,SimplePropertyData<Type> >
{
public:
Type get( const Parent *p ) const { return data(p)->value; }
void set( Parent *p, const Type &v ) const { data(p)->value = v; }
};
/**
* Move somewhere else
* @{
*/
/**
* Explicitly specialised for all types QVariant supports
*/
template<class T> T variantTo(QVariant);
QVariant variantFromXML(const QDomElement&);
void variantToXML(QVariant v, QDomElement &);
/**
* @}
*/
/**
* @brief Convenience implementation of XMLSerializable in terms of QVariants
*
* This class provides XML serialization for data that can be stored in a QVariant. You
* will need to multiply-inherit from this class and (usually indirectly) from @ref Property.
*
* You can combine this class with other convenience classes such as SimpleDataProperty
* like this:
*
* \code
* class ContactNickNameProperty
* : public SimpleDataProperty<Contact,QString>
* , XMLProperty<ContactNickNameProperty,Contact,QString>
* {
* public:
* const char *name() const { return "nickName"; }
* };
* \endcode
*/
template<class Derived, class Parent, typename Type>
class XMLProperty : public XMLSerializable<Parent>
{
public:
void fromXML( Parent *t, const QDomElement &e )
{
static_cast<Derived*>(this)->set(t, variantTo<Type>(variantFromXML(e)));
}
void toXML( const Parent *t, QDomElement &e )
{
variantToXML(QVariant(static_cast<Derived*>(this)->get(t)),e);
}
};
//END convenience classes
} // namespace Properties
} // namespace Kopete
#endif
|