Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 11085 was 11071, checked in by landauf, 9 years ago

merged branch cpp11_v3 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 nullptr;
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 class ParseResult
327        {
328            not_started,
329            finished,
330            waiting_for_default_values
331        };
332
333        public:
334            XMLPortParamContainer()
335                { this->parseResult_ = ParseResult::not_started; }
336            virtual ~XMLPortParamContainer() = default;
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            XMLPortParamContainer& port(BaseObject* owner, T* object, Element& xmlelement, XMLPort::Mode mode)
381            {
382                OrxAssert(owner, "XMLPortParamContainer must have a BaseObject as owner.");
383                this->owner_ = owner;
384                this->parseParams_.object = object;
385                this->parseParams_.xmlelement = &xmlelement;
386                this->parseParams_.mode = mode;
387
388                if ((mode == XMLPort::LoadObject) || (mode == XMLPort::ExpandObject))
389                {
390                    try
391                    {
392                        if (this->owner_->lastLoadedXMLElement_ != &xmlelement)
393                        {
394                            this->owner_->xmlAttributes_.clear();
395                            // Iterate through the attributes manually in order to make them case insensitive
396                            ticpp::Attribute* attribute = xmlelement.FirstAttribute(false);
397                            while (attribute != nullptr)
398                            {
399                                this->owner_->xmlAttributes_[getLowercase(attribute->Name())] = attribute->Value();
400                                attribute = attribute->Next(false);
401                            }
402                            this->owner_->lastLoadedXMLElement_ = &xmlelement;
403                        }
404                        std::map<std::string, std::string>::const_iterator it = this->owner_->xmlAttributes_.find(getLowercase(this->paramname_));
405                        std::string attributeValue;
406                        if (it != this->owner_->xmlAttributes_.end())
407                            attributeValue = it->second;
408
409                        // TODO: Checking the iterator would be better since then we can have strings with value "" as well.
410                        //       Unfortunately this does not seem to work with the Executor parser yet.
411                        if ((!attributeValue.empty()) || ((mode != XMLPort::ExpandObject) && this->loadexecutor_->allDefaultValuesSet()))
412                        {
413                            orxout(verbose_more, context::xml) << this->owner_->getLoaderIndentation() << "Loading parameter " << this->paramname_ << " in " << this->identifier_->getName() << " (objectname " << this->owner_->getName() << ")." << endl;
414                            int error;
415                            this->loadexecutor_->parse(object, attributeValue, &error, ",");
416                            if (!error || (mode  == XMLPort::ExpandObject))
417                                this->parseResult_ = ParseResult::finished;
418                            else
419                                this->parseResult_ = ParseResult::waiting_for_default_values;
420                        }
421                        else if (mode == XMLPort::ExpandObject)
422                            this->parseResult_ = ParseResult::finished;
423                        else
424                            this->parseResult_ = ParseResult::waiting_for_default_values;
425                    }
426                    catch (ticpp::Exception& ex)
427                    {
428                        orxout(internal_error, context::xml) << endl;
429                        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;
430                        orxout(internal_error, context::xml) << ex.what() << endl;
431                    }
432                }
433                else if (mode == XMLPort::SaveObject)
434                {
435                    if (this->saveexecutor_)
436                    {
437//                        xmlelement.SetAttribute(this->paramname_, "...");
438                    }
439                }
440
441                return (*this);
442            }
443
444            XMLPortParamContainer& port(BaseObject* owner, const ParseParams& parseParams)
445            {
446                return this->port(owner, parseParams.object, *parseParams.xmlelement, parseParams.mode);
447            }
448
449            XMLPortParamContainer& portIfWaitingForDefaultValues(const ParseResult& result, const ParseParams& params)
450            {
451                if (result == ParseResult::waiting_for_default_values)
452                    return this->port(this->owner_, params);
453                else
454                    return (*this);
455            }
456
457            virtual XMLPortParamContainer& defaultValue(unsigned int index, const MultiType& param) override
458            {
459                if (!this->loadexecutor_->defaultValueSet(index))
460                    this->loadexecutor_->setDefaultValue(index, param);
461                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
462            }
463            virtual XMLPortParamContainer& defaultValues(const MultiType& param1) override
464            {
465                if (!this->loadexecutor_->defaultValueSet(0))
466                    this->loadexecutor_->setDefaultValues(param1);
467                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
468            }
469            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2) override
470            {
471                if ((!this->loadexecutor_->defaultValueSet(0)) || (!this->loadexecutor_->defaultValueSet(1)))
472                    this->loadexecutor_->setDefaultValues(param1, param2);
473                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
474            }
475            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3) override
476            {
477                if ((!this->loadexecutor_->defaultValueSet(0)) || (!this->loadexecutor_->defaultValueSet(1)) || (!this->loadexecutor_->defaultValueSet(2)))
478                    this->loadexecutor_->setDefaultValues(param1, param2, param3);
479                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
480            }
481            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4) override
482            {
483                if ((!this->loadexecutor_->defaultValueSet(0)) || (!this->loadexecutor_->defaultValueSet(1)) || (!this->loadexecutor_->defaultValueSet(2)) || (!this->loadexecutor_->defaultValueSet(3)))
484                    this->loadexecutor_->setDefaultValues(param1, param2, param3, param4);
485                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
486            }
487            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4, const MultiType& param5) override
488            {
489                if ((!this->loadexecutor_->defaultValueSet(0)) || (!this->loadexecutor_->defaultValueSet(1)) || (!this->loadexecutor_->defaultValueSet(2)) || (!this->loadexecutor_->defaultValueSet(3)) || (!this->loadexecutor_->defaultValueSet(4)))
490                    this->loadexecutor_->setDefaultValues(param1, param2, param3, param4, param5);
491                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
492            }
493
494        private:
495            ExecutorMemberPtr<T> loadexecutor_;
496            ExecutorMemberPtr<T> saveexecutor_;
497            ParseParams parseParams_;
498    };
499
500
501    // ################################
502    // ###  XMLPortObjectContainer  ###
503    // ################################
504    class _CoreExport XMLPortObjectContainer
505    {
506        public:
507            XMLPortObjectContainer()
508                { this->bApplyLoaderMask_ = false; }
509            virtual ~XMLPortObjectContainer() = default;
510
511            XMLPortObjectContainer& port(BaseObject* object, Element& xmlelement, XMLPort::Mode mode);
512
513            virtual void callLoadExecutor(BaseObject* object, BaseObject* newObject) = 0;
514
515            inline const std::string& getName() const
516                { return this->sectionname_; }
517
518            inline XMLPortObjectContainer& description(const std::string& description)
519                { this->description_ = description; return *this; }
520            const std::string& getDescription() const
521                { return this->description_; }
522
523            bool identifierIsIncludedInLoaderMask(const Identifier* identifier);
524
525        protected:
526            std::string sectionname_;
527            bool bApplyLoaderMask_;
528            bool bLoadBefore_;
529            Identifier* identifier_;
530            Identifier* objectIdentifier_;
531            std::string description_;
532    };
533
534    template <class T, class O>
535    class XMLPortClassObjectContainer : public XMLPortObjectContainer
536    {
537        public:
538            XMLPortClassObjectContainer(const std::string& sectionname, Identifier* identifier, const ExecutorMemberPtr<T>& loadexecutor, const ExecutorMemberPtr<T>& saveexecutor, bool bApplyLoaderMask, bool bLoadBefore)
539            {
540                this->sectionname_ = sectionname;
541                this->identifier_ = identifier;
542                assert(identifier->isA(ClassIdentifier<T>::getIdentifier()));
543                this->objectIdentifier_ = ClassIdentifier<O>::getIdentifier();
544                this->loadexecutor_ = loadexecutor;
545                this->saveexecutor_ = saveexecutor;
546                this->bApplyLoaderMask_ = bApplyLoaderMask;
547                this->bLoadBefore_ = bLoadBefore;
548            }
549
550            virtual void callLoadExecutor(BaseObject* object, BaseObject* newObject) override
551            {
552                T* castObject = orxonox_cast<T*>(object);
553                assert(castObject);
554                O* castNewObject = orxonox_cast<O*>(newObject);
555                assert(castNewObject);
556
557                (*this->loadexecutor_)(castObject, castNewObject);
558            }
559
560        private:
561            ExecutorMemberPtr<T> loadexecutor_;
562            ExecutorMemberPtr<T> saveexecutor_;
563    };
564
565
566    // ####################################
567    // ###  XMLPortVariableHelperClass  ###
568    // ####################################
569    /**
570    @brief
571        Helper class to load and save simple variables with XMLPort.
572
573        getLoader and getSaver were necessary to get the type T with
574        the help of template function type deduction (const T& is unused).
575        These functions return the adress of save<T> or load<T>.
576    */
577    class XMLPortVariableHelperClass
578    {
579        public:
580            XMLPortVariableHelperClass(void* var)
581                : variable_(var)
582                { }
583            virtual ~XMLPortVariableHelperClass() {}
584
585            template <class T>
586            void load(const T& value)
587                { *static_cast<T*>(this->variable_) = value; }
588
589            template <class T>
590            const T& save()
591                { return *static_cast<T*>(this->variable_); }
592
593            template <class T>
594            static void (XMLPortVariableHelperClass::*getLoader(const T& var))(const T& value)
595                { return &XMLPortVariableHelperClass::load<T>; }
596
597            template <class T>
598            static const T& (XMLPortVariableHelperClass::*getSaver(const T& var))()
599                { return &XMLPortVariableHelperClass::save<T>; }
600
601        private:
602            void* variable_;
603    };
604}
605
606#endif /* _XMLPort_H__ */
Note: See TracBrowser for help on using the repository browser.