1 #ifndef SH_PROPERTYBASE_H
2 #define SH_PROPERTYBASE_H
3 
4 #include <string>
5 #include <map>
6 
7 #include <boost/shared_ptr.hpp>
8 
9 namespace sh
10 {
11 	class StringValue;
12 	class PropertySetGet;
13 	class LinkedValue;
14 
15 	enum ValueType
16 	{
17 		VT_String,
18 		VT_Int,
19 		VT_Float,
20 		VT_Vector2,
21 		VT_Vector3,
22 		VT_Vector4
23 	};
24 
25 	class PropertyValue
26 	{
27 	public:
PropertyValue()28 		PropertyValue() {}
29 
~PropertyValue()30 		virtual ~PropertyValue() {}
31 
_getStringValue()32 		std::string _getStringValue() { return mStringValue; }
33 
34 		virtual std::string serialize() = 0;
35 
36 	protected:
37 		std::string mStringValue; ///< this will possibly not contain anything in the specialised classes
38 	};
39 	typedef boost::shared_ptr<PropertyValue> PropertyValuePtr;
40 
41 	class StringValue : public PropertyValue
42 	{
43 	public:
44 		StringValue (const std::string& in);
get() const45 		std::string get() const { return mStringValue; }
46 
47 		virtual std::string serialize();
48 	};
49 
50 	/**
51 	 * @brief Used for retrieving a named property from a context
52 	 */
53 	class LinkedValue : public PropertyValue
54 	{
55 	public:
56 		LinkedValue (const std::string& in);
57 
58 		std::string get(PropertySetGet* context) const;
59 
60 		virtual std::string serialize();
61 	};
62 
63 	class FloatValue : public PropertyValue
64 	{
65 	public:
66 		FloatValue (float in);
67 		FloatValue (const std::string& in);
get() const68 		float get() const { return mValue; }
69 
70 		virtual std::string serialize();
71 	private:
72 		float mValue;
73 	};
74 
75 	class IntValue : public PropertyValue
76 	{
77 	public:
78 		IntValue (int in);
79 		IntValue (const std::string& in);
get() const80 		int get() const { return mValue; }
81 
82 		virtual std::string serialize();
83 	private:
84 		int mValue;
85 	};
86 
87 	class BooleanValue : public PropertyValue
88 	{
89 	public:
90 		BooleanValue (bool in);
91 		BooleanValue (const std::string& in);
get() const92 		bool get() const { return mValue; }
93 
94 		virtual std::string serialize();
95 	private:
96 		bool mValue;
97 	};
98 
99 	class Vector2 : public PropertyValue
100 	{
101 	public:
102 		Vector2 (float x, float y);
103 		Vector2 (const std::string& in);
104 
105 		float mX, mY;
106 
107 		virtual std::string serialize();
108 	};
109 
110 	class Vector3 : public PropertyValue
111 	{
112 	public:
113 		Vector3 (float x, float y, float z);
114 		Vector3 (const std::string& in);
115 
116 		float mX, mY, mZ;
117 
118 		virtual std::string serialize();
119 	};
120 
121 	class Vector4 : public PropertyValue
122 	{
123 	public:
124 		Vector4 (float x, float y, float z, float w);
125 		Vector4 (const std::string& in);
126 
127 		float mX, mY, mZ, mW;
128 
129 		virtual std::string serialize();
130 	};
131 
132 	/// \brief base class that allows setting properties with any kind of value-type
133 	class PropertySet
134 	{
135 	public:
~PropertySet()136         virtual ~PropertySet() {}
137 		void setProperty (const std::string& name, PropertyValuePtr& value, PropertySetGet* context);
138 
139 	protected:
140 		virtual bool setPropertyOverride (const std::string& name, PropertyValuePtr& value, PropertySetGet* context);
141 		///< @return \a true if the specified property was found, or false otherwise
142 	};
143 
144 	typedef std::map<std::string, PropertyValuePtr> PropertyMap;
145 
146 	/// \brief base class that allows setting properties with any kind of value-type and retrieving them
147 	class PropertySetGet
148 	{
149 	public:
150 		PropertySetGet (PropertySetGet* parent);
151 		PropertySetGet ();
152 
~PropertySetGet()153 		virtual ~PropertySetGet() {}
154 
155 		void save (std::ofstream& stream, const std::string& indentation);
156 
157 		void copyAll (PropertySet* target, PropertySetGet* context, bool copyParent=true);
158 		///< call setProperty for each property/value pair stored in \a this
159 		void copyAll (PropertySetGet* target, PropertySetGet* context, bool copyParent=true);
160 		///< call setProperty for each property/value pair stored in \a this
161 
162 		void setParent (PropertySetGet* parent);
getParent()163 		PropertySetGet* getParent () { return mParent; }
164 		void setContext (PropertySetGet* context);
165 		PropertySetGet* getContext();
166 
167 		virtual void setProperty (const std::string& name, PropertyValuePtr value);
168 		PropertyValuePtr& getProperty (const std::string& name);
169 
170 		void deleteProperty (const std::string& name);
171 
listProperties()172 		const PropertyMap& listProperties() { return mProperties; }
173 
174 		bool hasProperty (const std::string& name) const;
175 
176 	private:
177 		PropertyMap mProperties;
178 
179 	protected:
180 		PropertySetGet* mParent;
181 		///< the parent can provide properties as well (when they are retrieved via getProperty) \n
182 		/// multiple levels of inheritance are also supported \n
183 		/// children can override properties of their parents
184 
185 		PropertySetGet* mContext;
186 		///< used to retrieve linked property values
187 	};
188 
189 	template <typename T>
retrieveValue(boost::shared_ptr<PropertyValue> & value,PropertySetGet * context)190 	static T retrieveValue (boost::shared_ptr<PropertyValue>& value, PropertySetGet* context)
191 	{
192 		if (typeid(*value).name() == typeid(LinkedValue).name())
193 		{
194 			std::string v = static_cast<LinkedValue*>(value.get())->get(context);
195 			PropertyValuePtr newVal = PropertyValuePtr (new StringValue(v));
196 			return retrieveValue<T>(newVal, NULL);
197 		}
198 		if (typeid(T).name() == typeid(*value).name())
199 		{
200 			// requested type is the same as source type, only have to cast it
201 			return *static_cast<T*>(value.get());
202 		}
203 
204 		if ((typeid(T).name() == typeid(StringValue).name())
205 			&& typeid(*value).name() != typeid(StringValue).name())
206 		{
207 			// if string type is requested and value is not string, use serialize method to convert to string
208 			T* ptr = new T (value->serialize()); // note that T is always StringValue here, but we can't use it here
209 			value = boost::shared_ptr<PropertyValue> (static_cast<PropertyValue*>(ptr));
210 			return *ptr;
211 		}
212 
213 		{
214 			// remaining case: deserialization from string by passing the string to constructor of class T
215 			T* ptr = new T(value->_getStringValue());
216 			PropertyValuePtr newVal (static_cast<PropertyValue*>(ptr));
217 			value = newVal;
218 			return *ptr;
219 		}
220 	}
221 	///<
222 	/// @brief alternate version that supports linked values (use of $variables in parent material)
223 	/// @note \a value is changed in-place to the converted object
224 	/// @return converted object \n
225 
226 	/// Create a property from a string
makeProperty(const std::string & prop)227 	inline PropertyValuePtr makeProperty (const std::string& prop)
228 	{
229 		if (prop.size() > 1 && prop[0] == '$')
230 			return PropertyValuePtr (static_cast<PropertyValue*>(new LinkedValue(prop)));
231 		else
232 			return PropertyValuePtr (static_cast<PropertyValue*> (new StringValue(prop)));
233 	}
234 
235 	template <typename T>
236 	/// Create a property of any type
237 	/// Example: sh::makeProperty (new sh::Vector4(1, 1, 1, 1))
makeProperty(T * p)238 	inline PropertyValuePtr makeProperty (T* p)
239 	{
240 		return PropertyValuePtr ( static_cast<PropertyValue*>(p) );
241 	}
242 }
243 
244 #endif
245