diff options
Diffstat (limited to 'kopete/libkopete/kopeteproperties.h')
-rw-r--r-- | kopete/libkopete/kopeteproperties.h | 350 |
1 files changed, 350 insertions, 0 deletions
diff --git a/kopete/libkopete/kopeteproperties.h b/kopete/libkopete/kopeteproperties.h new file mode 100644 index 00000000..bfeaedea --- /dev/null +++ b/kopete/libkopete/kopeteproperties.h @@ -0,0 +1,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 |