Managed Properties

OpenTwin provides a convenience layer to ease the property handling. When developing a library, application or service that does not require frontend functionallity the OTGui class Managed Property Object provides a simple interface to add properties that will automatically be concidered for serialization.

Frontend components that include the OTWidgets library can use the Managed Property Widget Object class to enable the use of multiple property visualization related property linking wrappers.

Property Management structure

../_images/managed_properties_class.svg

Property Creation

Adding properties to a class requires a OTGui Property Manager object. The manager provides the setter and getter methods for all supported properties.

Property Callbacks

When creating a property a callback function for the read and one for the write access to the property can be added. This callback methods will be called before a property read operation and after a property write operation. By using the callback methods automatic data dependent updates can be triggered.

Tree Entity Name Example

The following example will demonstrate how to create a string property and synchronize it with a tree item.

Convenience macros provided in the OTGui/ManagedPropertyRegistrarBase.h file will be used in this example.

The OT_PROPERTY_STRING_CALL macro from the Managed Property Registrar Base is used the generate the property. A setter and getter method in the following syntax will be gerated:

// Setter
//
// Syntax:
// void set<PropertyObjectName>(<SetterArgumentType> _value);
//
// Example with:
//     - Property Object Name: TreeEntityName
//     - Property Type: String
void setTreeEntityName(const std::String& _value);

// Setter
//
// Syntax:
// GetterArgumentType get<PropertyObjectName>(void) const;
//
// Example with:
//     - Property Object Name: TreeEntityName
//     - Property Type: String
const std::string& getTreeEntityName(void) const;

A registrar to initialize the property and pass the optional read and write callback notifier will be generated aswell. This registrar will create a Managed Property Registrar Base In the code example a setter notifier is passed to notify the object whenever the property value has changed.

Notifier syntax:

// Setter
// is called after the write operation is completed.
// void lambda(const ot::Property<Type>* _property);
// e.g.
void lambda(const ot::PropertyBool* _property);

// Getter
// is called before the read operation starts.
// void lambda(const ot::Property<Type>* _property);
// e.g.
void lambda(const std::string& _propertyGroup, const std::string& _propertyName);

The property itself can be accessed at any time after object creation from the objects Property Manager. The property in the code example can be accessed via the property name Entity Name from the general group in the Property Manager. This allows the property to be retreived and modified (e.g. change property flags, limits, …).

Code
// OpenTwin header
#include "OTWidgets/TreeWidgetItem.h"
#include "OTWidgets/ManagedWidgetPropertyObject.h"

class TreeEntity : ot::TreeWidgetItem, public ot::ManagedWidgetPropertyObject {
public:
        OT_PROPERTY_STRING_CALL(
        TreeEntityName,                       // Object name
        "Entity Name",                        // Property name.
         ,                                    // No read callback
        [=](const ot::PropertyString* _str) { // Write callback
            // Argument type is PropertyString since a string
            // property was created. PropertyBool for bool and so on.
            // Notify this object about the name change.
            this->treeEntityNameHasChanged(_str->getValue());
        },
        "New Entity"                          // Initial value
    );

protected:
    // Will be called every time the entity was written.
    // Inheriting classes could react to name chanes by overriding.
    virtual void treeEntityNameHasChanged(const std::string& _newName) {
        // Handle the name changes.
        // For example:

        // Ensure name is valid
        if (!this->isNameValid(_newName)) {
            // Handle invalid name
        }
        // Update tree item text if needed.
        const QString txt = QString::fromStdString(_newName);
        if (txt != this->text(0)) {
            this->setText(0, txt);
        }
    };

    // Example interface to validate an entity name.
    virtual bool isNameValid(const std::string& _name) const = 0;


};

Property Linking

Libraries and applications that use the OTWidgets library can use the frontend property management to enable different kinds of property handling.

Editing in Property Grid

Property visualization in a property grid can be archieved by using the Property Manager Grid Link. The grid link can be set to a Widget Property Manager that is owned by a Managed Widget Property Object. All properties that were added to the objects Widget Property Manager will be visualized when calling the visualization method of the Property Manager Grid Link. Changes to the property by the property grid will update the property stored in the Widget Property Manager. Since the changes will be handled by the Widget Property Manager the use of the Property Manager Grid Link won’t affect any set callback methods for property read and write operations.

// OpenTwin header
#include "OTWidgets/TreeWidgetItem.h"
#include "OTWidgets/ManagedWidgetPropertyObject.h"

class TreeEntity : ot::TreeWidgetItem, public ot::ManagedWidgetPropertyObject {
public:
    // Example property from Managed Property Example 1.
        OT_PROPERTY_STRING_CALL(TreeEntityName, "Entity Name", ,
        [=](const ot::PropertyString* _str)
        { this->treeEntityNameHasChanged(_str->getValue()); },
        "New Entity"
    );

protected:
    // Will be called every time the entity was written
    virtual void treeEntityNameHasChanged(const std::string& _newName) {};

private:
    // Grid link that is used.
    ot::PropertyManagerGridLink* m_gridLink;

public:
    // In the constructor add the grid link
    TreeEntity() {
        m_gridLink = new ot::PropertyManagerGridLink(this->getPropertyManager());
    }

    // Whenever the entity should be displayed in the property grid call this method.
    void visualizeAtGrid(ot::PropertyGrid* _grid) {
        m_gridLink->visualizeAtGrid(_grid);
    }

    // When the property is not edited in the property grid call this method.
    // This should be called before another entity will visualize itself at the same grid.
    void forgetPropertyGrid(void) {
        m_gridLink->forgetPropertyGrid(void);
    }

    // Instead of the the methods "visualizeAtGrid" and "forgetPropertyGrid"
    // a getter to get the grid link could be added so the grid link handling
    // will take place elsewhere.
};