Added documentation to Property class

Modified callback function mechanism to only allow one call back function to be present
This commit is contained in:
Alexander Bock
2014-09-07 15:01:54 +02:00
parent cd29bbee70
commit eb7d1aac06
3 changed files with 213 additions and 39 deletions

View File

@@ -39,42 +39,216 @@ namespace properties {
class PropertyOwner;
/**
* A property encapsulates a value which should be user-changeable. A property almost
* always belongs to a PropertyOwner who has taken ownership (setPropertyOwner) of the
* Property. Per PropertyOwner, the <code>identifier</code> needs to be unique and can be
* used as a URI. This class is an abstract base class and each subclass (most notable
* TemplateProperty) needs to implement the methods Property::className, Property::get,
* Property::set, Property::type(), Property::getLua, Property::setLua, and
* Property::typeLua to make full use of the infrastructure.
* The most common types can be implemented by creating a specialized instantiation of
* TemplateProperty, which provides default implementations for these methods.
*
* The onChange method can be used by the PropertyOwner to listen to changes that happen
* to the Property. The parameter is a function object that gets called after new value
* has been set.
* The metaData allows the developer to specify additional information about the Property
* which might be used in GUI representations. One example would be a glm::vec4 property,
* (Vec4Property) that can either represent a 4-dimensional position, a powerscaled
* coordinate, a light position, or other things, requiring different GUI representations.
* \see TemplateProperty
* \see PropertyOwner
*/
class Property {
public:
/**
* The constructor for the property. The <code>identifier</code> needs to be unique
* for each PropertyOwner. The <code>guiName</code> will be stored in the metaData
* to be accessed by the GUI elements using the <code>guiName</code> key. The default
* visibility settings is <code>true</code>, whereas the default read-only state is
* <code>false</code>.
* \param identifier A unique identifier for this property. It has to be unique to the
* PropertyOwner
* \param guiName The human-readable GUI name for this Property
*/
Property(std::string identifier, std::string guiName);
/**
* The destructor taking care of deallocating all unused memory. This method will not
* remove the Property from the PropertyOwner.
*/
virtual ~Property();
//virtual Property* create() const = 0;
/**
* This method returns the class name of the Property. The method is used by the
* TemplateFactory to create new instances of Propertys. The returned value is almost
* always identical to the C++ class name of the derived class.
* \return The class name of the Property
*/
virtual std::string className() const = 0;
/**
* This method returns the encapsulated value of the Property to the caller. The type
* that is returned is determined by the type function and is up to the developer of
* the derived class. The default implementation returns an empty boost::any object.
* \return The value that is encapsulated by this Property, or an empty boost::any
* object if the method was not overritten.
*/
virtual boost::any get() const;
virtual void set(boost::any value);
virtual const std::type_info& type() const;
/**
* Sets the value encapsulated by this Property to the <code>value</code> passed to
* this function. It is the caller's responsibility to ensure that the type contained
* in <code>value</code> is compatible with the concrete subclass of the Property. The
* method Property::type will return the desired type for the Property. The default
* implementation of this method ignores the input.
* \param value The new value that should be stored in this Property
*/
virtual void set(boost::any value);
/**
* This method returns the type that is requested by this Property for the set method.
* The default implementation returns the type of <code>void</code>.
* \return The type that is requested by this Property's Property::set method
*/
virtual const std::type_info& type() const;
/**
* This method encodes the encapsulated value of this Property at the top of the Lua
* stack. The specific details of this serialization is up to the property developer
* as long as the rest of the stack is unchanged. The implementation has to be
* synchronized with the Property::setLua method. The default implementation is a
* no-op.
* \param state The Lua state to which the value will be encoded
* \return <code>true</code> if the encoding succeeded, <code>false</code> otherwise
*/
virtual bool getLua(lua_State* state) const;
/**
* This method sets the value encapsulated by this Property by deserializing the value
* on top of the passed Lua stack. The specific details of the deserialization are up
* to the Property developer, but they must only depend on the top element of the
* stack and must leave all other elements unchanged. The implementation has to be
* synchronized with the Property::getLua method. The default implementation is a
* no-op.
* \param state The Lua state from which the value will be decoded
* \return <code>true</code> if the decoding and setting of the value succeeded,
* <code>false</code> otherwise
*/
virtual bool setLua(lua_State* state);
/**
* Returns the Lua type that will be put onto the stack in the Property::getLua method
* and which will be consumed by the Property::setLua method. The returned value
* can belong to the set of Lua types: <code>LUA_TNONE</code>, <code>LUA_TNIL</code>,
* <code>LUA_TBOOLEAN</code>, <code>LUA_TLIGHTUSERDATA</code>,
* <code>LUA_TNUMBER</code>, <code>LUA_TSTRING</code>, <code>LUA_TTABLE</code>,
* <code>LUA_TFUNCTION</code>, <code>LUA_TUSERDATA</code>, or
* <code>LUA_TTHREAD</code>. The default implementation will return
* <code>LUA_TNONE</code>.
* \return The Lua type that will be consumed or produced by the Property::getLua and
* Property::setLua methods.
*/
virtual int typeLua() const;
/**
* This method registers a <code>callback</code> function that will be called every
* time if either Property:set or Property::setLua was called with a value that is
* different from the previously stored value. The callback can be removed my passing
* an empty <code>std::function<void()></code> object.
* \param callback The callback function that is called when the encapsulated type has
* been successfully changed by either the Property::set or Property::setLua methods.
*/
virtual void onChange(std::function<void()> callback);
/**
* This method returns the unique identifier of this Property.
* \return The unique identifier of this Property
*/
const std::string& identifier() const;
const std::string& guiName() const;
/**
* Returns the PropertyOwner of this Property or <code>nullptr</code>, if it does not
* have an owner.
*\ return The Property of this Property
*/
PropertyOwner* owner() const;
void setPropertyOwner(PropertyOwner* owner);
/**
* Assigned the Property to a new PropertyOwner. This method does not inform the
* PropertyOwner of this action.
* \param owner The new PropertyOwner for this Property
*/
void setPropertyOwner(PropertyOwner* owner);
/**
* Returns the human-readable GUI name for this Property that has been set in the
* constructor. This method returns the same value as accessing the metaData object
* and requesting the <code>std::string</code> stored for the <code>guiName</code>
* key.
* \return The human-readable GUI name for this Property
*/
const std::string& guiName() const;
/**
* Sets the identifier of the group that this Property belongs to. Property groups can
* be used, for example, by GUI application to visually group different properties,
* but it has no impact on the Property itself. The default value for the groupID is
* <code>""</code>.
* \param groupId The group id that this property should belong to
*/
void setGroupIdentifier(std::string groupId);
/**
* Returns the group idenfier that this Property belongs to, or <code>""</code> if it
* belongs to no group.
* \return The group identifier that this Property belongs to
*/
std::string groupIdentifier() const;
/**
* Determines a hint if this Property should be visible, or hidden. Each application
* accessing the properties is free to ignore this hint. It is stored in the metaData
* Dictionary with the key: <code>isVisible</code>. The default value is
* <code>true</code>.
* \param state <code>true</code> if the Property should be visible,
* <code>false</code> otherwise.
*/
void setVisible(bool state);
bool isVisible() const;
void setReadOnly(bool state);
bool isReadOnly() const;
/**
* This method determines if this Property should be read-only in external
* applications. This setting is only a hint and does not need to be followed by GUI
* applications and does not have any effect on the Property::set or Property::setLua
* methods. The value is stored in the metaData Dictionary with the key:
* <code>isReadOnly</code>. The default value is <code>false</code>.
* \param state <code>true</code> if the Property should be read only,
* <code>false</code> otherwise
*/
void setReadOnly(bool state);
/**
* This method allows the developer to give hints to the GUI about different
* representations for the GUI. The same Property (for example Vec4Property) can be
* used in different ways, each requiring a different input method. These values are
* stored in the metaData object using the <code>views.</code> prefix in front of the
* <code>option</code> parameter. See Property::ViewOptions for a default list of
* possible options. As these are only hints, the GUI is free to ignore any suggestion
* by the developer.
* \param option The view option that should be modified
* \param value Determines if the view option should be active (<code>true</code>) or
* deactivated (<code>false</code>)
*/
void setViewOption(std::string option, bool value = true);
bool viewOption(const std::string& option) const;
/**
* Default view options that can be used in the Property::setViewOption method. The
* values are: Property::ViewOptions::Color = <code>color</code>,
* Property::ViewOptions::LightPosition = <code>lightPosition</code>,
* Property::ViewOptions::PowerScaledScalar = <code>powerScaledScalar</code>, and
* Property::ViewOptions::PowerScaledCoordinate = <code>powerScaledCoordinate</code>.
*/
struct ViewOptions {
static const std::string Color;
static const std::string LightPosition;
@@ -82,18 +256,32 @@ public:
static const std::string PowerScaledCoordinate;
};
/**
* Returns the metaData that contains all information for external applications to
* correctly display information about the Property. No information that is stored in
* this Dictionary is necessary for the programmatic use of the Property.
* \return The Dictionary containing all meta data information about this Property
*/
const ghoul::Dictionary& metaData() const;
protected:
void notifyListeners();
/**
* This method must be called by all subclasses whenever the encapsulated value has
* changed and a potential listener has to be informed.
*/
void notifyListener();
PropertyOwner* _owner;
/// The PropetyOwner this Property belongs to, or <code>nullptr</code>
PropertyOwner* _owner;
/// The identifier for this Property
std::string _identifier;
std::string _guiName;
/// The Dictionary containing all meta data necessary for external applications
ghoul::Dictionary _metaData;
std::vector<std::function<void()>> _onChangeCallbacks;
/// The callback function that will be invoked whenever the encapsulated value changes
std::function<void()> _onChangeCallback;
};
} // namespace properties

