Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/doc/src/libraries/core/XMLPort.h @ 7297

Last change on this file since 7297 was 7297, checked in by landauf, 14 years ago

fixed lots of Doxygen warnings

Note: Doxygen prints a warning if only a part of the parameters of a function are documented.

Added documentation for missing parameters (as good as I could), removed documentation of obsolete parameters and fixed names of renamed parameters.
Some parameters are tagged with "FIXME", please replace this with an appropriate documentation if you know what it does.

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