Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentation/src/core/XMLPort.h @ 2471

Last change on this file since 2471 was 2459, checked in by rgrieder, 16 years ago

Merged physics_merge back to presentation branch.

  • Property svn:eol-style set to native
File size: 39.2 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30    @file
31    @brief Declaration of the XMLPort helper classes and macros.
32
33    XMLPort is a virtual function of every BaseObject. Every object can change this function.
34    The XMLPort function gets called with an XMLElement, containing all attributes and
35    subclasses the object gets from the levelfile.
36
37    This file declares classes and macros to simplify XML-parsing.
38*/
39
40#ifndef _XMLPort_H__
41#define _XMLPort_H__
42
43#include "CorePrereqs.h"
44
45#include "util/Debug.h"
46#include "util/Exception.h"
47#include "util/MultiType.h"
48#include "tinyxml/ticpp.h"
49#include "XMLIncludes.h"
50#include "Executor.h"
51#include "CoreIncludes.h"
52#include "BaseObject.h"
53
54// ------------
55// XMLPortParam
56
57/**
58    @brief Declares an XML attribute with a name, which will be set through load- and savefunctions.
59    @param classname The name of the class owning this param
60    @param paramname The name of the attribute
61    @param loadfunction A function to set the param in the object with a given value (~a set-function)
62    @param savefunction A function to get the value of the param from the object (~a get-function)
63    @param xmlelement The XMLElement, you get this from the XMLPort function
64    @param mode The mode (load or save), you get this from the XMLPort function
65
66    In the XML file, a param or attribute will be set like this:
67    <classname paramname="value" />
68
69    The macro will then call loadfunction(value) to set the given value (or call savefunction() to
70    write an existing value to an XML file).
71*/
72#define XMLPortParam(classname, paramname, loadfunction, savefunction, xmlelement, mode) \
73    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
74    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::savefunction), std::string( #classname ) + "::" + #savefunction); \
75    XMLPortParamGeneric(xmlcontainer##loadfunction##savefunction, classname, classname, this, paramname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode)
76
77/**
78    @brief Declares an XML attribute with a name, which will be set through a variable.
79    @param classname The name of the class owning this param
80    @param paramname The name of the attribute
81    @param variable Name of the variable used to save and load the value
82    @param xmlelement The XMLElement, you get this from the XMLPort function
83    @param mode The mode (load or save), you get this from the XMLPort function
84
85    In the XML file, a param or attribute will be set like this:
86    <classname paramname="value" />
87
88    The macro will then store "value" in the variable or read it when saving.
89*/
90#define XMLPortParamVariable(classname, paramname, variable, xmlelement, mode) \
91    static XMLPortVariableHelperClass xmlcontainer##variable##dummy((void*)&variable); \
92    static ExecutorMember<orxonox::XMLPortVariableHelperClass>* xmlcontainer##variable##loadexecutor = static_cast<ExecutorMember<orxonox::XMLPortVariableHelperClass>*>(orxonox::createExecutor(orxonox::createFunctor(orxonox::XMLPortVariableHelperClass::getLoader(variable)), std::string( #classname ) + "::" + #variable + "loader")); \
93    static ExecutorMember<orxonox::XMLPortVariableHelperClass>* xmlcontainer##variable##saveexecutor = static_cast<ExecutorMember<orxonox::XMLPortVariableHelperClass>*>(orxonox::createExecutor(orxonox::createFunctor(orxonox::XMLPortVariableHelperClass::getSaver (variable)), std::string( #classname ) + "::" + #variable + "saver" )); \
94    XMLPortParamGeneric(xmlcontainer##variable, classname, orxonox::XMLPortVariableHelperClass, &xmlcontainer##variable##dummy, paramname, xmlcontainer##variable##loadexecutor, xmlcontainer##variable##saveexecutor, xmlelement, mode)
95
96/**
97    @brief Declares an XML attribute with a name, which will be set through a variable and gotten from a function.
98    @param classname The name of the class owning this param
99    @param paramname The name of the attribute
100    @param variable Name of the variable used to save the value
101    @param savefunction A function to get the value of the param from the object (~a get-function)
102    @param xmlelement The XMLElement, you get this from the XMLPort function
103    @param mode The mode (load or save), you get this from the XMLPort function
104
105    In the XML file, a param or attribute will be set like this:
106    <classname paramname="value" />
107
108    The macro will then store "value" in the variable or read it when saving.
109*/
110#define XMLPortParamVariableOnLoad(classname, paramname, variable, savefunction, xmlelement, mode) \
111    static XMLPortVariableHelperClass xmlcontainer##variable##dummy((void*)&variable); \
112    static ExecutorMember<orxonox::XMLPortVariableHelperClass>* xmlcontainer##variable##loadexecutor = static_cast<ExecutorMember<orxonox::XMLPortVariableHelperClass>*>(&(orxonox::createExecutor(orxonox::createFunctor(orxonox::XMLPortVariableHelperClass::getLoader(variable)), std::string( #classname ) + "::" + #variable + "loader"))); \
113    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::savefunction), std::string( #classname ) + "::" + #savefunction); \
114    XMLPortParamGeneric(xmlcontainer##variable, classname, orxonox::XMLPortVariableHelperClass, &xmlcontainer##variable##dummy, paramname, xmlcontainer##variable##loadexecutor, xmlcontainer##variable##saveexecutor, xmlelement, mode)
115
116/**
117    @brief This is the same as XMLPortParam, but you can set the template arguments needed to store the loadfunction.
118
119    Sometimes the name of the loadfunction is ambiguous (example: setPosition(Vector3) or
120    setPosition(float, float, float)). In this case, you can choose the right function by
121    telling the types of the functionparams. In our example, this would be either
122    > XMLPortParamTemplate(classname, paramname, loadfunction, savefunction, xmlelement, mode, Vector3);
123    or
124    > XMLPortParamTemplate(classname, paramname, loadfunction, savefunction, xmlelement, mode, float, float, float);
125    You don't have to use this, if there exist only one function with the given name.
126*/
127#define XMLPortParamTemplate(classname, paramname, loadfunction, savefunction, xmlelement, mode, ...) \
128    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor<classname, __VA_ARGS__ >(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
129    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::savefunction), std::string( #classname ) + "::" + #savefunction); \
130    XMLPortParamGeneric(xmlcontainer##loadfunction##savefunction, classname, classname, this, paramname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode)
131
132// --------------------
133// XMLPortParamLoadOnly
134
135/**
136    @brief Declares an XML attribute with a name, which can be set through a loadfunction.
137
138    This is the same as XMLPortParam, but you don't need a savefunction (get-function). Therefore,
139    this param won't be saved in an XML file, but you can add the attribute manually an it will be
140    loaded.
141
142    This might be helpful in cases, when you have several options to set a value, for example the
143    rotation. You can set the rotation with a quaternion, but you could also use three angles.
144    When saving the object, only one of both options has to be saved; this is, where this macro helps.
145*/
146#define XMLPortParamLoadOnly(classname, paramname, loadfunction, xmlelement, mode) \
147    static ExecutorMember<classname>* xmlcontainer##loadfunction##0##loadexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
148    XMLPortParamGeneric(xmlcontainer##loadfunction##0, classname, classname, this, paramname, xmlcontainer##loadfunction##0##loadexecutor, 0, xmlelement, mode)
149/**
150    @brief This is the same as XMLPortParamTemplate, but for load-only attributes (see XMLPortParamLoadOnly).
151*/
152#define XMLPortParamLoadOnlyTemplate(classname, paramname, loadfunction, xmlelement, mode, ...) \
153    static ExecutorMember<classname>* xmlcontainer##loadfunction##0##loadexecutor = orxonox::createExecutor(orxonox::createFunctor<classname, __VA_ARGS__ >(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
154    XMLPortParamGeneric(xmlcontainer##loadfunction##0, classname, classname, this, paramname, xmlcontainer##loadfunction##0##loadexecutor, 0, xmlelement, mode)
155
156// ------------------
157// XMLPortParamExtern
158
159/**
160    @brief This is the same as XMLPortParam, but for attributes in an extern class.
161    @param classname The name of the class owning the object owning the attribute
162    @param externclass The name of the extern class (the objects class)
163    @param object The name of the object of the extern class (a member of the main class)
164    @param paramname The name of the attribute
165    @param loadfunction The function to set the attribute inside of the member object.
166    @param loadfunction The function to get the attribute from the member object
167
168    Sometimes you'll have a member object in your class, which has it's own load- and savefunctions.
169    With this macro, you can simply use them instead of writing your own functions.
170
171    @example
172    Your class is called SpaceShip and this class has an object (myPilot_) of class Pilot. Pilot has a name
173    and two functions, setName(name) and getName(). Now you want an attribute "pilotname" in your
174    SpaceShip class. Instead of writing wrapper functions, you can simply use the XMLPortParamExtern
175    macro:
176    > XMLPortParamExtern(SpaceShip, Pilot, myPilot_, "pilotname", setName, getName, xmlelement, mode);
177*/
178#define XMLPortParamExtern(classname, externclass, object, paramname, loadfunction, savefunction, xmlelement, mode) \
179    static ExecutorMember<externclass>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor(&externclass::loadfunction), std::string( #externclass ) + "::" + #loadfunction); \
180    static ExecutorMember<externclass>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&externclass::savefunction), std::string( #externclass ) + "::" + #savefunction); \
181    XMLPortParamGeneric(xmlcontainer##loadfunction##savefunction, classname, externclass, object, paramname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode);
182/**
183    @brief This is the same as XMLPortParamTemplate, but for extern attributes (see XMLPortParamExtern).
184*/
185#define XMLPortParamExternTemplate(classname, externclass, object, paramname, loadfunction, savefunction, xmlelement, mode, ...) \
186    static ExecutorMember<externclass>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor<externclass, __VA_ARGS__ >(&externclass::loadfunction), std::string( #externclass ) + "::" + #loadfunction); \
187    static ExecutorMember<externclass>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&externclass::savefunction), std::string( #externclass ) + "::" + #savefunction); \
188    XMLPortParamGeneric(xmlcontainer##loadfunction##savefunction, classname, externclass, object, paramname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode);
189
190// -------------------
191// XMLPortParamGeneric
192
193/**
194    @brief This is the generic XMLPort param macro, which is used by all six specialized macros above.
195*/
196#define XMLPortParamGeneric(containername, classname, objectclass, object, paramname, loadexecutor, saveexecutor, xmlelement, mode) \
197    orxonox::XMLPortClassParamContainer<objectclass>* containername = (orxonox::XMLPortClassParamContainer<objectclass>*)(ClassIdentifier<classname>::getIdentifier()->getXMLPortParamContainer(paramname)); \
198    if (!containername) \
199    { \
200        containername = new orxonox::XMLPortClassParamContainer<objectclass>(std::string(paramname), ClassIdentifier<classname>::getIdentifier(), loadexecutor, saveexecutor); \
201        ClassIdentifier<classname>::getIdentifier()->addXMLPortParamContainer(paramname, containername); \
202    } \
203    containername->port((BaseObject*)this, object, xmlelement, mode)
204
205// --------------------
206// XMLPortObjectExtended
207
208/**
209    @brief Declares a possible sub-object that can be added in the XML file.
210    @param classname The name of the class that uses this macro
211    @param objectclass The baseclass of objects that can be added
212    @param sectionname The name of the subsection in the XML file that encloses the sub-objects ("" means no subsection)
213    @param loadfunction The function to add a new object to the class
214    @param loadfunction The function to get all added objects from the class
215    @param xmlelement The XMLElement (recieved through the XMLPort function)
216    @param mode The mode (load/save) (received through the XMLPort function)
217    @param bApplyLoaderMask If this is true, an added sub-object gets loaded only if it's class is included in the Loaders ClassTreeMask (this is usually false)
218    @param bLoadBefore If this is true, the sub-object gets loaded (through XMLPort) BEFORE it gets added to the main class (this is usually true)
219
220    bApplyLoaderMask is usually false for the following reason:
221    If the loaders mask says, for example, "load only SpaceShips" and you added weapons to the
222    SpaceShips, then the Weapons will still be loaded (which is most probably what you want).
223    Of course, if there are "standalone" weapons in the level, they wont be loaded.
224
225    If bLoadBefore is true, an added object already has all attributes set (like it's name). This is most
226    likely the best option, so this is usually true.
227
228    @note
229    The load- and savefunctions have to follow an exactly defined protocol.
230    Loadfunction:
231      The loadfunction gets a pointer to the object.
232      > void loadfunction(objectclass* pointer);
233
234    Savefunction:
235      The savefunction gets an index, starting with 0. For every returnvalue != 0, the savefunction
236      gets called again, but with index + 1. It's the functions responsibility to do something smart
237      with the index and to return 0 if all objects were returned.
238      > objectclass* savefunction(unsigned int index) const;
239
240      Possible implementation:
241        objectclass* savefunction(unsigned int index) const
242        {
243          if (index < number_of_added_objects_)
244            return my_added_objects[index];
245          else
246            return 0;
247        }
248
249    @example
250    Possible usage of the macro:
251    > XMLPortObject(SpaceShip, Weapon, "weapons", addWeapon, getWeapon, xmlelement, mode, false, true);
252
253    Now you can add weapons through the XML file:
254    <SpaceShip someattribute="..." ...>
255      <weapons>
256        <Weapon someattribute="..." ... />
257        <Weapon someattribute="..." ... />
258        <Weapon someattribute="..." ... />
259      </weapons>
260    </SpaceShip>
261
262    Note that "weapons" is the subsection. This allows you to add more types of sub-objects. In our example,
263    you could add pilots, blinking lights or other stuff. If you don't want a subsection, just use "" (an
264    empty string). Then you can add sub-objects directly into the mainclass.
265*/
266#define XMLPortObjectExtended(classname, objectclass, sectionname, loadfunction, savefunction, xmlelement, mode, bApplyLoaderMask, bLoadBefore) \
267    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
268    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::savefunction), std::string( #classname ) + "::" + #savefunction); \
269    XMLPortObjectGeneric(xmlcontainer##loadfunction##savefunction, classname, objectclass, sectionname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode, bApplyLoaderMask, bLoadBefore)
270/**
271    @brief This is the same as XMLPortObjectExtended, but you can specify the loadfunction by adding the param types. See XMLPortParamTemplate for more details about the types.
272*/
273#define XMLPortObjectExtendedTemplate(classname, objectclass, sectionname, loadfunction, savefunction, xmlelement, mode, bApplyLoaderMask, bLoadBefore, ...) \
274    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor<classname, __VA_ARGS__ >(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
275    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::savefunction), std::string( #classname ) + "::" + #savefunction); \
276    XMLPortObjectGeneric(xmlcontainer##loadfunction##savefunction, classname, objectclass, sectionname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode, bApplyLoaderMask, bLoadBefore)
277
278// -------------
279// XMLPortObject
280
281/**
282    @brief This is the same as XMLPortObjectExtended, but bApplyLoaderMask is false and bLoadBefore is true by default.
283*/
284#define XMLPortObject(classname, objectclass, sectionname, loadfunction, savefunction, xmlelement, mode) \
285    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
286    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::savefunction), std::string( #classname ) + "::" + #savefunction); \
287    XMLPortObjectGeneric(xmlcontainer##loadfunction##savefunction, classname, objectclass, sectionname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode, false, true)
288/**
289    @brief This is the same as XMLPortObject, but you can specify the loadfunction by adding the param types. See XMLPortParamTemplate for more details about the types.
290*/
291#define XMLPortObjectTemplate(classname, objectclass, sectionname, loadfunction, savefunction, xmlelement, mode, ...) \
292    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##loadexecutor = orxonox::createExecutor(orxonox::createFunctor<classname, __VA_ARGS__ >(&classname::loadfunction), std::string( #classname ) + "::" + #loadfunction); \
293    static ExecutorMember<classname>* xmlcontainer##loadfunction##savefunction##saveexecutor = orxonox::createExecutor(orxonox::createFunctor(&classname::savefunction), std::string( #classname ) + "::" + #savefunction); \
294    XMLPortObjectGeneric(xmlcontainer##loadfunction##savefunction, classname, objectclass, sectionname, xmlcontainer##loadfunction##savefunction##loadexecutor, xmlcontainer##loadfunction##savefunction##saveexecutor, xmlelement, mode, false, true)
295
296// --------------------
297// XMLPortObjectGeneric
298
299/**
300    @brief Generic XMLPortObject macro, that gets called by all other XMLPortObject macros above.
301*/
302#define XMLPortObjectGeneric(containername, classname, objectclass, sectionname, loadexecutor, saveexecutor, xmlelement, mode, bApplyLoaderMask, bLoadBefore) \
303    orxonox::XMLPortClassObjectContainer<classname, objectclass>* containername = (orxonox::XMLPortClassObjectContainer<classname, objectclass>*)(ClassIdentifier<classname>::getIdentifier()->getXMLPortObjectContainer(sectionname)); \
304    if (!containername) \
305    { \
306        containername = new orxonox::XMLPortClassObjectContainer<classname, objectclass>(std::string(sectionname), ClassIdentifier<classname>::getIdentifier(), loadexecutor, saveexecutor, bApplyLoaderMask, bLoadBefore); \
307        ClassIdentifier<classname>::getIdentifier()->addXMLPortObjectContainer(sectionname, containername); \
308    } \
309    containername->port(this, xmlelement, mode)
310
311
312namespace orxonox
313{
314    // ###############################
315    // ###  XMLPortParamContainer  ###
316    // ###############################
317    class _CoreExport XMLPortParamContainer
318    {
319    public:
320        enum ParseResult
321        {
322            PR_not_started,
323            PR_finished,
324            PR_waiting_for_default_values
325        };
326
327        public:
328            XMLPortParamContainer()
329                { this->parseResult_ = PR_not_started; }
330            virtual ~XMLPortParamContainer() {}
331
332            inline const std::string& getName() const
333                { return this->paramname_; }
334
335            virtual XMLPortParamContainer& description(const std::string description) = 0;
336            virtual const std::string& getDescription() = 0;
337
338            virtual XMLPortParamContainer& defaultValue(unsigned int index, const MultiType& param) = 0;
339            virtual XMLPortParamContainer& defaultValues(const MultiType& param1) = 0;
340            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2) = 0;
341            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3) = 0;
342            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4) = 0;
343            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4, const MultiType& param5) = 0;
344
345        protected:
346            std::string paramname_;
347            ParseResult parseResult_;
348            Identifier* identifier_;
349            BaseObject* owner_;
350    };
351
352    template <class T>
353    class XMLPortClassParamContainer : public XMLPortParamContainer
354    {
355        struct ParseParams
356        {
357            T* object;
358            Element* xmlelement;
359            XMLPort::Mode mode;
360        };
361
362        public:
363            XMLPortClassParamContainer(const std::string paramname, Identifier* identifier, ExecutorMember<T>* loadexecutor, ExecutorMember<T>* saveexecutor)
364            {
365                this->paramname_ = paramname;
366                this->identifier_ = identifier;
367                this->loadexecutor_ = loadexecutor;
368                this->saveexecutor_ = saveexecutor;
369            }
370
371            XMLPortParamContainer& port(BaseObject* owner, T* object, Element& xmlelement, XMLPort::Mode mode)
372            {
373                this->owner_ = owner;
374                this->parseParams_.object = object;
375                this->parseParams_.xmlelement = &xmlelement;
376                this->parseParams_.mode = mode;
377
378                if (mode == XMLPort::LoadObject)
379                {
380                    try
381                    {
382                        std::string attribute = xmlelement.GetAttribute(this->paramname_);
383                        if ((attribute.size() > 0) || (this->loadexecutor_->allDefaultValuesSet()))
384                        {
385                            COUT(5) << this->owner_->getLoaderIndentation() << "Loading parameter " << this->paramname_ << " in " << this->identifier_->getName() << " (objectname " << this->owner_->getName() << ")." << std::endl << this->owner_->getLoaderIndentation();
386                            if (this->loadexecutor_->parse(object, attribute, ","))
387                                this->parseResult_ = PR_finished;
388                            else
389                                this->parseResult_ = PR_waiting_for_default_values;
390                        }
391                        else
392                            this->parseResult_ = PR_waiting_for_default_values;
393                    }
394                    catch (ticpp::Exception& ex)
395                    {
396                        COUT(1) << std::endl;
397                        COUT(1) << "An error occurred in XMLPort.h while loading attribute '" << this->paramname_ << "' of '" << this->identifier_->getName() << "' (objectname: " << this->owner_->getName() << ") in " << this->owner_->getFilename() << ":" << std::endl;
398                        COUT(1) << ex.what() << std::endl;
399                    }
400                }
401                else
402                {
403                    if (this->saveexecutor_)
404                    {
405//                        xmlelement.SetAttribute(this->paramname_, "...");
406                    }
407                }
408
409                return (*this);
410            }
411
412            XMLPortParamContainer& port(BaseObject* owner, const ParseParams& parseParams)
413            {
414                return this->port(owner, parseParams.object, *parseParams.xmlelement, parseParams.mode);
415            }
416
417            XMLPortParamContainer& portIfWaitingForDefaultValues(const ParseResult& result, const ParseParams& params)
418            {
419                if (result == PR_waiting_for_default_values)
420                    return this->port(this->owner_, params);
421                else
422                    return (*this);
423            }
424
425            virtual XMLPortParamContainer& description(const std::string description)
426                { this->loadexecutor_->setDescription(description); return (*this); }
427            virtual const std::string& getDescription()
428                { return this->loadexecutor_->getDescription(); }
429
430            virtual XMLPortParamContainer& defaultValue(unsigned int index, const MultiType& param)
431            {
432                if (!this->loadexecutor_->defaultValueSet(index))
433                    this->loadexecutor_->setDefaultValue(index, param);
434                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
435            }
436            virtual XMLPortParamContainer& defaultValues(const MultiType& param1)
437            {
438                if (!this->loadexecutor_->defaultValueSet(0))
439                    this->loadexecutor_->setDefaultValues(param1);
440                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
441            }
442            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2)
443            {
444                if ((!this->loadexecutor_->defaultValueSet(0)) || (!this->loadexecutor_->defaultValueSet(1)))
445                    this->loadexecutor_->setDefaultValues(param1, param2);
446                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
447            }
448            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3)
449            {
450                if ((!this->loadexecutor_->defaultValueSet(0)) || (!this->loadexecutor_->defaultValueSet(1)) || (!this->loadexecutor_->defaultValueSet(2)))
451                    this->loadexecutor_->setDefaultValues(param1, param2, param3);
452                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
453            }
454            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4)
455            {
456                if ((!this->loadexecutor_->defaultValueSet(0)) || (!this->loadexecutor_->defaultValueSet(1)) || (!this->loadexecutor_->defaultValueSet(2)) || (!this->loadexecutor_->defaultValueSet(3)))
457                    this->loadexecutor_->setDefaultValues(param1, param2, param3, param4);
458                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
459            }
460            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4, const MultiType& param5)
461            {
462                if ((!this->loadexecutor_->defaultValueSet(0)) || (!this->loadexecutor_->defaultValueSet(1)) || (!this->loadexecutor_->defaultValueSet(2)) || (!this->loadexecutor_->defaultValueSet(3)) || (!this->loadexecutor_->defaultValueSet(4)))
463                    this->loadexecutor_->setDefaultValues(param1, param2, param3, param4, param5);
464                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
465            }
466
467        private:
468            ExecutorMember<T>* loadexecutor_;
469            ExecutorMember<T>* saveexecutor_;
470            ParseParams parseParams_;
471    };
472
473
474    // ################################
475    // ###  XMLPortObjectContainer  ###
476    // ################################
477    class _CoreExport XMLPortObjectContainer
478    {
479        public:
480            XMLPortObjectContainer()
481                { this->bApplyLoaderMask_ = false; }
482            virtual ~XMLPortObjectContainer() {}
483
484            inline const std::string& getName() const
485                { return this->sectionname_; }
486
487            virtual XMLPortObjectContainer& description(const std::string description) = 0;
488            virtual const std::string& getDescription() = 0;
489
490            bool identifierIsIncludedInLoaderMask(const Identifier* identifier);
491
492        protected:
493            std::string sectionname_;
494            bool bApplyLoaderMask_;
495            bool bLoadBefore_;
496            Identifier* identifier_;
497    };
498
499    template <class T, class O>
500    class XMLPortClassObjectContainer : public XMLPortObjectContainer
501    {
502        public:
503            XMLPortClassObjectContainer(const std::string sectionname, Identifier* identifier, ExecutorMember<T>* loadexecutor, ExecutorMember<T>* saveexecutor, bool bApplyLoaderMask, bool bLoadBefore)
504            {
505                this->sectionname_ = sectionname;
506                this->identifier_ = identifier;
507                this->loadexecutor_ = loadexecutor;
508                this->saveexecutor_ = saveexecutor;
509                this->bApplyLoaderMask_ = bApplyLoaderMask;
510                this->bLoadBefore_ = bLoadBefore;
511            }
512
513            XMLPortObjectContainer& port(T* object, Element& xmlelement, XMLPort::Mode mode)
514            {
515                if (mode == XMLPort::LoadObject)
516                {
517                    try
518                    {
519                        Element* xmlsubelement;
520                        if ((this->sectionname_ != "") && (this->sectionname_.size() > 0))
521                            xmlsubelement = xmlelement.FirstChildElement(this->sectionname_, false);
522                        else
523                            xmlsubelement = &xmlelement;
524
525                        if (xmlsubelement)
526                        {
527                            for (ticpp::Iterator<ticpp::Element> child = xmlsubelement->FirstChildElement(false); child != child.end(); child++)
528                            {
529                                Identifier* identifier = ClassByString(child->Value());
530                                if (identifier)
531                                {
532                                    if (identifier->isA(Class(O)))
533                                    {
534                                        if (identifier->isLoadable())
535                                        {
536                                            if (this->identifierIsIncludedInLoaderMask(identifier))
537                                            {
538                                                try
539                                                {
540                                                    COUT(4) << ((BaseObject*)object)->getLoaderIndentation() << "fabricating " << child->Value() << "..." << std::endl;
541
542                                                    BaseObject* newObject = identifier->fabricate((BaseObject*)object);
543                                                    assert(newObject);
544                                                    newObject->setLoaderIndentation(((BaseObject*)object)->getLoaderIndentation() + "  ");
545
546                                                    O* castedObject = dynamic_cast<O*>(newObject);
547                                                    assert(castedObject);
548
549                                                    if (this->bLoadBefore_)
550                                                    {
551                                                        newObject->XMLPort(*child, XMLPort::LoadObject);
552                                                        COUT(4) << ((BaseObject*)object)->getLoaderIndentation() << "assigning " << child->Value() << " (objectname " << newObject->getName() << ") to " << this->identifier_->getName() << " (objectname " << ((BaseObject*)object)->getName() << ")" << std::endl;
553                                                    }
554                                                    else
555                                                    {
556                                                        COUT(4) << ((BaseObject*)object)->getLoaderIndentation() << "assigning " << child->Value() << " (object not yet loaded) to " << this->identifier_->getName() << " (objectname " << ((BaseObject*)object)->getName() << ")" << std::endl;
557                                                    }
558
559                                                    COUT(5) << ((BaseObject*)object)->getLoaderIndentation();
560                                                    (*this->loadexecutor_)(object, castedObject);
561
562                                                    if (!this->bLoadBefore_)
563                                                        newObject->XMLPort(*child, XMLPort::LoadObject);
564
565                                                    COUT(5) << ((BaseObject*)object)->getLoaderIndentation() << "...fabricated " << child->Value() << " (objectname " << newObject->getName() << ")." << std::endl;
566                                                }
567                                                catch (AbortLoadingException& ex)
568                                                {
569                                                    COUT(1) << "An error occurred while loading object, abort loading..." << std::endl;
570                                                    throw ex;
571                                                }
572                                                catch (std::exception& ex)
573                                                {
574                                                    COUT(1) << "An error occurred while loading object:" << std::endl;
575                                                    COUT(1) << ex.what() << std::endl;
576                                                }
577                                                catch (...)
578                                                {
579                                                    COUT(1) << "An unknown error occurred while loading object." << std::endl;
580                                                }
581                                            }
582                                        }
583                                        else
584                                        {
585                                            COUT(2) << ((BaseObject*)object)->getLoaderIndentation() << "Warning: '" << child->Value() << "' is not loadable." << std::endl;
586                                        }
587                                    }
588                                    else
589                                    {
590                                        COUT(2) << ((BaseObject*)object)->getLoaderIndentation() << "Warning: '" << child->Value() << "' is not a '" << Class(O)->getName() << "'." << std::endl;
591                                    }
592                                }
593                                else
594                                {
595                                    if (this->sectionname_ != "")
596                                    {
597                                        COUT(2) << object->getLoaderIndentation() << "Warning: '" << child->Value() << "' is not a valid classname." << std::endl;
598                                    }
599                                    else
600                                    {
601                                        // It's probably just another subsection
602                                    }
603                                }
604                            }
605                        }
606                    }
607                    catch (ticpp::Exception& ex)
608                    {
609                        COUT(1) << std::endl;
610                        COUT(1) << "An error occurred in XMLPort.h while loading a '" << Class(O)->getName() << "' in '" << this->sectionname_ << "' of '" << this->identifier_->getName() << "' (objectname: " << ((BaseObject*)object)->getName() << ") in " << object->getFilename() << ":" << std::endl;
611                        COUT(1) << ex.what() << std::endl;
612                    }
613                }
614                else
615                {
616                }
617
618                return (*this);
619            }
620
621            virtual XMLPortObjectContainer& description(const std::string description)
622                { this->loadexecutor_->setDescription(description); return (*this); }
623            virtual const std::string& getDescription()
624                { return this->loadexecutor_->getDescription(); }
625
626        private:
627            ExecutorMember<T>* loadexecutor_;
628            ExecutorMember<T>* saveexecutor_;
629    };
630
631
632    // ####################################
633    // ###  XMLPortVariableHelperClass  ###
634    // ####################################
635    /**
636    @brief
637        Helper class to load and save simple variables with XMLPort.
638
639        getLoader and getSaver were necessary to get the type T with
640        the help of template function type deduction (const T& is unused).
641        These functions return the adress of save<T> or load<T>.
642    */
643    class XMLPortVariableHelperClass
644    {
645        public:
646            XMLPortVariableHelperClass(void* var)
647                : variable_(var)
648                { }
649
650            template <class T>
651            void load(const T& value)
652                { *((T*)this->variable_) = value; }
653
654            template <class T>
655            const T& save()
656                { return *((T*)this->variable_); }
657
658            template <class T>
659            static void (XMLPortVariableHelperClass::*getLoader(const T& var))(const T& value)
660                { return &XMLPortVariableHelperClass::load<T>; }
661
662            template <class T>
663            static const T& (XMLPortVariableHelperClass::*getSaver(const T& var))()
664                { return &XMLPortVariableHelperClass::save<T>; }
665
666        private:
667            void* variable_;
668    };
669}
670
671#endif /* _XMLPort_H__ */
Note: See TracBrowser for help on using the repository browser.