Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/physics/src/core/XMLPort.h @ 2298

Last change on this file since 2298 was 2291, checked in by rgrieder, 16 years ago

Added new XMLPort macro: XMLPortParamVariable
It allows to directly load values into a variable or from one. However it is not yet save to use. For instance declaring a Vector3 parameter as "1,2,3" is a very bad idea. "(1,2,3)" works well.

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