/* kopeteproperties.h - Kopete Properties Copyright (c) 2004 by Richard Smith Kopete (c) 2002-2004 by the Kopete developers ************************************************************************* * * * 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 #include class TQString; class TQVariant; class TQDomElement; namespace Kopete { /** * Contains the classes forming Kopete's Properties system. * * @todo Explain more, give examples. * * @author Richard Smith */ 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 */ template 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 &myProperty = ... * TQString value = propertyContainer->property(myProperty); * propertyContainer->setProperty(myProperty, "hello"); * \endcode * * You should never need to call functions in this class directly. */ template class Property : public PropertyBase { 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 TQAsciiDict 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::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 { ... }; * \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 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 T property( Property const &prop ) { return prop.get( static_cast(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 void setProperty( Property const &prop, const T &value ) { prop.set( static_cast(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 &property ); }; //END core functionality //BEGIN interfaces /** * @brief An interface for user-visible properties * @todo document */ template struct UserVisible { virtual TQString userText( Parent * ) = 0; virtual TQString label() = 0; virtual TQString icon() = 0; }; /** * @brief An interface for properties which can be serialized as XML * @todo document */ template struct XMLSerializable { virtual void fromXML( Parent *, const TQDomElement & ) = 0; virtual void toXML( const Parent *, TQDomElement & ) = 0; }; /** * @brief An interface for properties which can be serialized as strings * @todo document */ template struct StringSerializable { virtual void fromString( Parent *, const TQString & ) = 0; virtual TQString 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 DataProperty : public Property { public: Data *data( const Parent *c ) const { PropertyData *pd = c->getCustomPropertyData( this->name() ); Data *data = dynamic_cast(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 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 SimpleDataProperty : public DataProperty > { 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 TQVariant supports */ template T variantTo(TQVariant); TQVariant variantFromXML(const TQDomElement&); void variantToXML(TQVariant v, TQDomElement &); /** * @} */ /** * @brief Convenience implementation of XMLSerializable in terms of TQVariants * * This class provides XML serialization for data that can be stored in a TQVariant. 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 * , XMLProperty * { * public: * const char *name() const { return "nickName"; } * }; * \endcode */ template class XMLProperty : public XMLSerializable { public: void fromXML( Parent *t, const TQDomElement &e ) { static_cast(this)->set(t, variantTo(variantFromXML(e))); } void toXML( const Parent *t, TQDomElement &e ) { variantToXML(TQVariant(static_cast(this)->get(t)),e); } }; //END convenience classes } // namespace Properties } // namespace Kopete #endif