diff --git a/ChangeLog b/ChangeLog index dcc221d9..e0fd1576 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2020-09-26 Markus Gans * FData improvements + * The number of FObject children can now be limited with + setMaxChildren() + * FApplication can now have no more than one child widget 2020-09-25 Markus Gans * std::clog now streams everything to the FLogger object diff --git a/src/fapplication.cpp b/src/fapplication.cpp index 3d1bfd75..cc0a2c7c 100644 --- a/src/fapplication.cpp +++ b/src/fapplication.cpp @@ -388,6 +388,9 @@ void FApplication::processExternalUserEvent() //---------------------------------------------------------------------- void FApplication::init() { + // FApplication cannot have a second child widget + setMaxChildren(1); + // Initialize the last event time time_last_event.tv_sec = 0; time_last_event.tv_usec = 0; diff --git a/src/fobject.cpp b/src/fobject.cpp index f10a8adc..fffaac9f 100644 --- a/src/fobject.cpp +++ b/src/fobject.cpp @@ -48,7 +48,6 @@ FObject::FObject (FObject* parent) if ( parent ) // add object to parent { parent->addChild(this); - has_parent = true; } else { @@ -107,7 +106,7 @@ FObject* FObject::getChild (int index) const if ( ! hasChildren() ) return nullptr; - if ( index <= 0 || index > numOfChildren() ) + if ( index <= 0 || index > int(numOfChildren()) ) return nullptr; auto iter = begin(); @@ -148,6 +147,9 @@ void FObject::addChild (FObject* obj) if ( ! obj ) return; + if ( max_children != UNLIMITED && max_children <= numOfChildren() ) + throw std::length_error ("max. child objects reached"); + if ( obj->parent_obj ) obj->parent_obj->delChild(obj); diff --git a/src/ftermlinux.cpp b/src/ftermlinux.cpp index 5a775168..58478eee 100644 --- a/src/ftermlinux.cpp +++ b/src/ftermlinux.cpp @@ -698,7 +698,7 @@ int FTermLinux::setScreenFont ( const uChar fontdata[], uInt count } for (std::size_t i{0}; i < count; i++) - std::memcpy ( const_cast(font.data + bytes_per_line * 32 * i) + std::memcpy ( font.data + bytes_per_line * 32 * i , &fontdata[i * font.height] , font.height); } diff --git a/src/include/final/fobject.h b/src/include/final/fobject.h index e4456bb8..0a7217ae 100644 --- a/src/include/final/fobject.h +++ b/src/include/final/fobject.h @@ -78,6 +78,9 @@ class FObject typedef FObjectList::iterator iterator; typedef FObjectList::const_iterator const_iterator; + // Constants + static constexpr std::size_t UNLIMITED = static_cast(-1); + // Constructor explicit FObject (FObject* = nullptr); @@ -96,12 +99,16 @@ class FObject FObject* getChild (int) const; FObjectList& getChildren(); const FObjectList& getChildren() const; - int numOfChildren() const; + std::size_t getMaxChildren() const; + std::size_t numOfChildren() const; iterator begin(); iterator end(); const_iterator begin() const; const_iterator end() const; + // Mutator + void setMaxChildren (std::size_t); + // Inquiries bool hasParent() const; bool hasChildren() const; @@ -160,6 +167,7 @@ class FObject // Data members FObject* parent_obj{nullptr}; FObjectList children_list{}; // no children yet + std::size_t max_children{UNLIMITED}; bool has_parent{false}; bool widget_object{false}; static bool timer_modify_lock; @@ -184,8 +192,12 @@ inline const FObject::FObjectList& FObject::getChildren() const { return children_list; } //---------------------------------------------------------------------- -inline int FObject::numOfChildren() const -{ return int(children_list.size()); } +inline std::size_t FObject::getMaxChildren() const +{ return max_children; } + +//---------------------------------------------------------------------- +inline std::size_t FObject::numOfChildren() const +{ return children_list.size(); } //---------------------------------------------------------------------- inline FObject::iterator FObject::begin() @@ -203,6 +215,10 @@ inline FObject::const_iterator FObject::begin() const inline FObject::const_iterator FObject::end() const { return children_list.end(); } +//---------------------------------------------------------------------- +inline void FObject::setMaxChildren (std::size_t max) +{ max_children = max; } + //---------------------------------------------------------------------- inline bool FObject::hasParent() const { return has_parent; } diff --git a/test/fobject-test.cpp b/test/fobject-test.cpp index 60d48637..da3da803 100644 --- a/test/fobject-test.cpp +++ b/test/fobject-test.cpp @@ -376,38 +376,57 @@ void FObjectTest::addTest() { // obj -> child - auto obj = new finalcut::FObject(); + auto obj1 = new finalcut::FObject(); auto child = new finalcut::FObject(); - CPPUNIT_ASSERT ( ! obj->hasChildren() ); - CPPUNIT_ASSERT ( obj->numOfChildren() == 0 ); - CPPUNIT_ASSERT ( ! obj->isChild(child) ); + CPPUNIT_ASSERT ( ! obj1->hasChildren() ); + CPPUNIT_ASSERT ( obj1->numOfChildren() == 0 ); + CPPUNIT_ASSERT ( ! obj1->isChild(child) ); CPPUNIT_ASSERT ( ! child->hasParent() ); - CPPUNIT_ASSERT ( child->getParent() != obj ); + CPPUNIT_ASSERT ( child->getParent() != obj1 ); - obj->addChild(child); - CPPUNIT_ASSERT ( obj->hasChildren() ); - CPPUNIT_ASSERT ( obj->numOfChildren() == 1 ); - CPPUNIT_ASSERT ( obj->isChild(child) ); + obj1->addChild(child); + CPPUNIT_ASSERT ( obj1->hasChildren() ); + CPPUNIT_ASSERT ( obj1->numOfChildren() == 1 ); + CPPUNIT_ASSERT ( obj1->isChild(child) ); CPPUNIT_ASSERT ( child->hasParent() ); - CPPUNIT_ASSERT ( child->getParent() == obj ); + CPPUNIT_ASSERT ( child->getParent() == obj1 ); // Switch of the parent by a second addChild auto obj2 = new finalcut::FObject(); obj2->addChild(child); CPPUNIT_ASSERT ( child->hasParent() ); - CPPUNIT_ASSERT ( ! obj->hasChildren() ); - CPPUNIT_ASSERT ( obj->numOfChildren() == 0 ); - CPPUNIT_ASSERT ( ! obj->isChild(child) ); - CPPUNIT_ASSERT ( child->getParent() != obj ); + CPPUNIT_ASSERT ( ! obj1->hasChildren() ); + CPPUNIT_ASSERT ( obj1->numOfChildren() == 0 ); + CPPUNIT_ASSERT ( ! obj1->isChild(child) ); + CPPUNIT_ASSERT ( child->getParent() != obj1 ); CPPUNIT_ASSERT ( obj2->hasChildren() ); CPPUNIT_ASSERT ( obj2->numOfChildren() == 1 ); CPPUNIT_ASSERT ( obj2->isChild(child) ); CPPUNIT_ASSERT ( child->getParent() == obj2 ); - delete obj; // also deletes the child object + // Are the maximum number of child objects reached? + CPPUNIT_ASSERT ( obj2->getMaxChildren() == finalcut::FObject::UNLIMITED ); + obj2->setMaxChildren(1); + CPPUNIT_ASSERT ( obj2->hasChildren() ); + CPPUNIT_ASSERT ( obj2->getMaxChildren() == 1 ); + CPPUNIT_ASSERT ( obj2->numOfChildren() == 1 ); + auto child2 = new finalcut::FObject(); + CPPUNIT_ASSERT ( ! child2->hasParent() ); + CPPUNIT_ASSERT_THROW ( obj2->addChild(child2), std::length_error ); + CPPUNIT_ASSERT ( obj2->numOfChildren() == 1 ); + obj2->setMaxChildren(2); + CPPUNIT_ASSERT ( ! child2->hasParent() ); + CPPUNIT_ASSERT ( obj2->getMaxChildren() == 2 ); + obj2->addChild(child2); + CPPUNIT_ASSERT ( child2->hasParent() ); + CPPUNIT_ASSERT ( obj2->hasChildren() ); + CPPUNIT_ASSERT ( obj2->numOfChildren() == 2 ); + + delete obj1; + delete obj2; // also deletes the child object } //---------------------------------------------------------------------- @@ -456,7 +475,7 @@ void FObjectTest::iteratorTest() finalcut::FObject::const_iterator c_iter, c_last; c_iter = obj->begin(); c_last = obj->end(); - int i = 0; + std::size_t i = 0; while ( c_iter != c_last ) {