You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdenetwork/kopete/libkopete/kopeteproperties.h

351 lines
10 KiB

/*
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 <tqasciidict.h>
#include <typeinfo>
class TQString;
class TQVariant;
class TQDomElement;
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,TQString> &myProperty = ...
* TQString 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 TQAsciiDict<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 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<class Parent>
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<class Parent>
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 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 TQVariant supports
*/
template<class T> 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<Contact,TQString>
* , XMLProperty<ContactNickNameProperty,Contact,TQString>
* {
* 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 TQDomElement &e )
{
static_cast<Derived*>(this)->set(t, variantTo<Type>(variantFromXML(e)));
}
void toXML( const Parent *t, TQDomElement &e )
{
variantToXML(TQVariant(static_cast<Derived*>(this)->get(t)),e);
}
};
//END convenience classes
} // namespace Properties
} // namespace Kopete
#endif