View File

@@ -133,7 +133,7 @@ template <typename T>
void TemplateProperty<T>::set(boost::any value) {
try {
_value = boost::any_cast<T>(std::move(value));
notifyListeners();
notifyListener();
}
catch (boost::bad_any_cast&) {
LERRORC("TemplateProperty", "Illegal cast from '" << value.type().name()

View File

@@ -30,9 +30,12 @@ namespace openspace {
namespace properties {
namespace {
const std::string _metaDataKeyGuiName = "guiName";
const std::string _metaDataKeyGroup = "group";
const std::string _metaDataKeyVisible = "isVisible";
const std::string _metaDataKeyReadOnly = "isReadOnly";
const std::string _metaDataKeyViewPrefix = "view.";
}
const std::string Property::ViewOptions::Color = "color";
@@ -43,9 +46,9 @@ const std::string Property::ViewOptions::PowerScaledScalar = "powerScaledScalar"
Property::Property(std::string identifier, std::string guiName)
: _identifier(std::move(identifier))
, _guiName(std::move(guiName))
{
setVisible(true);
_metaData.setValue(_metaDataKeyGuiName, std::move(guiName));
}
Property::~Property() {}
@@ -77,7 +80,9 @@ int Property::typeLua() const {
}
const std::string& Property::guiName() const {
return _guiName;
std::string result = "";
_metaData.getValue(_metaDataKeyGuiName, result);
return std::move(result);
}
void Property::setGroupIdentifier(std::string groupId) {
@@ -94,30 +99,12 @@ void Property::setVisible(bool state) {
_metaData.setValue(_metaDataKeyVisible, state);
}
bool Property::isVisible() const {
bool result = false;
_metaData.getValue(_metaDataKeyVisible, result);
return result;
}
void Property::setReadOnly(bool state) {
_metaData.setValue(_metaDataKeyReadOnly, state);
}
bool Property::isReadOnly() const {
bool result = false;
_metaData.getValue(_metaDataKeyReadOnly, result);
return result;
}
void Property::setViewOption(std::string option, bool value) {
_metaData.setValue("view." + option, value, true);
}
bool Property::viewOption(const std::string& option) const {
bool result = false;
_metaData.getValue("view." + option, result);
return result;
_metaData.setValue(_metaDataKeyViewPrefix + option, value, true);
}
const ghoul::Dictionary& Property::metaData() const {
@@ -125,7 +112,7 @@ const ghoul::Dictionary& Property::metaData() const {
}
void Property::onChange(std::function<void()> callback) {
_onChangeCallbacks.push_back(std::move(callback));
_onChangeCallback = std::move(callback);
}
@@ -139,9 +126,8 @@ void Property::setPropertyOwner(PropertyOwner* owner)
_owner = owner;
}
void Property::notifyListeners() {
for (std::function<void()>& f : _onChangeCallbacks)
f();
void Property::notifyListener() {
_onChangeCallback();
}
} // namespace properties