Object / Family

This class can be used to handle a list of children.

If your class cannot be a subclass of the Family class, you can still benefits from its features by simply using the Owner attribute. If the attribute is defined at creation time, each Child found in the taglist is added with the AddMember method to the Owner of the family rather then the family itself. The same happens during the Dispose method, where each member of the family is removed using the RemMember method invoked on the Owner of the family rather then the family itself.

The class implements the AddMember and RemMember virtual methods defined by the Object class to add and remove children. Because each children is referenced in a FFamilyNode, any kind of object can be added to a family. The class doesn't pay attention to objects kinds, its up the subclass or the owner of the family the filter children. If you need more than a FFamilyNode to store your children, you can define hooks to create and delete nodes.

Types

Attributes

Overrides

FFamilyNode -- (04.00)

typedef struct FeelinFamilyNode
{
    struct FeelinFamilyNode                    *Next;
    struct FeelinFamilyNode                    *Prev;
FObject Object; } FFamilyNode;

Each member of the family is referenced in a FFamilyNode linked to a private list.

CreateNodeHook -- (04.00) [I..], struct Hook *

The CreateNodeHook and DeleteNodeHook attributes allow the definition of Hooks, which are called to create and delete family's nodes. With this feature, one can add further information to the node. For example, the Group class use it to store various information about its children.

Example

F_HOOKM(APTR, code_family_create_node, FS_Family_CreateNode)
{
    FAreaPublic *apd = F_GET_AREA_PUBLIC(Msg->Object);
    FWidgetPublic *wpd = F_GET_WIDGET_PUBLIC(Msg->Object);
if ((apd != NULL) && (wpd != NULL)) { FWidgetNode *node = IFEELIN F_NewP(CUD->Pool, sizeof (FWidgetNode));
if (node != NULL) { node->AreaPublic = apd; node->WidgetPublic = wpd;
return node; } } else if (Msg->Object != NULL) { IFEELIN F_Log(FV_LOG_DEV, "%s{%08lx) is not a subclass of the Widget class", _object_classname(Msg->Object), Msg->Object); }
return NULL; }

DeleteNodeHook -- (04.00) [I..], struct Hook *

If you have defined a Hook to create nodes using the CreateNodeHook attribute, you might want to define another one to delete them.

Because nodes are disposed using the F_Dispose() function, you don't need to define a delete Hook if all you want to do is dispose nodes.

Family -- (02.00) [I.G], FObject

This attribute is designed to communicate with the Owner of the family. Classes with family capabilities are not always subclasses of the class, they may use it as a supporting tool. The attribute should also be used by classes to return a pointer to their Family object.

Example

The following example is only valid when the class is used as a support tool. You don't have to do all of this if your class is a subclass of the Family class.

If some children have failed i.e one Child is found NULL in the taglist, all children in the taglist are disposed by the class, and the family fails to create.

F_METHOD(FObject, mNew)
{
    ...
if (FamilyObject,
// Pointer to the Family object
FA_Family_Owner, Obj,
// Tag-items that comes with the New method
TAG_MORE, Msg)) { return Obj; } return NULL; }

When the family is disposed, all of its children are disposed too.

F_METHOD(uint32, mDispose)
{
    ...
F_DisposeObj(LOD->family); LOD->family = NULL;
return F_SUPERDO(); }

Save family's pointer in your Set method handler. This happens only if the creation of the family is ok.

Do not save family pointer during the New method !

F_METHOD(void,mSet)
{
    ...
while (F_DynamicNTI(&Tags, &item, Class) switch (item.ti_Tag) { ...
case FA_Family: LOD->family = (FObject)(item.ti_Data); break;
... } }
F_METHOD(void, mGet) { ...
while (F_DynamicNTI(&Tags, &item, Class)) switch (item.ti_Tag) { ... }
F_OBJDO(LOD->family);
F_SUPERDO(); }

Head -- (01.00) [..G], FFamilyNode *

A FFamilyNode holding the first member of the family, or NULL if the family is empty.

Owner -- (01.00) [I..], FObject

Defines the family's owner.

If your class cannot be a subclass of the Family class, you can still benefits from its features by simply using the Owner attribute. If the attribute is defined at creation time, each Child found in the taglist is added with the AddMember method to the Owner of the family rather then the family itself. The same happens during the Dispose method, where each member of the family is removed using the RemMember method invoked on the Owner of the family rather then the family itself.

F_METHOD(uint32, Group_New)
{
    struct LocalObjectData *LOD = F_LOD(Class, Obj);
...
if (FamilyObject,
FA_Family_Owner, Obj, FA_Family_CreateNodeHook, &CUD->create_family_node,
TAG_MORE,Msg, End) { return IFEELIN F_SuperDo(Class, Obj, Method,
FA_Widget_Chainable, FALSE,
TAG_MORE, Msg); }
... }
F_METHOD(uint32, Group_Set) { struct LocalObjectData *LOD = F_LOD(Class, Obj); struct TagItem *Tags = Msg, item;
while (IFEELIN F_DynamicNTI(&Tags, &item, Class)) switch (item.ti_Tag) { case FA_Family: { LOD->family = (FObject) item.ti_Data; } break;
... }
return F_SUPERDO(); }
F_METHODM(bool32, Group_AddMember, FS_AddMember) { struct LocalObjectData *LOD = F_LOD(Class, Obj);
FWidgetNode *node = (FWidgetNode *) F_OBJDO(LOD->family);
if (node == NULL) { return FALSE; }
LOD->members++;
...
return TRUE; }
F_METHODM(uint32, Group_RemMember, FS_RemMember) { struct LocalObjectData *LOD = F_LOD(Class, Obj);
uint32 rc;
if (Msg->Member == NULL) { return TRUE; }
...
rc = F_OBJDO(LOD->family);
if (rc != FALSE) { LOD->members--; }
return rc; }

Tail -- (01.00) [..G], FFamilyNode *

A FFamilyNode holding the last member of the family, or NULL if the family is empty.

AddMember

[method override]

Adds an orphan to the family.

Before actually adding the orphan, the method checks if the orphan is not already a member, in which case a message with the FV_LOG_DEV level is logged and the method returns with the error value FALSE. Otherwise, the Connect method is invoked on the orphan with the family (or its owner, if any) as argument. If the method result is different than FALSE, the orphan becomes a member.

See also

New

[method override]

For each Child found in the initial taglist, the family (or its Owner, if any) is invoked with the AddMember method with the Child as Orphan and FV_AddMember_Tail as Position.

If an object is NULL (because of a creation failure...) or if the AddMember method returns FALSE, each member of the family is removed with the RemMember method. The taglist is then read again and each Child is disposed with the F_DisposeObj() function.

RemMember

[method override]

Remove a member from a family.

Before actually removing the member, the method checks if it's really part of the family, in which case it's disconnected from the family using the method Disconnect method, and removed. Otherwise, an error message is logged with the FV_LOG_DEV level.

Result

TRUE if the member was successfully removed. FALSE otherwise.

Development