Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentation2/src/libraries/core/XMLPort.h @ 6170

Last change on this file since 6170 was 6117, checked in by rgrieder, 15 years ago

Merged sound3 branch to presentation2.

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