= XMLPort =
[[TOC]]
== Description ==
XMLPort.h is a compilation of macros and classes for easy XML parsing. Every object starting with [wiki:BaseObject] has some attributes to be set, either by a default value or specified in the [wiki:Level XML level file]. The [wiki:Loader] parses the file, creates the main objects an passes the attributes and subobjects to their XMLPort function.
Inside of this function, one macro for every parameter and every possible subobject defines how to assign the loaded values to the newly created object.
== The XMLPort Function ==
This is how an empty XMLPort function looks like:
*.h file:
{{{
class SomeClass : public BaseClass
{
public:
virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
};
}}}
*.cc file:
{{{
void SomeClass::XMLPort(Element& xmlelement, XMLPort::Mode mode)
{
SUPER(SomeClass, XMLPort, xmlelement, mode);
}
}}}
''xmlelement'' is a container, containing all attributes and subobjects passed to this class.[[br]]
''mode'' says if we're loading new objects from a file or saving existing objects to a file.[[br]]
''SUPER'' is a macro, see [wiki:Super] for more information.
'''Important''': XMLPort is a '''virtual''' function.
== Parameters ==
=== General ===
To load parameters like the name of an object, you need three things:
1. A set-function in your class to set the parameter:
{{{
void setName(const std::string& name);
}}}
2. A get-function returning the parameter:
{{{
const std::string& getName() const;
}}}
3. A call to the XMLPortParam macro in XMLPort:
{{{
void SomeClass::XMLPort(Element& xmlelement, XMLPort::Mode mode)
{
SUPER(SomeClass, XMLPort, xmlelement, mode);
XMLPortParam(SomeClass, "name", setName, getName, xmlelement, mode);
}
}}}
To create an instance of ''SomeClass'' and set the parameter ''name'', write the following text into the XML file:
{{{
}}}
XMLPortParam has the following form:
* '''XMLPortParam('''''classname, "param-name", set-function, get-function, xmlelement, mode''''')'''
''xmlelement'' and ''mode'' are received by the XMLPort function.
=== Ambiguity ===
Sometimes the name of the set-function in XMLPortParam is ambiguous, because the function is overloaded.
Example:
{{{
void setPosition(float x, float y, float z);
void setPosition(const Vector3& position);
}}}
In this case, the following code will fail:
{{{
XMLPortParam(SomeClass, "position", setPosition, getPosition, xmlelement, mode);
// Error: setPosition is ambiguous
}}}
The problem can be solved by using XMLPortParamTemplate:
{{{
// If you want to use the first variant with three floats:
XMLPortParamTemplate(SomeClass, "position", setPosition, getPosition, xmlelement, mode, float, float, float);
// If you want to use the second variant with a Vector3:
XMLPortParamTemplate(SomeClass, "position", setPosition, getPosition, xmlelement, mode, const Vector3&);
}}}
As you can see, the type(s) of the function arguments are just appended at the end of the macro.
=== Loadonly ===
In some special cases you don't want to save an existing parameter to the XML file. This could be the case if there are several dependend functions to set one parameter, but only one is needed to save the parameter.
Example: Rotation - you could pass a Quaternion or three angles or something else, but you only have to save the Quaternion. The three angles would then be stated as "loadonly":
{{{
XMLPortParamLoadOnly(SomeClass, "three-angles", setAngles, xmlelement, mode);
}}}
As you can see, there's no get-function.
Note: There is also a related macro called XMLPortParamLoadOnlyTemplate used to avoid ambiguity (see [wiki:XMLPort#Ambiguity the chapter above]).
=== Extern parameters ===
Sometimes you have a memberobject in you class which has a parameter that you want to set through XMLPort in your own class.
Example:
{{{
class Position
{
public:
void setPosition(const Vector3& position);
const Vector3& getPosition() const;
private:
Vector3 position_;
};
class SomeClass
{
public:
virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
private:
Position position_;
}
}}}
Of course you could just add two functions '''setPosition''' and '''getPosition''' to ''SomeClass'', but that would be a bit stupid. A more elegant way is to use '''XMLPortParamExtern''':
{{{
XMLPortParamExtern(SomeClass, Position, this->position_, "position", setPosition, getPosition, \
xmlelement, mode);
}}}
Note: The second and the third argument are new: ''Position'' is the class of the extern parameter, ''this->position_'' is the object. The other arguments stay the same, but the set- and get-function are now functions of ''Position'' instead of ''SomeClass'' and therefore we don't have to implement two useless functions.
Note: There is also a related macro called XMLPortParamExternTemplate used to avoid ambiguity (see [wiki:XMLPort#Ambiguity the chapter above]).
== Objects ==
=== General ===
To connect objects, you have to put one object into another object in the XML file:
{{{
}}}
In this example, we create one instance of ''SomeClass'' and connect three instances of ''OtherClass'' and two instances of ''DifferentClass'' to it.
To let the instance of ''SomeClass'' know there are some connected objects, we have to pass them to a function of ''SomeClass''. This can be achieved by using XMLPortObject:
{{{
void SomeClass::XMLPort(Element& xmlelement, XMLPort::Mode mode)
{
SUPER(SomeClass, XMLPort, xmlelement, mode);
XMLPortObject(SomeClass, OtherClass, "connected-objects", connectObject, getConnectedObject, \
xmlelement, mode);
XMLPortObject(SomeClass, DifferentClass, "more-objects", addDifferentObject, getDifferentObject, \
xmlelement, mode);
}
}}}
Note: We used XMLPortObject two times because we have two subsections with different types of connected objects.
XMLPortObject has the following form:
* '''XMLPortObject('''''classname, objectclass, sectionname, loadfunction, savefunction, xmlelement, mode''''')'''
''objectclass'' is the class of the conneted objects in the specified subsection.[[br]]
''sectionname'' is the name of the subsection.
'''Important''': If sectionname is an empty string (""), '''no''' subsection is used, so you can put sub-objects directly into the base object.
The set- and the get-function must have the following form:
* void set-function(objectclass* object);
* const objectclass* get-function(unsigned int index) const;
The set-function just passes the pointer of the connected object.[[br]]
The get-function returns a different pointer for each index, starting with zero. If all pointers were returned, the get-function returns a NULL pointer and the process stops.
Note: There is also a related macro called XMLPortObjectTemplate used to avoid ambiguity (see [wiki:XMLPort#Ambiguity the chapter above]).
=== Extended ===
There is an extended version of the XMLPortParam macro, taking two additional arguments:
* '''XMLPortObjectExtended('''''classname, objectclass, sectionname, loadfunction, savefunction, xmlelement, mode, bApplyLoaderMask, bLoadBefore''''')'''
If ''bApplyLoaderMask'' is true, a subobject gets only created and connected if it's class is included in the mask of the [wiki:Loader]. This argument is usually ''false'' because not connecting a subobject might damage the base-object, although the base-object IS included in the Loaders mask and should therefore not be touched.
If ''bLoadBefore'' is true, the subobject will get connected after all parameters (and subobjects of the subobject) are completely loaded. This argument is usually ''true'' because we might use the connected object already in the set-function. If the subobject is not already loaded at this point, this could cause trouble.
Note: There is also a related macro called XMLPortObjectExtendedTemplate used to avoid ambiguity (see [wiki:XMLPort#Ambiguity the chapter above]).