Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/objecthierarchy/src/core/XMLPort.h @ 2219

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