Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

XML code has to be enclosed in @code and @endcode tags or Doxygen will complain

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