Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/objecthierarchy2/src/core/XMLPort.h @ 2274

Last change on this file since 2274 was 2173, checked in by landauf, 16 years ago
  • Added new XMLPort mode, ExpandObject, which works like LoadObject but doesn't use default values if there are missing parameters. This is used if an object is expanded by templates (like adding CameraPositions).
  • Changed default level to sample3.oxw in objecthierarchy2 branch
  • Small fix with doubly added clients in Level- and PlayerManager
  • Property svn:eol-style set to native
File size: 34.9 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) || (mode == XMLPort::ExpandObject))
339                {
340                    try
341                    {
342                        std::string attribute = xmlelement.GetAttribute(this->paramname_);
343                        if ((attribute.size() > 0) || ((mode != XMLPort::ExpandObject) && 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, ",") || (mode  == XMLPort::ExpandObject))
347                                this->parseResult_ = PR_finished;
348                            else
349                                this->parseResult_ = PR_waiting_for_default_values;
350                        }
351                        else if (mode == XMLPort::ExpandObject)
352                            this->parseResult_ = PR_finished;
353                        else
354                            this->parseResult_ = PR_waiting_for_default_values;
355                    }
356                    catch (ticpp::Exception& ex)
357                    {
358                        COUT(1) << std::endl;
359                        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;
360                        COUT(1) << ex.what() << std::endl;
361                    }
362                }
363                else
364                {
365                    if (this->saveexecutor_)
366                    {
367//                        xmlelement.SetAttribute(this->paramname_, "...");
368                    }
369                }
370
371                return (*this);
372            }
373
374            XMLPortParamContainer& port(BaseObject* owner, const ParseParams& parseParams)
375            {
376                return this->port(owner, parseParams.object, *parseParams.xmlelement, parseParams.mode);
377            }
378
379            XMLPortParamContainer& portIfWaitingForDefaultValues(const ParseResult& result, const ParseParams& params)
380            {
381                if (result == PR_waiting_for_default_values)
382                    return this->port(this->owner_, params);
383                else
384                    return (*this);
385            }
386
387            virtual XMLPortParamContainer& description(const std::string description)
388                { this->loadexecutor_->setDescription(description); return (*this); }
389            virtual const std::string& getDescription()
390                { return this->loadexecutor_->getDescription(); }
391
392            virtual XMLPortParamContainer& defaultValue(unsigned int index, const MultiType& param)
393            {
394                if (!this->loadexecutor_->defaultValueSet(index))
395                    this->loadexecutor_->setDefaultValue(index, param);
396                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
397            }
398            virtual XMLPortParamContainer& defaultValues(const MultiType& param1)
399            {
400                if (!this->loadexecutor_->defaultValueSet(0))
401                    this->loadexecutor_->setDefaultValues(param1);
402                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
403            }
404            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2)
405            {
406                if ((!this->loadexecutor_->defaultValueSet(0)) || (!this->loadexecutor_->defaultValueSet(1)))
407                    this->loadexecutor_->setDefaultValues(param1, param2);
408                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
409            }
410            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3)
411            {
412                if ((!this->loadexecutor_->defaultValueSet(0)) || (!this->loadexecutor_->defaultValueSet(1)) || (!this->loadexecutor_->defaultValueSet(2)))
413                    this->loadexecutor_->setDefaultValues(param1, param2, param3);
414                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
415            }
416            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4)
417            {
418                if ((!this->loadexecutor_->defaultValueSet(0)) || (!this->loadexecutor_->defaultValueSet(1)) || (!this->loadexecutor_->defaultValueSet(2)) || (!this->loadexecutor_->defaultValueSet(3)))
419                    this->loadexecutor_->setDefaultValues(param1, param2, param3, param4);
420                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
421            }
422            virtual XMLPortParamContainer& defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4, const MultiType& param5)
423            {
424                if ((!this->loadexecutor_->defaultValueSet(0)) || (!this->loadexecutor_->defaultValueSet(1)) || (!this->loadexecutor_->defaultValueSet(2)) || (!this->loadexecutor_->defaultValueSet(3)) || (!this->loadexecutor_->defaultValueSet(4)))
425                    this->loadexecutor_->setDefaultValues(param1, param2, param3, param4, param5);
426                return this->portIfWaitingForDefaultValues(this->parseResult_, this->parseParams_);
427            }
428
429        private:
430            ExecutorMember<T>* loadexecutor_;
431            ExecutorMember<T>* saveexecutor_;
432            ParseParams parseParams_;
433    };
434
435
436    // ################################
437    // ###  XMLPortObjectContainer  ###
438    // ################################
439    class _CoreExport XMLPortObjectContainer
440    {
441        public:
442            XMLPortObjectContainer()
443                { this->bApplyLoaderMask_ = false; }
444            virtual ~XMLPortObjectContainer() {}
445
446            inline const std::string& getName() const
447                { return this->sectionname_; }
448
449            virtual XMLPortObjectContainer& description(const std::string description) = 0;
450            virtual const std::string& getDescription() = 0;
451
452            bool identifierIsIncludedInLoaderMask(const Identifier* identifier);
453
454        protected:
455            std::string sectionname_;
456            bool bApplyLoaderMask_;
457            bool bLoadBefore_;
458            Identifier* identifier_;
459    };
460
461    template <class T, class O>
462    class XMLPortClassObjectContainer : public XMLPortObjectContainer
463    {
464        public:
465            XMLPortClassObjectContainer(const std::string sectionname, Identifier* identifier, ExecutorMember<T>* loadexecutor, ExecutorMember<T>* saveexecutor, bool bApplyLoaderMask, bool bLoadBefore)
466            {
467                this->sectionname_ = sectionname;
468                this->identifier_ = identifier;
469                this->loadexecutor_ = loadexecutor;
470                this->saveexecutor_ = saveexecutor;
471                this->bApplyLoaderMask_ = bApplyLoaderMask;
472                this->bLoadBefore_ = bLoadBefore;
473            }
474
475            XMLPortObjectContainer& port(T* object, Element& xmlelement, XMLPort::Mode mode)
476            {
477                if ((mode == XMLPort::LoadObject) || (mode == XMLPort::ExpandObject))
478                {
479                    try
480                    {
481                        Element* xmlsubelement;
482                        if ((this->sectionname_ != "") && (this->sectionname_.size() > 0))
483                            xmlsubelement = xmlelement.FirstChildElement(this->sectionname_, false);
484                        else
485                            xmlsubelement = &xmlelement;
486
487                        if (xmlsubelement)
488                        {
489                            for (ticpp::Iterator<ticpp::Element> child = xmlsubelement->FirstChildElement(false); child != child.end(); child++)
490                            {
491                                Identifier* identifier = ClassByString(child->Value());
492                                if (identifier)
493                                {
494                                    if (identifier->isA(Class(O)))
495                                    {
496                                        if (identifier->isLoadable())
497                                        {
498                                            if (this->identifierIsIncludedInLoaderMask(identifier))
499                                            {
500                                                try
501                                                {
502                                                    COUT(4) << ((BaseObject*)object)->getLoaderIndentation() << "fabricating " << child->Value() << "..." << std::endl;
503
504                                                    BaseObject* newObject = identifier->fabricate((BaseObject*)object);
505                                                    assert(newObject);
506                                                    newObject->setLoaderIndentation(((BaseObject*)object)->getLoaderIndentation() + "  ");
507
508                                                    O* castedObject = dynamic_cast<O*>(newObject);
509                                                    assert(castedObject);
510
511                                                    if (this->bLoadBefore_)
512                                                    {
513                                                        newObject->XMLPort(*child, XMLPort::LoadObject);
514                                                        COUT(4) << ((BaseObject*)object)->getLoaderIndentation() << "assigning " << child->Value() << " (objectname " << newObject->getName() << ") to " << this->identifier_->getName() << " (objectname " << ((BaseObject*)object)->getName() << ")" << std::endl;
515                                                    }
516                                                    else
517                                                    {
518                                                        COUT(4) << ((BaseObject*)object)->getLoaderIndentation() << "assigning " << child->Value() << " (object not yet loaded) to " << this->identifier_->getName() << " (objectname " << ((BaseObject*)object)->getName() << ")" << std::endl;
519                                                    }
520
521                                                    COUT(5) << ((BaseObject*)object)->getLoaderIndentation();
522                                                    (*this->loadexecutor_)(object, castedObject);
523
524                                                    if (!this->bLoadBefore_)
525                                                        newObject->XMLPort(*child, XMLPort::LoadObject);
526
527                                                    COUT(5) << ((BaseObject*)object)->getLoaderIndentation() << "...fabricated " << child->Value() << " (objectname " << newObject->getName() << ")." << std::endl;
528                                                }
529                                                catch (AbortLoadingException& ex)
530                                                {
531                                                    COUT(1) << "An error occurred while loading object, abort loading..." << std::endl;
532                                                    throw ex;
533                                                }
534                                                catch (std::exception& ex)
535                                                {
536                                                    COUT(1) << "An error occurred while loading object:" << std::endl;
537                                                    COUT(1) << ex.what() << std::endl;
538                                                }
539                                                catch (...)
540                                                {
541                                                    COUT(1) << "An unknown error occurred while loading object." << std::endl;
542                                                }
543                                            }
544                                        }
545                                        else
546                                        {
547                                            COUT(2) << ((BaseObject*)object)->getLoaderIndentation() << "Warning: '" << child->Value() << "' is not loadable." << std::endl;
548                                        }
549                                    }
550                                    else
551                                    {
552                                        COUT(2) << ((BaseObject*)object)->getLoaderIndentation() << "Warning: '" << child->Value() << "' is not a '" << Class(O)->getName() << "'." << std::endl;
553                                    }
554                                }
555                                else
556                                {
557                                    if (this->sectionname_ != "")
558                                    {
559                                        COUT(2) << object->getLoaderIndentation() << "Warning: '" << child->Value() << "' is not a valid classname." << std::endl;
560                                    }
561                                    else
562                                    {
563                                        // It's probably just another subsection
564                                    }
565                                }
566                            }
567                        }
568                    }
569                    catch (ticpp::Exception& ex)
570                    {
571                        COUT(1) << std::endl;
572                        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;
573                        COUT(1) << ex.what() << std::endl;
574                    }
575                }
576                else
577                {
578                }
579
580                return (*this);
581            }
582
583            virtual XMLPortObjectContainer& description(const std::string description)
584                { this->loadexecutor_->setDescription(description); return (*this); }
585            virtual const std::string& getDescription()
586                { return this->loadexecutor_->getDescription(); }
587
588        private:
589            ExecutorMember<T>* loadexecutor_;
590            ExecutorMember<T>* saveexecutor_;
591    };
592}
593
594#endif /* _XMLPort_H__ */
Note: See TracBrowser for help on using the repository browser.