#ifndef OFX_PROPERTY_SUITE_H #define OFX_PROPERTY_SUITE_H /* Software License : Copyright (c) 2007-2009, The Open Effects Association Ltd. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name The Open Effects Association Ltd, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #ifndef WINDOWS #define OFX_EXCEPTION_SPEC throw (OFX::Host::Property::Exception) #else #define OFX_EXCEPTION_SPEC #endif namespace OFX { namespace Host { namespace Property { /// simple function to turn a thing into a std string template inline std::string castToString(T i) { std::ostringstream o; o << i; return o.str(); } /// simple function to turn a string into an int inline int stringToInt(const std::string &s) { std::istringstream is(s); int number; is >> number; return number; } /// simple function to turn a string into a double inline double stringToDouble(const std::string &s) { std::istringstream is(s); double number; is >> number; return number; } // forward declarations class Property; class Set; /// exception, representing an OfxStatus class Exception { OfxStatus _stat; public: /// ctor Exception(OfxStatus stat) : _stat(stat) { } /// get the status OfxStatus getStatus() const { return _stat; } }; /// type of a property enum TypeEnum { eNone = -1, eInt = 0, eDouble = 1, eString = 2, ePointer = 3 }; /// type holder, for integers, used to template up int properties struct IntValue { typedef int APIType; ///< C type of the property that is passed across the raw API typedef int APITypeConstless; ///< C type of the property that is passed across the raw API, without any const it typedef int Type; ///< Type we actually hold and deal with the propery in everything by the raw API typedef int ReturnType; ///< type to return from a function call static const TypeEnum typeCode = eInt; static int kEmpty; }; /// type holder, for doubles, used to template up double properties struct DoubleValue { typedef double APIType; typedef double APITypeConstless; typedef double Type; typedef double ReturnType; ///< type to return from a function call static const TypeEnum typeCode = eDouble; static double kEmpty; }; /// type holder, for pointers, used to template up pointer properties struct PointerValue { typedef void *APIType; typedef void *APITypeConstless; typedef void *Type; typedef void *ReturnType; ///< type to return from a function call static const TypeEnum typeCode = ePointer; static void *kEmpty; }; /// type holder, for strings, used to template up string properties struct StringValue { typedef const char *APIType; typedef char *APITypeConstless; typedef std::string Type; typedef const std::string &ReturnType; ///< type to return from a function call static const TypeEnum typeCode = eString; static std::string kEmpty; }; /// array representing the names of the various types, in order of TypeEnum extern const char *gTypeNames[]; /// Sits on a property and can override the local property value when a value is being fetched /// only one of these can be in any property (as the thing has only a single value). class GetHook { public : /// dtor virtual ~GetHook() { } /// We specialise this to do some magic so that it calls get string/int/double/pointer appropriately /// this is what is called by the propertytemplate code to fetch values out of a hook. template typename T::ReturnType getProperty(const std::string &name, int index=0) const OFX_EXCEPTION_SPEC; /// We specialise this to do some magic so that it calls get int/double/pointer appropriately /// this is what is called by the propertytemplate code to fetch values out of a hook. template void getPropertyN(const std::string &name, typename T::APIType *values, int count) const OFX_EXCEPTION_SPEC; /// override this to fetch a single value at the given index. virtual const std::string& getStringProperty(const std::string &name, int index = 0) const OFX_EXCEPTION_SPEC; /// override this to fetch a multiple values in a multi-dimension property virtual void getStringPropertyN(const std::string &name, const char** values, int count) const OFX_EXCEPTION_SPEC; /// override this to fetch a single value at the given index. virtual int getIntProperty(const std::string &name, int index = 0) const OFX_EXCEPTION_SPEC; /// override this to fetch a multiple values in a multi-dimension property virtual void getIntPropertyN(const std::string &name, int *values, int count) const OFX_EXCEPTION_SPEC; /// override this to fetch a single value at the given index. virtual double getDoubleProperty(const std::string &name, int index = 0) const OFX_EXCEPTION_SPEC; /// override this to fetch a multiple values in a multi-dimension property virtual void getDoublePropertyN(const std::string &name, double *values, int count) const OFX_EXCEPTION_SPEC; /// override this to fetch a single value at the given index. virtual void *getPointerProperty(const std::string &name, int index = 0) const OFX_EXCEPTION_SPEC; /// override this to fetch a multiple values in a multi-dimension property virtual void getPointerPropertyN(const std::string &name, void **values, int count) const OFX_EXCEPTION_SPEC; /// override this to fetch the dimension size. virtual int getDimension(const std::string &name) const OFX_EXCEPTION_SPEC; /// override this to handle a reset(). virtual void reset(const std::string &name) OFX_EXCEPTION_SPEC; }; /// Sits on a property and is called when the local property is being set. /// It notify or notifyN is called whenever the plugin sets a property /// Many of these can sit on a property, as various objects will need to know when a property /// has been changed. On notification you should fetch properties with a 'raw' call, rather /// than the standard calls, as you may be fetching through a getHook and you won't see /// the local value that has been shoved into the property. class NotifyHook { public : /// dtor virtual ~NotifyHook() {} /// override this to be notified when a property changes /// \arg name is the name of the property just set /// \arg singleValue is whether setProperty on a single index was call, otherwise N properties were set /// \arg indexOrN is the index if single value is true, or the count if singleValue is false virtual void notify(const std::string &name, bool singleValue, int indexOrN) OFX_EXCEPTION_SPEC = 0; }; /// base class for all properties class Property { protected : std::string _name; ///< name of this property TypeEnum _type; ///< type of this property int _dimension; ///< the fixed dimension of this property bool _pluginReadOnly; ///< set is forbidden through suite: value may still change between get() calls std::vector _notifyHooks; ///< hooks to call whenever the property is set GetHook *_getHook; ///< if we are not storing props locally, they are stored via fetching from here friend class Set; public : /// ctor Property(const std::string &name, TypeEnum type, int dimension = 1, bool pluginReadOnly=false); /// copy ctor Property(const Property &other); /// dtor virtual ~Property() { } /// is it read only? bool getPluginReadOnly() const {return _pluginReadOnly; } /// change the state of readonlyness void setPluginReadOnly(bool v) {_pluginReadOnly = v;} /// override this to return a clone of the property virtual Property *deepCopy() = 0; /// get the name of this property const std::string &getName() { return _name; } /// get the type of this property TypeEnum getType() { return _type; } /// add a notify hook void addNotifyHook(NotifyHook *hook) { _notifyHooks.push_back(hook); } /// set the get hook void setGetHook(GetHook *hook) { _getHook = hook; } /// call notify on the contained notify hooks void notify(bool single, int indexOrN); // get the current dimension of this property virtual int getDimension() const = 0; /// get the fixed dimension of this property int getFixedDimension() const { return _dimension; } /// are we a fixed dim property bool isFixedSize() const { return _dimension != 0; } /// reset this property to the default virtual void reset() = 0; // get a string representing the value of this property at element nth virtual std::string getStringValue(int nth) = 0; }; /// this represents a generic property. /// template parameter T is the type descriptor of the /// type of property to model. the class holds an internal _value vector which can be used /// to store the values. if set and get hooks are installed, these will be called instead /// of using this variable. /// Make sure that T::ReturnType is const if appropriate, as no extra qualifiers are applied here. template class PropertyTemplate : public Property { public : typedef typename T::Type Type; typedef typename T::ReturnType ReturnType; typedef typename T::APIType APIType; protected : /// this is the present value of the property std::vector _value; /// this is the default value of the property std::vector _defaultValue; public : /// constructor PropertyTemplate(const std::string &name, int dimension, bool pluginReadOnly, APIType defaultValue); PropertyTemplate(const PropertyTemplate &pt); PropertyTemplate *deepCopy() { return new PropertyTemplate(*this); } virtual ~PropertyTemplate() { } /// get the vector const std::vector &getValues() { return _value; } // get multiple values void getValueN(APIType *value, int count) const OFX_EXCEPTION_SPEC; #ifdef WINDOWS #pragma warning( disable : 4181 ) #endif /// get one value const ReturnType getValue(int index=0) const OFX_EXCEPTION_SPEC; /// get one value, without going through the getHook const ReturnType getValueRaw(int index=0) const OFX_EXCEPTION_SPEC; #ifdef WINDOWS #pragma warning( default : 4181 ) #endif // get multiple values, without going through the getHook void getValueNRaw(APIType *value, int count) const OFX_EXCEPTION_SPEC; /// set one value void setValue(const Type &value, int index=0) OFX_EXCEPTION_SPEC; /// set multiple values void setValueN(const APIType *value, int count) OFX_EXCEPTION_SPEC; /// reset void reset() OFX_EXCEPTION_SPEC; /// get the size of the vector int getDimension() const OFX_EXCEPTION_SPEC; /// return the value as a string inline std::string getStringValue(int idx) { return castToString(_value[idx]); } }; typedef PropertyTemplate Int; /// Our int property typedef PropertyTemplate Double; /// Our double property typedef PropertyTemplate String; /// Our string property typedef PropertyTemplate Pointer; /// Our pointer property /// A class that is used to initialise a property set. Feed in an array of these to /// a property and it will construct a bunch of properties. Terminate such an array /// with an empty (all zero) set. struct PropSpec { const char *name; ///< name of the property TypeEnum type; ///< type int dimension; ///< fixed dimension of the property, set to zero if variable dimension bool readonly; ///< is the property plug-in read only const char *defaultValue; ///< Default value as a string. Pointers are ignored and always null. }; static const PropSpec propSpecEnd = {0, eNone, 0, false, 0}; /// A std::map of properties by name typedef std::map PropertyMap; //................................................................................ /// Class that holds a set of properties and manipulates them /// The 'fetch' methods return a property object. /// The 'get' methods return a property value class Set { private : static const int kMagic = 0x12082007; ///< magic number for property sets, and Connie's birthday :-) const int _magic; ///< to check for handles being nice protected : PropertyMap _props; ///< Our properties. /// chained property set, which is read only /// these are searched on a get if not found /// on a local search Set *_chainedSet; /// hide assignment void operator=(const Set &); /// set a particular property template void setProperty(const std::string &property, int index, const typename T::Type &value); /// set the first N of a particular property template void setPropertyN(const std::string &property, int count, const typename T::APIType *value); /// get a particular property template typename T::ReturnType getProperty(const std::string &property, int index) const; /// get the first N of a particular property template void getPropertyN(const std::string &property, int index, typename T::APIType *v) const; /// get a particular property without going through any getHook template typename T::ReturnType getPropertyRaw(const std::string &property, int index) const; /// get a particular property without going through any getHook template void getPropertyRawN(const std::string &property, int count, typename T::APIType *v) const; public : /// take an array of of PropSpecs (which must be terminated with an entry in which /// ->name is null), and turn these into a Set explicit Set(const PropSpec *); /// deep copies the property set explicit Set(const Set &); /// empty ctor explicit Set(); /// destructor virtual ~Set(); /// adds a bunch of properties from PropSpec void addProperties(const PropSpec *); /// add one new property void createProperty(const PropSpec &s); /// add one new property void addProperty(Property *prop); /// set the chained property set void setChainedSet(Set *s) {_chainedSet = s;} /// grab the internal properties map const PropertyMap &getProperties() const { return _props; } /// set the get hook for a particular property. users may need to call particular /// specialised versions of this. void setGetHook(const std::string &s, GetHook *ghook) const; /// add a set hook for a particular property. users may need to call particular /// specialised versions of this. void addNotifyHook(const std::string &name, NotifyHook *hook) const; /// Fetchs a pointer to a property of the given name, following the property chain if the /// 'followChain' arg is not false. Property *fetchProperty(const std::string &name, bool followChain = false) const; /// get property with the particular name and type. if the property is /// missing or is of the wrong type, return an error status. if this is a sloppy /// property set and the property is missing, a new one will be created of the right /// type template bool fetchTypedProperty(const std::string &name, T *&prop, bool followChain = false) const; /// retrieve the nameed string property String *fetchStringProperty(const std::string &name, bool followChain = false) const; /// retrieve the named double property Double *fetchDoubleProperty(const std::string &name, bool followChain = false) const; /// retrieve the named double property Pointer *fetchPointerProperty(const std::string &name, bool followChain = false) const; /// retrieve the named double property Int *fetchIntProperty(const std::string &name, bool followChain = false) const; /// get a particular int property without fetching via a get hook, useful for notifies int getIntPropertyRaw(const std::string &property, int index = 0) const; /// get a particular double property without fetching via a get hook, useful for notifies double getDoublePropertyRaw(const std::string &property, int index = 0) const; /// get a particular pointer property without fetching via a get hook, useful for notifies void *getPointerPropertyRaw(const std::string &property, int index = 0) const; /// get a particular string property const std::string &getStringPropertyRaw(const std::string &property, int index = 0) const; /// get the value of a particular string property const std::string &getStringProperty(const std::string &property, int index = 0) const; /// get the value of a particular int property int getIntProperty(const std::string &property, int index = 0) const; /// get the value of a particular double property void getIntPropertyN(const std::string &property, int *v, int N) const; /// get the value of a particular double property double getDoubleProperty(const std::string &property, int index = 0) const; /// get the value of a particular double property void getDoublePropertyN(const std::string &property, double *v, int N) const; /// get the value of a particular pointer property void *getPointerProperty(const std::string &property, int index = 0) const; /// set a particular string property without fetching via a get hook, useful for notifies void setStringProperty(const std::string &property, const std::string &value, int index = 0); /// get a particular int property void setIntProperty(const std::string &property, int v, int index = 0); /// get a particular double property void setIntPropertyN(const std::string &property, const int *v, int N); /// get a particular double property void setDoubleProperty(const std::string &property, double v, int index = 0); /// get a particular double property void setDoublePropertyN(const std::string &property, const double *v, int N); /// get a particular double property void setPointerProperty(const std::string &property, void *v, int index = 0); /// get the dimension of a particular property int getDimension(const std::string &property) const; /// is the given string one of the values of a multi-dimensional string prop /// this returns a non negative index if it is found, otherwise, -1 int findStringPropValueIndex(const std::string &propName, const std::string &propValue) const; /// get a handle on this object for passing to the C API OfxPropertySetHandle getHandle() const { return (OfxPropertySetHandle)this; } /// is this a nice property set, or a dodgy pointer passed back to us bool verifyMagic() { return _magic == kMagic; } }; /// return the OFX function suite that manages properties const void *GetSuite(int version); } } } #endif