diff --git a/src/App/Property.cpp b/src/App/Property.cpp index 4bd598a99a..1764e9778c 100644 --- a/src/App/Property.cpp +++ b/src/App/Property.cpp @@ -159,9 +159,9 @@ const char* Property::getDocumentation() const return father->getPropertyDocumentation(this); } -void Property::setContainer(PropertyContainer* Father) +void Property::setContainer(PropertyContainer* father) { - father = Father; + this->father = father; } void Property::setPathValue(const ObjectIdentifier& path, const boost::any& value) diff --git a/src/App/Property.h b/src/App/Property.h index eaaff9cd9f..63b78106ff 100644 --- a/src/App/Property.h +++ b/src/App/Property.h @@ -45,16 +45,17 @@ class PropertyContainer; class ObjectIdentifier; /** - * @brief %Base class of all properties + * @brief %Base class of all properties. * @ingroup PropertyFramework * - * @details This is the father of all properties. Properties are objects which that used - * in the document tree to parameterize e.g. features and their graphical output. - * They are also used to gain access from the scripting facility. - * @par - * This abstract base class defines all methods shared by all - * possible properties. It is also possible to define user properties - * and use them in the framework. + * This is the base class of all properties. Properties are objects that are + * used in documents or document objects that maintain all kinds of information + * about the document or document objects. Examples are properties of + * features, such as the length, but properties can also keep track of shapes. + * They are also used to gain access to the document object in the console. + * + * This abstract base class defines all methods shared by all possible + * properties. It is also possible to create user-defined properties. * * For a more high-level overview see topic @ref PropertyFramework "Property Framework". */ @@ -142,223 +143,448 @@ public: User4 = 31 }; + /// Construct a property. Property(); + /// Destruct a property. ~Property() override; - /// For safe deleting of a dynamic property + /** + * @brief Safely delete a dynamic property. + * + * @param[inout] p The property to delete. + */ static void destroy(Property* p); - /** 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? - * This method is defined in Base::Persistence - * @see Base::Persistence - */ unsigned int getMemSize() const override { // you have to implement this method in all property classes! return sizeof(father) + sizeof(StatusBits); } - /** Get the name of this property in the belonging container + /** + * @brief Get the name of this property in the belonging container. + * * With \ref hasName() it can be checked beforehand if a valid name is set. - * @note If no name is set this function returns an empty string, i.e. "". + * + * @return The name of the property or if no name is set, an empty string. */ const char* getName() const; - /** Check if the property has a name set. + + /** + * @brief Check whether the property has a name set. + * * If no name is set then \ref getName() will return an empty string + * + * @return True if a name is set, false otherwise. */ bool hasName() const; - /** Check if the passed name is valid. - * If \a name is null or an empty string it's considered invalid, - * and valid otherwise. + + /** + * @brief Check whether the passed name is valid. + * + * If a name is null or an empty string it is considered invalid, and valid + * otherwise. + * + * @param[in] name The name to check. + * @return True if the name is valid, false otherwise. */ static bool isValidName(const char* name); + /** + * @brief Get the name of the property and its container. + * + * The container name is separated from the property name by a dot. If the + * property has no name, then a question mark is returned. If the + * container has no name, then a question mark is returned for the + * container named. + */ std::string getFullName() const; - /// Get the class name of the associated property editor item + /** + * @brief Get the class name of the associated property editor item. + * + * @return The class name of the property editor item or an empty string if + * not defined. + */ virtual const char* getEditorName() const { return ""; } - /// Get the type of the property in the container + /** + * @brief Get the type of the property in the container. + * + * The type is expressed as a bitmask of enum PropertyType. + * + * @return The type of the property as a bitmask of enum PropertyType. + */ short getType() const; - /// Get the group of this property + /** + * @brief Get the group of this property. + * + * @return The group of the property or a nullptr if not defined. + */ const char* getGroup() const; - /// Get the documentation of this property + /** + * @brief Get the documentation of this property. + * + * @return The documentation of the property or a nullptr if not defined. + */ const char* getDocumentation() const; - /// Is called by the framework to set the father (container) - void setContainer(PropertyContainer* Father); + /** + * @brief Set the container of this property. + * + * This is called by the framework to set the father (container). + * + * @param[in] father The container of this property. + */ + void setContainer(PropertyContainer* father); - /// Get a pointer to the PropertyContainer derived class the property belongs to + /** + * @brief Get the container of this property. + * + * Get a pointer to the PropertyContainer derived class to which the + * property belongs. + * + * @return A pointer to the PropertyContainer derived class. + */ PropertyContainer* getContainer() const { return father; } - /// Set value of property + /** + * @brief Set the value of the property identified by the path. + * + * This function sets the value of the property identified by the path. It + * is meant to be overridden for subclasses in which the `path` is + * typically ignored. The default implementation redirects setting a value + * to the the `path` ObjectIdentifier. + * + * @param[in] path The path to the property. + * @param[in] value The value to set. + */ virtual void setPathValue(const App::ObjectIdentifier& path, const boost::any& value); - /// Get value of property + /** + * @brief Get the value of the property identified by the path. + * + * This function gets the value of the property identified by the path. It + * is meant to be overridden for subclasses in which the `path` is + * typically ignored. The default implementation makes use of the `path` + * ObjectIdentifier to get the value of the property. + * + * @param[in] path The path to the property. + * @return The value of the property. + */ virtual const boost::any getPathValue(const App::ObjectIdentifier& path) const; - /// Get Python value of property - virtual bool getPyPathValue(const App::ObjectIdentifier&, Py::Object&) const + /** + * @brief Get the Python value of the property identified by the path. + * + * This function gets the Python value of the property identified by the + * path. It is meant to be overridden for subclasses. This default + * implementation return `false`. + * + * @param[in] path The path to the property. + * @param[out] value The Python value of the property. + * @return True if the value was successfully retrieved, false otherwise. + */ + virtual bool getPyPathValue(const App::ObjectIdentifier& path, Py::Object& value) const { return false; } - /// Convert p to a canonical representation of it - virtual App::ObjectIdentifier canonicalPath(const App::ObjectIdentifier& p) const; + /** + * @brief Convert an object identifier to a canonical representation. + * + * Convert an object identifier to a canonical representation of the object + * identifier. + * + * @param[in] path The object identifier to convert. + * @return An object identifier that represents the canonical path. + */ + virtual App::ObjectIdentifier canonicalPath(const App::ObjectIdentifier& path) const; - /// Get valid paths for this property; used by auto completer + /** + * @brief Get valid paths for this property. + * + * This function is used by auto completer. + * + * @param[out] paths A vector of object identifiers with the valid paths + * for this property. + */ virtual void getPaths(std::vector& paths) const; - /** Called at the beginning of Document::afterRestore() + /** @brief Callback for after document restore. * - * This function is called without dependency sorting, because some - * types of link property can only reconstructs the linking information - * inside this function. + * This function is called at the beginning of Document::afterRestore(). + * It is called without dependency sorting, because some link property + * types can only reconstruct the linking information inside this function. + * Typical use cases include: * - * One example use case of this function is PropertyLinkSub that uses - * afterRestore() to parse and restore subname references, which may - * contain sub-object reference from external document, and there will be - * special mapping required during object import. + * - **PropertyLinkSub** + * Parses and restores sub-object references (including + * those that point into external documents), applying any necessary + * name-mapping during import. * - * Another example is PropertyExpressionEngine which only parse the - * restored expression in afterRestore(). The reason, in addition to - * subname mapping like PropertyLinkSub, is that it can handle document - * name adjustment as well. It internally relies on PropertyXLink to store - * the external document path for external linking. When the external - * document is restored, its internal name may change due to name conflict - * with existing documents. PropertyExpressionEngine can now auto adjust - * external references without any problem. + * - **PropertyExpressionEngine** + * Re-parses expressions after restore so that it can handle document + * name adjustment. It internally relies on PropertyXLink to store the + * external document path for external linking. When the external + * document is restored, its internal name may change due to name + * conflict with existing documents. With this callback it can now auto + * adjust external references without any problem. */ - virtual void afterRestore() - {} + virtual void afterRestore() {} - /** Called before calling DocumentObject::onDocumentRestored() + /** @brief Callback for after document restore. * - * This function is called after finished calling Property::afterRestore() - * of all properties of objects. By then, the object dependency information - * is assumed ready. So, unlike Property::afterRestore(), this function is - * called on objects with dependency order. + * This function is called by Document::restore() after finished calling + * Property::afterRestore() on all properties of objects. By then, the + * object dependency information is assumed ready. So, unlike + * Property::afterRestore(), this function is called on objects with + * dependency order. + * + * It is called before calling DocumentObject::onDocumentRestored(). */ - virtual void onContainerRestored() - {} + virtual void onContainerRestored() {} - /** Property status handling + /** @name Property status handling + * @{ */ - //@{ - /// Set the property touched + + /// Set the property touched. void touch(); - /// Test if this property is touched + + /** + * @brief Test if this property is touched. + * + * @return True if the property is touched, false otherwise. + */ inline bool isTouched() const { return StatusBits.test(Touched); } - /// Reset this property touched + + /// Reset this property as being touched. inline void purgeTouched() { StatusBits.reset(Touched); } - /// return the status bits + + /** + * @brief Get the status of this property. + * + * @return The status of the property as a bitmask of enum Status. + */ inline unsigned long getStatus() const { return StatusBits.to_ulong(); } + + /** + * @brief Test if the property has a specific status. + * + * @param[in] pos The status to test. + * @return True if the property has the specified status, false otherwise. + */ inline bool testStatus(Status pos) const { return StatusBits.test(static_cast(pos)); } + + /** + * @brief Set the status of the property. + * + * Sets the status of the property given a specific position. + * + * @param[in] pos The status to set. + * @param[in] on The value to set the status to. + */ void setStatus(Status pos, bool on); + + /** + * @brief Set the status of the property. + * + * Sets the status of the property given a specific bitmask. + * + * @param[in] status The status to set as a bitmask. + */ void setStatusValue(unsigned long status); - /// Sets property editable/grayed out in property editor + + /** + * @brief Set the property read only. + * + * This sets property editable/grayed out in property editor. + * @param[in] readOnly True to set the property as read-only, false otherwise. + */ void setReadOnly(bool readOnly); + + /** + * @brief Check if the property is read-only. + * + * @return True if the property is read-only, false otherwise. + */ inline bool isReadOnly() const { return testStatus(App::Property::ReadOnly); } - /// Sets precision of properties using floating point - /// numbers to single, the default is double. + + /** + * @brief Set the precision of floating point properties. + * + * This sets the precision of properties using floating point + * numbers to single precision. The default is double precision. + * + * @param[in] single True to set single precision, false for double precision. + */ void setSinglePrecision(bool single) { setStatus(App::Property::Single, single); } - /// Gets precision of properties using floating point numbers + + /** + * @brief Gets precision of floating point properties. + * + * @return True if single precision is set, false for double precision. + */ inline bool isSinglePrecision() const { return testStatus(App::Property::Single); } - //@} + /// @} - /// Returns a new copy of the property (mainly for Undo/Redo and transactions) + /** + * @brief Returns a new copy of the property. + * + * The copy is mainly used for Undo/Redo and transactions. + * + * @return A new copy of the property. + */ virtual Property* Copy() const = 0; - /// Paste the value from the property (mainly for Undo/Redo and transactions) + + /** + * @brief Pastes the value from a property. + * + * This function pastes the value from a property into this property. It + * is mainly used for Undo/Redo and transactions. + * + * @param[in] from The property to paste from. + */ virtual void Paste(const Property& from) = 0; - /// Called when a child property has changed value - virtual void hasSetChildValue(Property&) - {} - /// Called before a child property changing value - virtual void aboutToSetChildValue(Property&) - {} + /** + * @brief Callback for when a child property has changed value. + * + * @param[in] prop The child property that has changed value. + */ + virtual void hasSetChildValue(Property&) {} - /// Compare if this property has the same content as the given one + /** + * @brief Callback for when a child property is about to change value. + * + * It is called before a child property changes value. + * + *@param[in] prop The child property that is about to change value. + */ + virtual void aboutToSetChildValue(Property&) {} + + /** + * @brief Compare if this property has the same content as the given one. + * + * @param[in] other The property to compare with. + * @return True if the properties are the same, false otherwise. + */ virtual bool isSame(const Property& other) const; - /** Return a unique ID for the property + /** + * @brief Return a unique ID for the property. * * The ID of a property is generated from a monotonically increasing - * internal counter. The intention of the ID is to be used as a key for - * mapping, instead of using the raw pointer. Because, it is possible for - * the runtime memory allocator to reuse just deleted memory, which will - * cause hard to debug problem if use pointer as key. + * internal counter. The intention of the ID is to be used as a key for + * mapping, instead of using the raw pointer. This prevent the runtime + * allocator to reuse just deleted memory as a result of using raw + * pointers, something that is challenging to debug. */ int64_t getID() const { return _id; } - virtual void beforeSave() const - {} + /** + * @brief Callback for when the property is about to be saved. + * + * This method is called before saving the property. It can be overridden + * by subclasses to implement custom behavior before saving. + * + * @see PropertyContainer::beforeSave() + */ + virtual void beforeSave() const {} friend class PropertyContainer; friend struct PropertyData; friend class DynamicProperty; protected: - /** Status bits of the property + /** @brief %Status bits of the property. + * * The first 8 bits are used for the base system the rest can be used in * descendent classes to mark special statuses on the objects. * The bits and their meaning are listed below: - * 0 - object is marked as 'touched' - * 1 - object is marked as 'immutable' - * 2 - object is marked as 'read-only' (for property editor) - * 3 - object is marked as 'hidden' (for property editor) + * - **0**: object is marked as 'touched' + * - **1**: object is marked as 'immutable' + * - **2**: object is marked as 'read-only' (for property editor) + * - **3**: object is marked as 'hidden' (for property editor) + * + * @see Property::Status that defines the position of the status bits. */ std::bitset<32> StatusBits; protected: - /// Gets called by all setValue() methods after the value has changed + + /** + * @brief Callback for when the value of the property has changed. + * + * This is called by all setValue() methods after the value has changed. + */ virtual void hasSetValue(); - /// Gets called by all setValue() methods before the value has changed + + /** + * @brief Callback for when the value of the property is about to change. + * + * This is called by all setValue() methods before the value has changed. + */ virtual void aboutToSetValue(); - /// Verify a path for the current property - virtual void verifyPath(const App::ObjectIdentifier& p) const; + /** + * @brief Verify a path for the current property. + * + * @param[in] path The path to verify. + */ + virtual void verifyPath(const App::ObjectIdentifier& path) const; - /// Return a file name suitable for saving this property - std::string getFileName(const char* postfix = 0, const char* prefix = 0) const; + /** + * @brief Return a file name suitable for saving this property. + * + * @param[in] postfix The postfix to append to the file name. + * @param[in] prefix The prefix to prepend to the file name. + * @return The file name for saving the property. + */ + std::string getFileName(const char* postfix = nullptr, const char* prefix = nullptr) const; public: - // forbidden + /** + * @brief The copy constructor is deleted to prevent copying. + */ Property(const Property&) = delete; + + /** + * @brief The assignment operator is deleted to prevent assignment. + */ Property& operator=(const Property&) = delete; private: @@ -371,37 +597,42 @@ private: int64_t _id; public: + /// Signal emitted when the property value has changed. boost::signals2::signal signalChanged; }; -/** A template class that is used to inhibit multiple nested calls to aboutToSetValue/hasSetValue - * for properties. +/** + * @brief A template class to inhibit nested calls for setting values. * * A template class that is used to inhibit multiple nested calls to * aboutToSetValue/hasSetValue for properties, and only invoke it on change and - * last time it is needed. This is useful in cases where you want to change multiple - * values in a property "atomically", using possibly multiple primitive functions - * that normally would trigger aboutToSetValue/hasSetValue calls on their own. + * on the last time it is needed. This is useful in cases where you want to + * change multiple values in a property "atomically", using possibly multiple + * primitive functions that normally would trigger aboutToSetValue/hasSetValue + * calls on their own. * - * To use, inherit privately from the AtomicPropertyChangeInterface class, using - * your class name as the template argument. In all cases where you normally would - * call aboutToSetValue/hasSetValue before and after a change, create an - * AtomicPropertyChange object. The default constructor assume you are about to - * change the property and will call property's aboutToSetValue() if the - * property has not been marked as changed before by any other - * AtomicPropertyChange instances in current call stack. You can pass 'false' - * as the a second argument to the constructor, and manually call - * AtomicPropertyChange::aboutToChange() before actual change, this enables you - * to prevent unnecessary property copy for undo/redo where there is actual - * changes. AtomicPropertyChange will guaranetee calling hasSetValue() when the - * last instance in the current call stack is destroyed. + * To use, inherit privately from the AtomicPropertyChangeInterface class, + * using your class name as the template argument. In all cases in which you + * would normally call aboutToSetValue/hasSetValue before and after a change, + * create an AtomicPropertyChange object. + * + * The default constructor assumes you are about to change the property and + * will call property's Property::aboutToSetValue() if the property has not + * been marked as changed before by any other AtomicPropertyChange instances in + * current call stack. You can pass `false` as the a second argument to the + * constructor, and manually call AtomicPropertyChange::aboutToChange() before + * actual change, which enables you to prevent unnecessary property copy for + * undo/redo when there are actual changes. AtomicPropertyChange will + * guarantee calling Property::hasSetValue() when the last instance in the + * current call stack is destroyed. * * One thing to take note is that, because C++ does not allow throwing * exception in destructor, any exception thrown when calling property's - * hasSetValue() will be caught and swallowed. To allow exception propagation, - * you can manually call AtomicPropertyChange::tryInvoke(). If the condition is - * satisfied, it will call hasSetValue() that allows exception propagation. + * Property::hasSetValue() will be caught and swallowed. To allow exception + * propagation, you can manually call AtomicPropertyChange::tryInvoke(). If the + * condition is satisfied, it will call Property::hasSetValue() that allows + * exception propagation. */ template class AtomicPropertyChangeInterface @@ -410,10 +641,24 @@ protected: AtomicPropertyChangeInterface() = default; public: + /** + * @brief A class that captures property changes atomically. + * + * This class is used to capture multiple property changes atomically. It + * automatically marks the property as changed and calls the + * Property::aboutToSetValue() method when the object is constructed. It + * also automatically calls the Property::hasSetValue() method when the + * object is destructed, if the property has been marked as changed. This + * ensures that Property::aboutToSetValue() and Property::hasSetValue() are + * only called once for multiple property changes. + * + * @see AtomicPropertyChangeInterface + */ class AtomicPropertyChange { public: - /** Constructor + /** + * @brief Construct an AtomicPropertyChange object. * * @param prop: the property * @param markChange: If true, marks the property as changed if it @@ -429,7 +674,8 @@ public: } } - /** Mark the property as changed + /** + * @brief Mark the property as changed * * It will mark the property as changed only if it has been marked * before, and only then will it call the property's aboutToSetValue(). @@ -442,7 +688,8 @@ public: } } - /** Destructor + /** + * @brief Destruct an AtomicPropertyChange object. * * If the property is marked as changed, and this is the last instance * of the class in current call stack, it will call property's @@ -471,7 +718,8 @@ public: } } - /** Check and invoke property's hasSetValue() + /** + * @brief Check and invoke property's hasSetValue(). * * Check if this is the last instance and the property has been marked * as changed. If so, invoke property's hasSetValue(). @@ -494,34 +742,67 @@ public: }; protected: - int signalCounter {0}; /**< Counter for invoking transaction start/stop */ + /// Counter for invoking transaction start/stop. + int signalCounter {0}; + /// Flag to indicate if the property has been changed. bool hasChanged {false}; }; -/** Helper class to construct list like properties +/** + * @brief Base class for list-like properties. * * This class is not derived from Property so that we can have more that one - * base class for list like properties, e.g. see PropertyList, and - * PropertyLinkListBase + * base class for list-like properties. + * + * @see PropertyList + * @see PropertyLinkListBase */ class AppExport PropertyListsBase { public: + + /** + * @brief Set the size of the property list. + * + *@param newSize The new size of the property list. + */ virtual void setSize(int newSize) = 0; + + /** + * @brief Get the size of the property list. + * + * @return The size of the property list. + */ virtual int getSize() const = 0; + /** + * @brief Get the list of touched elements. + * + * @return A set of touched elements. + */ const std::set& getTouchList() const { return _touchList; } + /// Clear the list of touched elements. void clearTouchList() { _touchList.clear(); } protected: + /** + * @brief Set the values of the property list with Python values. + * + * This method is used to set the values of the property list with values + * represented as Python objects. If `indices` is empty, all values are + * set. + * + * @param[in] vals The new values for the property list as Python values. + * @param[in] indices The indices of the values to set. + */ virtual void setPyValues(const std::vector& vals, const std::vector& indices) { (void)vals; @@ -529,70 +810,154 @@ protected: throw Base::NotImplementedError("not implemented"); } - void _setPyObject(PyObject*); + /** + * @brief Set the values of the property list with a Python object. + * + * The Python object is expected to be a dictionary or something that looks + * like a sequence of values, for example a list or tuple, or an iterable. + * + * @param[in] pyObj The Python object to set the values from. + */ + void _setPyObject(PyObject* pyObj); protected: + /// The list of touched elements. std::set _touchList; }; -/** Base class of all property lists. - * The PropertyLists class is the base class for properties which can contain - * multiple values, not only a single value. - * All property types which may contain more than one value inherits this class. +/** + * @brief The base class of all property lists. + * + * The PropertyLists class is the base class for properties that can contain + * multiple values, not only a single value. All property types that may + * contain more than one value inherit from this class. */ class AppExport PropertyLists: public Property, public PropertyListsBase - { TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: + /** + * @brief Set the values of the property list with a Python object. + * + * The Python object is expected to be a dictionary or something that looks + * like a sequence of values, for example a list or tuple, or an iterable. + * + * @param[in] obj The Python object to set the values from. + */ void setPyObject(PyObject* obj) override { _setPyObject(obj); } - // if the order of the elements in the list relevant? - // if yes, certain operations, like restoring must make sure that the - // order is kept despite errors. + /** + * @brief Set the order of the elements to be relevant. + * + * If the order of the elements in the list is relevant, certain + * operations, such as restoring, must ensure that the order is kept + * despite potential errors. + * + * @param[in] on True to set the order as relevant, false otherwise. + */ inline void setOrderRelevant(bool on) { this->setStatus(Status::Ordered, on); } + + /** + * @brief Check if the order of the elements is relevant. + * + * @return True if the order is relevant, false otherwise. + */ inline bool isOrderRelevant() const { return this->testStatus(Status::Ordered); } }; -/** Helper class to implement PropertyLists */ +/** + * @brief Helper class to implement PropertyLists. + * + * This class combines property storage (via a standard container ListT) with + * the change-notification interface in AtomicPropertyChangeInterface. + * + * @tparam T The type of individual property values. + * @tparam ListT The container type for holding values (defaults to @c std::vector). + * @tparam ParentT The base class providing core property-list behavior + * (defaults to PropertyLists). + */ template, class ParentT = PropertyLists> class PropertyListsT: public ParentT, public AtomicPropertyChangeInterface> { public: + /// Alias for a reference to a const element in the list. using const_reference = typename ListT::const_reference; + + /// The underlying container type. using list_type = ListT; + + /// The base class type. using parent_type = ParentT; + + /** + * @brief Helper type for performing atomic property changes. + * + * This is defined by the AtomicPropertyChangeInterface class. + */ using atomic_change = typename AtomicPropertyChangeInterface< PropertyListsT>::AtomicPropertyChange; + /** + * @brief Grant atomic_change access to private internals. + * + * Allows atomic_change operations to modify the internal state directly. + */ friend atomic_change; + /** + * @brief Resize the property list, filling new slots with a given value. + * + * @param[in] newSize The desired total number of elements. + * @param[in] def The single element value to use for all newly-added slots. + */ virtual void setSize(int newSize, const_reference def) { _lValueList.resize(newSize, def); } + /** + * @brief Resize the property list, value-initializing any new elements. + * + * Adjusts the container to hold exactly @p newSize elements. + * - If @p newSize is less than the current size, the container is shrunk. + * - If @p newSize is greater, new elements are default-constructed + * + * @param[in] newSize The desired total number of elements. + */ void setSize(int newSize) override { _lValueList.resize(newSize); } + /** + * @brief Get the size of the list. + * + * @return The size of the list. + */ int getSize() const override { return static_cast(_lValueList.size()); } + /** + * @brief Set a property list to a given value. + * + * Clears any existing values and makes the list contain exactly one + * element initialized to @p value. + * + * @param[in] value The value to assign. + */ void setValue(const_reference value) { ListT vals; @@ -600,6 +965,14 @@ public: setValues(vals); } + /** + * @brief Replace the entire list of values. + * + * Clears and assigns @p newValues to the internal list, notifying + * observers of the change atomically. + * + * @param[in] newValues The new container of values (defaults to empty list). + */ virtual void setValues(const ListT& newValues = ListT()) { atomic_change guard(*this); @@ -608,27 +981,55 @@ public: guard.tryInvoke(); } + /** + * @brief Alias for setValues(). + * + * @param[in] newValues The new container of values (defaults to empty list). + */ void setValue(const ListT& newValues = ListT()) { setValues(newValues); } + /** + * @brief Retrieve the underlying list of values. + * + * @return A const reference to the internal container. + */ const ListT& getValues() const { return _lValueList; } - // alias to getValues + /** + * @brief Alias for getValues(). + * + * @return A const reference to the internal container. + */ const ListT& getValue() const { return getValues(); } + /** + * @brief Retrieve an element by index. + * + * @param[in] idx The index of the element to retrieve. + * @return The element at position @p idx. + * + * @note No bounds-check is performed. + */ const_reference operator[](int idx) const { return _lValueList[idx]; } + /** + * @brief Compare two Property instances for equivalence. + * + * @param[in] other The other Property to compare against. + * @return True if both are of the same type and contain equal values. + */ bool isSame(const Property& other) const override { if (&other == this) { @@ -638,6 +1039,14 @@ public: && this->getValue() == static_cast(&other)->getValue(); } + /** + * @brief Set the property value from a Python object. + * + * Attempts to extract a value via getPyValue() and assign it; + * on failure, falls back to the ParentT implementation. + * + * @param[in] value A PyObject pointer representing the new value. + */ void setPyObject(PyObject* value) override { try { @@ -649,6 +1058,17 @@ public: parent_type::setPyObject(value); } + /** + * @brief Set a value at a specific index, growing the list if needed. + * + * If @p index is -1 or equal to the current size, the list grows by one. + * Otherwise, the existing element at @p index is replaced. + * Observers are notified of the change atomically. + * + * @param[in] index The position at which to set @p value (-1 for append). + * @param[in] value The new element value. + * @throw Base::RuntimeError if @p index is out of bounds (< -1 or > size). + */ virtual void set1Value(int index, const_reference value) { int size = getSize(); @@ -690,6 +1110,13 @@ protected: guard.tryInvoke(); } + /** + * @brief Convert a Python object to a value of type T. + * + * @param[in] item The Python object to convert. + * + * @return The converted value of type T. + */ virtual T getPyValue(PyObject* item) const = 0; protected: