Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/netp6/src/core/XMLPort.h @ 4070

Last change on this file since 4070 was 3196, checked in by rgrieder, 16 years ago

Merged pch branch back to trunk.

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