Understanding Applicative Container |
| Technical Article |
AbstractAny feature which is instantiated, is located within a container. When this persistent structure is created by the modeler's engine, it is called "container", when it is created by an application, DS or CAA, it is named "applicative container". The goal of this article is to give you all necessary information to choose the right container to instantiate your CAA feature, and how to create, use and manage an applicative container. |
A Container is an Object Modeler component which has a late type. Generally the contained elements are created by a factory, an interface implemented by the container. Two example: CATIGSMFactory, implemented by CATPrtCont, a CATPart container, and CATGeoFactory , implemented by CGMGeom, a CATPart container too.
A container can contain features or CATBaseUnknown objects. The CGMGeom container contains geometrical objects which are not features. Nevertheless you will see in the Creation section, that by CAA you could only create container for features.
There are two kinds of containers:
There are containers managed by the Modeler:
- CATPart : three modeler containers : CATPrtCont, CGMGeom, CATMFBRP
- CATDrawing : one container . There is no direct access on it, you have only access to the root feature
- See your Modeler documentation for other cases.
These container are created by applications. These applications can be DS or CAA. An example of DS applicative containers are electrical containers. In the next sections you will have all the necessary information to create, use and manage correctly your own applicative container.
But the first question is when it is necessary to create an applicative container. It is purpose of the next section.
You have just finished designing your new CAA feature, now the question is where to store the new Startup instantiations. The rule is as follows:
If you are in the second and third situation, the whole article is for you, but in the first case, the Access by Name and Parsing the Contents sections can be nevertheless useful.
This section deals with the elementary functions: creating, retrieving and introspecting an applicative container. Nevertheless, the two sub-sections can be valid for DS containers too.
The only way to create an applicative container is the global function : CATCreateApplicativeContainer
HRESULT CATCreateApplicativeContainer(CATBaseUnknown ** oApplicativeContainer, CATDocument * iDocument, const CATIdent iContainerType, const IID& iInterfaceId, const CATIdent iContainerSuperType="", const CATUnicodeString& iIdentifier="");
Have a look to each argument:
| argument | meaning |
| oApplicativeContainer | It is the newly created container. It is a iInterfaceId
interface pointer. |
| iDocument | The document containing the new container. |
| iContainerType | It represents the late type of the container. You will implement
interfaces on this late type, like
CATInit, but also factories to create the elements for the
container. If you do not want specify a late type, use the " |
| iInterfaceId | The IID value of an interface implemented by the container. It can be CATBaseUnknown, CATIClientContainer, CATInit, or any other interface implemented by the container. These three are the main generic ones. |
| iContainerSuperType | An applicative container can only be a CATFeatCont or a container
deriving from CATFeatCont , so the possible values for iContainerSuperType
depends on the iContainerType value:
|
| iIdentifier | It represents the identifier name of the container, the name to be retrieved,
see the next section. BUT take note that it is
strongly recommended to use the same name as the late type value, that
is iIdentifier
is equal to iContainerType. This is mandatory for saving
your container in 3D XML file.
If Two containers of the same type can co-exist in the same stream, but their name must be different. |
Generally you create an applicative container like this:
...
CATBaseUnknown *pContainer = NULL ;
CATDocument *pDoc =... ;
::CATCreateApplicativeContainer(pContainer,pDoc,
"MyContainerType",
IID_CATBaseUnknown,"CATFeatCont");
...
A container, applicative or not, can be retrieved from a CATDocument using its identifier name. This value is the sixth argument of the CATCreateApplicativeContainer , or if no value, its late type, the second argument of the same method. For DS container, refer to the modeler documentation if container's named are exposed.
The global function CATGetApplicativeContainer retrieves a container by its name
HRESULT CATGetApplicativeContainer(CATBaseUnknown ** oApplicativeContainer, CATDocument* iDocument, const IID& iInterfaceId, const CATUnicodeString& iIdentifier);
The interface to use is CATIClientContainer. It is an interface
implemented by any CATFeatCont container. We have seen previously
that an applicative container can only contain features, so this interface is
available for your applicative container.
Its unique method is
ListMembers :
HRESULT ListMembers( const IID& iIID, const CATUnicodeString ClientID, CATListPtrCATBaseUnknown** oLst)const =0
This method retrieves within a container, all features implementing a given interface (IID). All the returned element can be used as IID interface pointer.
...
CATIClientContainer *pMyContainer = ....;
CATListPtrCATBaseUnknown * listfeatures = NULL ;
pMyContainer->ListMembers(IID_CATISpecObject,ClientIdValue, &listfeatures);
if (NULL != listfeatures )
{
...
CATISpecObject *pCurrentElement = (*listfeatures)[i];
...
}
One you have through with the list, do nor forget to release its elements, and delete it.
The last not explained argument is "ClientID". This mandatory argument is the key of a Startup catalog. It means that CATIClientContainer can only retrieve features whose you know the Startup catalog key.
By creating you own applicative container you benefit from all Feature modeler capabilities: persistency, introspection, sometimes automatic loading, and other facilities. But the modeler responsible of the CATDocument does not know the contents of your applicative containers, so it cannot expose the data as you would certainly like. That is the reason why, for some DS behavior (mostly interactive ones), which require the knowledge of the applicative container contents, the modeler delegates to a special object this introspection. This special object is a Manager of Providers. Each applicative container, which want to be invoked for a DS behavior, should be previously declared to this manager. Each object which gives the behavior of one applicative container for one behavior is named a "Provider".
These possibilities are valid for Product Modeler and Mechanical Modeler.
For other modelers, have a look to their CAA documentation.
To be usable, an applicative container must be first either loaded in session, or just created , and then to be activated. The activation consists in to "give the hand" to the container in order to operate some actions of initialization. It will be explained in details next.
The loading and activation steps is depending on the context:
AddExtension
method of CATIOsmExtendable create the container, it
will be automatically initialized after its creation,The activation is done through the Init method of the CATInit interface. This interface must be implemented on the late type of your applicative container, the second argument of the creation method.
This activation is done for each instance of applicative container. Consider this example:
![]() |
The two streams (document) contain each one an instance of the applicative container whose the late type is "Appl. Container 2". Within Stream A, the container contains 2 features, and within Stream B , three others. When the activation of those containers will be requested, the Init method of the CATInit interface will be called for each one.
The contents of this method generally contains these three steps, and in this order:
::SpecBindNativeFormat("iContainerType");where
iContainerTypeis the container type, see previous section.
If the first two can be useless, if you have no UI behaviors to implement, the last one is mandatory.
It depends on your applicative container contents. If the container contains a feature which is unique, and represents a root, this method can return it, otherwise the implementation can return NULL.
A container is normally a persistent structure, but you can have a volatile container. It means that this specific container will not be saved when the stream is stored. It is the way to create "temporary object" while benefiting from Feature modeler capabilities.
Imagine you want to handle temporary objects during a session. It is possible using Object Modeler, but you will not take advantage of the feature modeler capabilities like undo/ redo functionalities.
A solution is to create an applicative container like it is described just above, but moreover to declare it "non persistent" by implementing on it the CATIOsmVolatileContainer interface. When the stream is saved, the container will be not discarded.
In this article, we have described what is an application container, how it's created, introspected and activated.
| Version: 1 [Oct 2007] | Document created |