[Doc] Improve documentation PropertyContainer

This commit is contained in:
Pieter Hijma
2025-04-11 20:49:56 +02:00
committed by Benjamin Nauck
parent 8956c56235
commit 519b78d775
6 changed files with 489 additions and 116 deletions

View File

@@ -334,6 +334,14 @@ public:
return FeatureT::canLoadPartial();
}
/**
* @brief Called when a property is edited by the user.
*
* This override first attempts to handle the property edit in the
* associated Python object.
*
* @param[in] propName The name of the property to be edited.
*/
void editProperty(const char* propName) override
{
if (!imp->editProperty(propName)) {

View File

@@ -63,49 +63,83 @@ class AppExport Property: public Base::Persistence
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
/**
* @brief Defines the position in the status bitmask.
*/
enum Status
{
Touched = 0, // touched property
Immutable = 1, // can't modify property
ReadOnly = 2, // for property editor
Hidden = 3, // for property editor
Transient = 4, // for property container save
MaterialEdit = 5, // to turn ON PropertyMaterial edit
NoMaterialListEdit = 6, // to turn OFF PropertyMaterialList edit
Output = 7, // same effect as Prop_Output
LockDynamic = 8, // prevent being removed from dynamic property
NoModify = 9, // prevent causing Gui::Document::setModified()
PartialTrigger = 10, // allow change in partial doc
NoRecompute = 11, // don't touch owner for recompute on property change
Single = 12, // for save/load of floating point numbers
Ordered = 13, // for PropertyLists whether the order of the elements is
// relevant for the container using it
EvalOnRestore = 14, // In case of expression binding, evaluate the
// expression on restore and touch the object on value change.
Busy = 15, // internal use to avoid recursive signaling
CopyOnChange =
16, // for Link to copy the linked object on change of the property with this flag
UserEdit = 17, // cause property editor to create button for user defined editing
/// @brief Whether a property is touched.
Touched = 0,
/// @brief Whether a property can be modified.
Immutable = 1,
/// @brief Whether a property is read-only for the property editor.
ReadOnly = 2,
/// @brief Whether the property is hidden in the property editor.
Hidden = 3,
/// @brief Whether a property is saved in the document.
Transient = 4,
/// @brief To turn ON PropertyMaterial edit.
MaterialEdit = 5,
/// @brief To turn OFF PropertyMaterialList edit.
NoMaterialListEdit = 6,
/// @brief Whether a property is an output property.
Output = 7,
/// @brief Whether a dynamic property can be removed.
LockDynamic = 8,
/// @brief Prevents causing `Gui::Document::setModified()`
NoModify = 9,
/// @brief Whether to allow change in a partial document.
PartialTrigger = 10,
/// @brief Whether to prevent to touch the owner for a recompute on property change.
NoRecompute = 11,
/// @brief Whether a floating point number should be saved as single precision.
Single = 12,
/// @brief For PropertyLists, whether the order of the elements is
/// relevant for the container using it.
Ordered = 13,
/// @brief In case of expression binding, whether the expression on
/// restore and touch the object on value change.
EvalOnRestore = 14,
/// @brief For internal use to avoid recursive signaling.
Busy = 15,
/// @brief Whether the linked object should be copied on change of the property.
CopyOnChange = 16,
/// @brief Whether the property editor should create a button for user defined editing.
UserEdit = 17,
// The following bits are corresponding to PropertyType set when the
// property added. These types are meant to be static, and cannot be
// changed in runtime. It is mirrored here to save the linear search
// required in PropertyContainer::getPropertyType()
//
/// @brief Mark the beginning of enum PropertyType bits.
PropStaticBegin = 21,
PropDynamic = 21, // indicating the property is dynamically added
PropNoPersist = 22, // corresponding to Prop_NoPersist
PropNoRecompute = 23, // corresponding to Prop_NoRecompute
PropReadOnly = 24, // corresponding to Prop_ReadOnly
PropTransient = 25, // corresponding to Prop_Transient
PropHidden = 26, // corresponding to Prop_Hidden
PropOutput = 27, // corresponding to Prop_Output
/// @brief Whether the property is dynamically added.
PropDynamic = 21,
/// @brief Corresponds to Prop_NoPersist
PropNoPersist = 22,
/// @brief Corresponds to Prop_NoRecompute
PropNoRecompute = 23,
/// @brief Corresponds to Prop_ReadOnly
PropReadOnly = 24,
/// @brief Corresponds to Prop_Transient
PropTransient = 25,
/// @brief Corresponds to Prop_Hidden
PropHidden = 26,
/// @brief Corresponds to Prop_Output
PropOutput = 27,
/// @brief Mark the end of enum PropertyType bits.
PropStaticEnd = 28,
User1 = 28, // user-defined status
User2 = 29, // user-defined status
User3 = 30, // user-defined status
User4 = 31 // user-defined status
/// @brief User defined status bit.
User1 = 28,
/// @brief User defined status bit.
User2 = 29,
/// @brief User defined status bit.
User3 = 30,
/// @brief User defined status bit.
User4 = 31
};
Property();

View File

@@ -46,10 +46,6 @@ using namespace std;
TYPESYSTEM_SOURCE(App::PropertyContainer,Base::Persistence)
//**************************************************************************
// Construction/Destruction
// Here's the implementation! Description should take place in the header file!
PropertyContainer::PropertyContainer()
{
propertyData.parentPropertyData = nullptr;
@@ -68,7 +64,6 @@ unsigned int PropertyContainer::getMemSize () const
return size;
}
App::Property* PropertyContainer::addDynamicProperty(
const char* type, const char* name, const char* group, const char* doc,
short attr, bool ro, bool hidden)
@@ -191,18 +186,6 @@ const PropertyData * PropertyContainer::getPropertyDataPtr(){return &propertyDat
const PropertyData & PropertyContainer::getPropertyData() const{return propertyData;}
/**
* @brief PropertyContainer::handleChangedPropertyName is called during restore to possibly
* fix reading of older versions of this property container. This method is typically called
* if the property on file has changed its name in more recent versions.
*
* The default implementation does nothing.
*
* @param reader The XML stream to read from.
* @param TypeName Name of property type on file.
* @param PropName Name of property on file that does not exist in the container anymore.
*/
void PropertyContainer::handleChangedPropertyName(Base::XMLReader &reader, const char * TypeName, const char *PropName)
{
(void)reader;
@@ -210,18 +193,6 @@ void PropertyContainer::handleChangedPropertyName(Base::XMLReader &reader, const
(void)PropName;
}
/**
* @brief PropertyContainer::handleChangedPropertyType is called during restore to possibly
* fix reading of older versions of the property container. This method is typically called
* if the property on file has changed its type in more recent versions.
*
* The default implementation does nothing.
*
* @param reader The XML stream to read from.
* @param TypeName Name of property type on file.
* @param prop Pointer to property to restore. Its type differs from TypeName.
*/
void PropertyContainer::handleChangedPropertyType(XMLReader &reader, const char *TypeName, Property *prop)
{
(void)reader;

View File

@@ -45,15 +45,29 @@ class DocumentObject;
class Extension;
// clang-format off
/**
* @brief Flags that define special behaviors for a property.
*
* These flags can be combined using bitwise OR to assign multiple attributes
* to a property.
*/
enum PropertyType
{
Prop_None = 0, /*!< No special property type */
Prop_ReadOnly = 1, /*!< Property is read-only in the editor */
Prop_Transient = 2, /*!< Property content won't be saved to file, but still saves name, type and status */
Prop_Hidden = 4, /*!< Property won't appear in the editor */
Prop_Output = 8, /*!< Modified property doesn't touch its parent container */
Prop_NoRecompute = 16,/*!< Modified property doesn't touch its container for recompute */
Prop_NoPersist = 32,/*!< Property won't be saved to file at all */
/// @brief No special property type.
Prop_None = 0,
/// @brief The property is read-only in the editor.
Prop_ReadOnly = 1,
/// @brief The property content won't be saved to file, but still saves name, type and status.
Prop_Transient = 2,
/// @brief The property is hidden in the editor.
Prop_Hidden = 4,
/// @brief A modified property doesn't touch its parent container.
Prop_Output = 8,
/// @brief A modified property doesn't touch its container for recompute.
Prop_NoRecompute = 16,
/// @brief property won't be saved to file at all.
Prop_NoPersist = 32,
};
// clang-format on
@@ -148,7 +162,15 @@ struct AppExport PropertyData
};
/** Base class of all classes with properties
/** @brief %Base class of all classes with properties.
* @ingroup PropertyFramework
*
* @details This base class for all classes that hold properties has
* essentially two important children: Document and DocumentObject. Both
* classes can hold properties and the shared functionality to make that happen
* is in this class.
*
* For a more high-level overview see topic @ref PropertyFramework "Property Framework".
*/
class AppExport PropertyContainer: public Base::Persistence
{
@@ -157,94 +179,304 @@ class AppExport PropertyContainer: public Base::Persistence
public:
/**
* A constructor.
* A more elaborate description of the constructor.
* @brief Construct a property container.
*/
PropertyContainer();
/**
* A destructor.
* A more elaborate description of the destructor.
* @brief Destruct a property container.
*/
~PropertyContainer() override;
unsigned int getMemSize () const override;
/**
* @brief Get the full name of the property container.
*
* The full name typically also contains the name of the document.
*
* @return The full name of the property container.
*/
virtual std::string getFullName() const {return {};}
/// find a property by its name
/**
* @brief Find a property by its name.
*
* @param[in] name The name of the property to find.
* @return The property if found or `nullptr` when not found.
*/
virtual Property *getPropertyByName(const char* name) const;
/// get the name of a property
/**
* @brief Get the name of a property.
*
* @param[in] prop The property to get the name for.
* @return The name of the property.
*/
virtual const char* getPropertyName(const Property* prop) const;
/// get all properties of the class (including properties of the parent)
virtual void getPropertyMap(std::map<std::string,Property*> &Map) const;
/// get all properties of the class (including properties of the parent)
/**
* Get all properties of the property container.
*
* This includes the properties of the parent container.
*
* @param[out] map A map of property names to properties.
*/
virtual void getPropertyMap(std::map<std::string,Property*> &map) const;
/**
* Get all properties of the property container.
*
* This includes the properties of the parent container.
*
* @param[out] List A vector of properties.
*/
virtual void getPropertyList(std::vector<Property*> &List) const;
/// Call the given visitor for each property. The visiting order is undefined.
/// This method is necessary because PropertyContainer has no begin and end methods
/// and it is not practical to implement these.
/// What gets visited is undefined if the collection of Properties is changed during this call.
/**
* @brief Visit each property in the container.
*
* This method allows you to apply a function to each property in the
* container. The visiting order is undefined. This mehod is necessary
* because PropertyContainer has no begin and end methods and it is not
* practical to implement these. What gets visited is undefined if the
* collection of Properties is changed during this call.
*
* @param[in] visitor The function to apply to each property.
*/
virtual void visitProperties(const std::function<void(Property*)>& visitor) const;
/// get all properties with their names, may contain duplicates and aliases
virtual void getPropertyNamedList(std::vector<std::pair<const char*,Property*> > &List) const;
/// set the Status bit of all properties at once
/**
* @brief Get a list of properties with their names.
*
* The list may contain duplicates and aliases.
*
* @param[out] List A vector of pairs, where each pair contains the name and
* the property.
*/
virtual void getPropertyNamedList(std::vector<std::pair<const char*,Property*> > &list) const;
/**
* @brief Set a status bit for all properties.
*
* This method sets a status bit for all properties in the container at once.
* The status bits are defined in enum Property::Status.
*
* @param[in] bit The status bit to set.
* @param[in] value The value to set the status bit to.
*/
void setPropertyStatus(unsigned char bit,bool value);
/// get the Type of a Property
/**
* @brief Get the type of a property given a property.
*
* This method returns the type as a bitmask of the PropertyType enum.
*
* @param[in] prop The property to get the type for.
* @return The type as a bitmask of the PropertyType enum.
*/
virtual short getPropertyType(const Property* prop) const;
/// get the Type of a named Property
/**
* @brief Get the type of a property given a property name.
*
* This method returns the type as a bitmask of the PropertyType enum.
*
* @param[in] name The name of the property to get the type for.
* @return The type as a bitmask of the PropertyType enum.
*/
virtual short getPropertyType(const char *name) const;
/// get the Group of a Property
/**
* @brief Get the group of a property given a property.
*
* @param[in] prop The property to get the group for.
* @return The group name of the property.
*/
virtual const char* getPropertyGroup(const Property* prop) const;
/// get the Group of a named Property
/**
* @brief Get the group of a property given a property name.
*
* @param[in] name The name of the property to get the group for.
* @return The group name of the property.
*/
virtual const char* getPropertyGroup(const char *name) const;
/// get the Group of a Property
/**
* @brief Get the documentation of a property given a property.
*
* @param[in] prop The property to get the documentation for.
* @return The documentation string of the property.
*/
virtual const char* getPropertyDocumentation(const Property* prop) const;
/// get the Group of a named Property
/**
* @brief Get the documentation of a property given a property name.
*
* @param[in] name The name of the property to get the documentation for.
* @return The documentation string of the property.
*/
virtual const char* getPropertyDocumentation(const char *name) const;
/// check if the property is read-only
/**
* @brief Check if a property is read-only given a property.
*
* @param[in] prop The property to check.
* @return `true` if the property is read-only; `false` otherwise.
*/
bool isReadOnly(const Property* prop) const;
/// check if the named property is read-only
/**
* @brief Check if a property is read-only given a property name.
*
* @param[in] name The name of the property to check.
* @return `true` if the property is read-only; `false` otherwise.
*/
bool isReadOnly(const char *name) const;
/// check if the property is hidden
/**
* @brief Check if a property is hidden given a property.
*
* @param[in] prop The property to check.
* @return `true` if the property is hidden; `false` otherwise.
*/
bool isHidden(const Property* prop) const;
/// check if the named property is hidden
/**
* @brief Check if a property is hidden given a property name.
*
* @param[in] name The name of the property to check.
* @return `true` if the property is hidden; `false` otherwise.
*/
bool isHidden(const char *name) const;
/**
* Add a property at runtime.
*
* Dynamic properties are properties that are not defined at compile-time
* but can be added and removed during the lifetime of the object.
*
* @param[in] type The type name of the property (e.g., "App::PropertyFloat").
* @param[in] name Optional name of the property. If null, a default name may be generated.
* @param[in] group Optional group name to which the property belongs
* (used for UI or logical grouping).
* @param[in] doc Optional documentation string describing the purpose of the property.
* @param[in] attr Bitmask of property attributes, composed of values from the
* PropertyType enum.
* @param[in] ro If true, the property is marked as read-only.
* @param[in] hidden If true, the property is hidden from the user interface.
* @return A pointer to the newly added Property.
* @throws Exception A runtime exception is thrown if the property cannot be added, such
* as when the name is invalid.
*/
virtual App::Property* addDynamicProperty(
const char* type, const char* name=nullptr,
const char* group=nullptr, const char* doc=nullptr,
short attr=0, bool ro=false, bool hidden=false);
/**
* @brief Get the data of a dynamic property.
*
* This function retrieves the data associated with a dynamic property.
*
* @param[in] prop The property to get the data for.
* @returns The data of the dynamic property.
*/
DynamicProperty::PropData getDynamicPropertyData(const Property* prop) const {
return dynamicProps.getDynamicPropertyData(prop);
}
/**
* Change the group and documentation of a dynamic property.
*
* @param[in] prop The property to change.
* @param[in] group The new group name for organizational purposes, (e.g., in UI panels).
* @param[in] doc The new documentation string for this property.
* @return `true` if the update was successful; `false` otherwise.
*/
bool changeDynamicProperty(const Property *prop, const char *group, const char *doc) {
return dynamicProps.changeDynamicProperty(prop,group,doc);
}
/**
* @brief Remove a dynamic property.
*
* @param[in] name The name of the property to remove.
* @return `true` if the property was removed; `false` otherwise.
*/
virtual bool removeDynamicProperty(const char* name) {
return dynamicProps.removeDynamicProperty(name);
}
/**
* @brief Get the names of all dynamic properties.
*
* @returns A vector of strings containing the names of all dynamic properties.
*/
virtual std::vector<std::string> getDynamicPropertyNames() const {
return dynamicProps.getDynamicPropertyNames();
}
/**
* @brief Get a dynamic property.
*
* @param[in] name The name of the property.
* @returns The property if found or `nullptr` when not found.
*/
virtual App::Property *getDynamicPropertyByName(const char* name) const {
return dynamicProps.getDynamicPropertyByName(name);
}
/**
* @brief Called when the status of a property is changed.
*
* This method is called when the status of a property changes. It can be
* overridden by subclasses to implement custom behavior when a property
* status changes.
*
* @param[in] prop The property whose status has changed.
* @param[in] oldStatus The old status of the property as a bitmask of enum
* Property::Status.
*/
virtual void onPropertyStatusChanged(const Property &prop, unsigned long oldStatus);
void Save (Base::Writer &writer) const override;
void Restore(Base::XMLReader &reader) override;
/**
* @brief Prepare the properties for saving.
*
* All non-transient properties are prepared to be saved.
*
* @see Property::beforeSave()
*/
virtual void beforeSave() const;
virtual void editProperty(const char * /*propName*/) {}
/**
* @brief Called when a property is edited by the user.
*
* Subclasses can override this method to implement custom behavior for
* editing specific properties.
*
* @param[in] propName The name of the property to be edited.
*/
virtual void editProperty([[maybe_unused]] const char* propName) {}
/**
* @brief Get the prefix for property names.
*
* @return The prefix for property names.
*/
const char *getPropertyPrefix() const {
return _propertyPrefix.c_str();
}
/**
* @brief Set the prefix for property names.
*
* @param[in] prefix The new prefix for property names.
*/
void setPropertyPrefix(const char *prefix) {
_propertyPrefix = prefix;
}
@@ -254,29 +486,113 @@ public:
protected:
/** get called by the container when a property has changed
/**
* @brief Called when a property is about to change.
*
* This function is called before onChanged()
* This method can be overridden by subclasses to implement custom behavior
* when a property is about to change. This method is called in
* Property::touch() right before onChanged() is called, typically in the
* DocumentObject::execute() phase.
*
* @note This can be considered a low-level callback and is not widely
* overridden. For preparing for a property change, use onBeforeChange().
*
* @param[in] prop The property that is about to change.
* @see Property::onBeforeChange()
*/
virtual void onEarlyChange(const Property* /*prop*/){}
/// get called by the container when a property has changed
virtual void onChanged(const Property* /*prop*/){}
/// get called before the value is changed
virtual void onBeforeChange(const Property* /*prop*/){}
virtual void onEarlyChange([[maybe_unused]] const Property* prop){}
//void hasChanged(Property* prop);
static const PropertyData * getPropertyDataPtr();
/**
* @brief Called when a property has changed.
*
* This method can be overridden by subclasses to implement custom behavior
* when a property has changed.
*
* @param[in] prop The property that has changed.
*/
virtual void onChanged([[maybe_unused]] const Property* prop){}
/**
* @brief Called before a property is changed.
*
* This method can be overridden by subclasses to implement custom behavior
* before a property has changed. It allows property containers to prepare
* for a property change.
*
* @param[in] prop The property that is about to change.
*/
virtual void onBeforeChange([[maybe_unused]] const Property* prop){}
/**
* @brief Get a pointer to the class-wide static property data.
*
* This method gives access to the class-wide static PropertyData shared by
* all instances of the class. The macros `PROPERTY_HEADER` and
* `PROPERTY_SOURCE` variants ensure that each subclass of %PropertyContainer
* has its own static PropertyData instance, and that this method returns the
* instance for that subclass.
*
* @returns A pointer to the static `PropertyData`.
*/
static const PropertyData* getPropertyDataPtr();
/**
* @brief Get a reference to the static property data for the dynamic type of this instance.
*
* This virtual method allows retrieval of the class-level static
* PropertyData associated with the actual (dynamic) type of the object, even
* when accessed via a base class pointer. The `PROPERTY_HEADER` and
* `PROPERTY_SOURCE` macros ensure that each subclass defines its own static
* PropertyData instance, and that this method correctly dispatches to return
* it.
*
* @return A reference to the static `PropertyData` corresponding to the dynamic type.
*/
virtual const PropertyData& getPropertyData() const;
virtual void handleChangedPropertyName(Base::XMLReader &reader, const char * TypeName, const char *PropName);
virtual void handleChangedPropertyType(Base::XMLReader &reader, const char * TypeName, Property * prop);
/**
* @brief Handle a changed property name during restore.
*
* This method is called during restore to possibly fix reading of older
* versions of this property container. This method is typically called if
* the property on file has changed its name in more recent versions.
*
* The default implementation does nothing.
*
* @param[in,out] reader The XML stream to read from.
* @param[in] typeName The name of the property type in the file.
* @param[in] propName The name of the property in the file that does no
* longer exist in the container.
*/
virtual void handleChangedPropertyName(Base::XMLReader& reader, const char* typeName, const char* propName);
/**
* @brief Handle a changed property type during restore.
*
* This method is called during restore to possibly fix reading of older
* versions of this property container. This method is typically called if
* the property on file has changed its type in more recent versions.
*
* The default implementation does nothing.
*
* @param[in,out] reader The XML stream to read from.
* @param[in] typeName The name of the property type in the file.
* @param[in, out] prop The property that needs to be restored. Its type differs from `typeName`.
*/
virtual void handleChangedPropertyType(Base::XMLReader &reader, const char * typeName, Property * prop);
public:
// forbidden
/// @brief The copy constructor is deleted to prevent copying.
PropertyContainer(const PropertyContainer&) = delete;
/// @brief The assignment operator is deleted to prevent assignment.
PropertyContainer& operator = (const PropertyContainer&) = delete;
protected:
/**
* @brief The container for dynamic properties.
*/
DynamicProperty dynamicProps;
private:

View File

@@ -6,6 +6,12 @@
* @ref DocumentGroup "Document", @ref DocumentObjectGroup "Document Object",
* the @ref ExpressionFramework "Expression Framework", and the @ref
* PropertyFramework "Property Framework".
*
* The largest difference between the functionality in @ref BASE "Base"
* compared to %App is that %App introduces the notion of properties, both used
* in @ref App::Document "Document" and @ref App::DocumentObject
* "DocumentObject". In addition, %App has a representation of the running
* @ref App::Application "Application".
*/
/**
@@ -58,11 +64,46 @@
*
* The property framework introduces the ability to access attributes (member
* variables) of a class by name without knowing the class type. It's like the
* reflection mechanism of Java or C#. This ability is introduced by the
* App::PropertyContainer class and can be used by all derived classes.
* reflection mechanism of Java or C#. This ability is introduced by the @ref
* App::PropertyContainer "PropertyContainer" class and can be used by all
* derived classes. In particular, there are two classes that inherit from
* @ref App::PropertyContainer "PropertyContainer" which are @ref App::Document
* "Document" and @ref App::DocumentObject "DocumentObject". These two classes
* serve different purposes but are both able to hold properties. @ref
* App::PropertyContainer "PropertyContainer" contains the shared logic to do
* so.
*
* This makes it possible in the first place to make an automatic mapping to python (e.g. in App::FeaturePy) and
* abstract editing properties in Gui::PropertyEditor.
* In C++, it is possible to define properties as part of the class. These can
* be considered "static" properties but this term is typically not used within
* FreeCAD. Properties created in a class cannot be removed from a @ref
* App::PropertyContainer "PropertyContainer".
*
* However, it is also possible to add properties to a @ref
* App::PropertyContainer "PropertyContainer" at runtime. These properties are
* called "dynamic properties" and these properties can be freely added and
* removed by users.
*
* In Python, all properties are dynamic properties. This makes it difficult
* to understand whether properties are part of a Python class and are
* necessary for the functioning of the class, or whether a user has added
* these properties. Therefore, it is possible to indicate that a property is
* "locked":
*
* @code
* prop->setStatus(Property::LockDynamic, true);
* @endcode
*
* In Python, this can be indicated in the `addProperty()` function:
*
* @code
* addProperty(type: string, name: string, group="", doc="",
* attr=0, read_only=False, hidden=False,
* locked=False, enum_vals=[])
* @endcode
*
* The Property Framework makes it possible in the first place to make an
* automatic mapping to python (e.g. in App::FeaturePy) and abstract editing
* properties in Gui::PropertyEditor.
*
* @section Examples
*

View File

@@ -39,11 +39,14 @@ class BaseExport Persistence: public BaseClass
TYPESYSTEM_HEADER();
public:
/** This method is used to get the size of objects
* It is not meant to have the exact size, it is more or less an estimation
* which runs fast! Is it two bytes or a GB?
/**
* @brief Get the size of objects.
*
* It is not meant to have the exact size, it is more or less a fast
* estimation to tell whether it is two bytes or a GB.
*/
virtual unsigned int getMemSize() const = 0;
/** This method is used to save properties to an XML document.
* A good example you'll find in PropertyStandard.cpp, e.g. the vector:
* \code