Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/core/XMLPort.h @ 10031

Last change on this file since 10031 was 9667, checked in by landauf, 11 years ago

merged core6 back to trunk

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