Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentation/src/core/XMLPort.h @ 2662

Last change on this file since 2662 was 2539, checked in by rgrieder, 16 years ago

XML Attribute are case insensitive now. However this does not applay to tags since they refer to actual classes, which are case sensitive.

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